You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2011/07/21 23:42:54 UTC

svn commit: r1149378 [5/5] - in /openejb/trunk/openejb3/examples/webapps: ./ rest-example/ rest-example/src/ rest-example/src/main/ rest-example/src/main/java/ rest-example/src/main/java/org/ rest-example/src/main/java/org/superbiz/ rest-example/src/ma...

Added: openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/view/view.js
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/view/view.js?rev=1149378&view=auto
==============================================================================
--- openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/view/view.js (added)
+++ openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/view/view.js Thu Jul 21 21:42:07 2011
@@ -0,0 +1,668 @@
+steal.plugins("jquery").then(function( $ ) {
+
+	// converts to an ok dom id
+	var toId = function( src ) {
+		return src.replace(/^\/\//, "").replace(/[\/\.]/g, "_");
+	},
+		// used for hookup ids
+		id = 1;
+
+	/**
+	 * @class jQuery.View
+	 * @tag core
+	 * @plugin jquery/view
+	 * @test jquery/view/qunit.html
+	 * @download dist/jquery.view.js
+	 * 
+	 * View provides a uniform interface for using templates with 
+	 * jQuery. When template engines [jQuery.View.register register] 
+	 * themselves, you are able to:
+	 * 
+	 *  - Use views with jQuery extensions [jQuery.fn.after after], [jQuery.fn.append append],
+	 *   [jQuery.fn.before before], [jQuery.fn.html html], [jQuery.fn.prepend prepend],
+	 *   [jQuery.fn.replaceWith replaceWith], [jQuery.fn.text text].
+	 *  - Template loading from html elements and external files.
+	 *  - Synchronous and asynchronous template loading.
+	 *  - Deferred Rendering.
+	 *  - Template caching.
+	 *  - Bundling of processed templates in production builds.
+	 *  - Hookup jquery plugins directly in the template.
+	 *  
+	 * ## Use
+	 * 
+	 * 
+	 * When using views, you're almost always wanting to insert the results 
+	 * of a rendered template into the page. jQuery.View overwrites the 
+	 * jQuery modifiers so using a view is as easy as: 
+	 * 
+	 *     $("#foo").html('mytemplate.ejs',{message: 'hello world'})
+	 *
+	 * This code:
+	 * 
+	 *  - Loads the template a 'mytemplate.ejs'. It might look like:
+	 *    <pre><code>&lt;h2>&lt;%= message %>&lt;/h2></pre></code>
+	 *  
+	 *  - Renders it with {message: 'hello world'}, resulting in:
+	 *    <pre><code>&lt;div id='foo'>"&lt;h2>hello world&lt;/h2>&lt;/div></pre></code>
+	 *  
+	 *  - Inserts the result into the foo element. Foo might look like:
+	 *    <pre><code>&lt;div id='foo'>&lt;h2>hello world&lt;/h2>&lt;/div></pre></code>
+	 * 
+	 * ## jQuery Modifiers
+	 * 
+	 * You can use a template with the following jQuery modifiers:
+	 * 
+	 * <table>
+	 * <tr><td>[jQuery.fn.after after]</td><td> <code>$('#bar').after('temp.jaml',{});</code></td></tr>
+	 * <tr><td>[jQuery.fn.after append] </td><td>  <code>$('#bar').append('temp.jaml',{});</code></td></tr>
+	 * <tr><td>[jQuery.fn.after before] </td><td> <code>$('#bar').before('temp.jaml',{});</code></td></tr>
+	 * <tr><td>[jQuery.fn.after html] </td><td> <code>$('#bar').html('temp.jaml',{});</code></td></tr>
+	 * <tr><td>[jQuery.fn.after prepend] </td><td> <code>$('#bar').prepend('temp.jaml',{});</code></td></tr>
+	 * <tr><td>[jQuery.fn.after replaceWith] </td><td> <code>$('#bar').replaceWidth('temp.jaml',{});</code></td></tr>
+	 * <tr><td>[jQuery.fn.after text] </td><td> <code>$('#bar').text('temp.jaml',{});</code></td></tr>
+	 * </table>
+	 * 
+	 * You always have to pass a string and an object (or function) for the jQuery modifier 
+	 * to user a template.
+	 * 
+	 * ## Template Locations
+	 * 
+	 * View can load from script tags or from files. 
+	 * 
+	 * ## From Script Tags
+	 * 
+	 * To load from a script tag, create a script tag with your template and an id like: 
+	 * 
+	 * <pre><code>&lt;script type='text/ejs' id='recipes'>
+	 * &lt;% for(var i=0; i &lt; recipes.length; i++){ %>
+	 *   &lt;li>&lt;%=recipes[i].name %>&lt;/li>
+	 * &lt;%} %>
+	 * &lt;/script></code></pre>
+	 * 
+	 * Render with this template like: 
+	 * 
+	 * @codestart
+	 * $("#foo").html('recipes',recipeData)
+	 * @codeend
+	 * 
+	 * Notice we passed the id of the element we want to render.
+	 * 
+	 * ## From File
+	 * 
+	 * You can pass the path of a template file location like:
+	 * 
+	 *     $("#foo").html('templates/recipes.ejs',recipeData)
+	 * 
+	 * However, you typically want to make the template work from whatever page they 
+	 * are called from.  To do this, use // to look up templates from JMVC root:
+	 * 
+	 *     $("#foo").html('//app/views/recipes.ejs',recipeData)
+	 *     
+	 * Finally, the [jQuery.Controller.prototype.view controller/view] plugin can make looking
+	 * up a thread (and adding helpers) even easier:
+	 * 
+	 *     $("#foo").html( this.view('recipes', recipeData) )
+	 * 
+	 * ## Packaging Templates
+	 * 
+	 * If you're making heavy use of templates, you want to organize 
+	 * them in files so they can be reused between pages and applications.
+	 * 
+	 * But, this organization would come at a high price 
+	 * if the browser has to 
+	 * retrieve each template individually. The additional 
+	 * HTTP requests would slow down your app. 
+	 * 
+	 * Fortunately, [steal.static.views steal.views] can build templates 
+	 * into your production files. You just have to point to the view file like: 
+	 * 
+	 *     steal.views('path/to/the/view.ejs');
+     *
+	 * ## Asynchronous
+	 * 
+	 * By default, retrieving requests is done synchronously. This is 
+	 * fine because StealJS packages view templates with your JS download. 
+	 * 
+	 * However, some people might not be using StealJS or want to delay loading 
+	 * templates until necessary. If you have the need, you can 
+	 * provide a callback paramter like: 
+	 * 
+	 *     $("#foo").html('recipes',recipeData, function(result){
+	 *       this.fadeIn()
+	 *     });
+	 * 
+	 * The callback function will be called with the result of the 
+	 * rendered template and 'this' will be set to the original jQuery object.
+	 * 
+	 * ## Deferreds (3.0.6)
+	 * 
+	 * If you pass deferreds to $.View or any of the jQuery 
+	 * modifiers, the view will wait until all deferreds resolve before 
+	 * rendering the view.  This makes it a one-liner to make a request and 
+	 * use the result to render a template. 
+	 * 
+	 * The following makes a request for todos in parallel with the 
+	 * todos.ejs template.  Once todos and template have been loaded, it with
+	 * render the view with the todos.
+	 * 
+	 *     $('#todos').html("todos.ejs",Todo.findAll());
+	 * 
+	 * ## Just Render Templates
+	 * 
+	 * Sometimes, you just want to get the result of a rendered 
+	 * template without inserting it, you can do this with $.View: 
+	 * 
+	 *     var out = $.View('path/to/template.jaml',{});
+	 *     
+     * ## Preloading Templates
+	 * 
+	 * You can preload templates asynchronously like:
+	 * 
+	 *     $.get('path/to/template.jaml',{},function(){},'view');
+	 * 
+	 * ## Supported Template Engines
+	 * 
+	 * JavaScriptMVC comes with the following template languages:
+	 * 
+	 *   - EmbeddedJS
+	 *     <pre><code>&lt;h2>&lt;%= message %>&lt;/h2></code></pre>
+	 *     
+	 *   - JAML
+	 *     <pre><code>h2(data.message);</code></pre>
+	 *     
+	 *   - Micro
+	 *     <pre><code>&lt;h2>{%= message %}&lt;/h2></code></pre>
+	 *     
+	 *   - jQuery.Tmpl
+	 *     <pre><code>&lt;h2>${message}&lt;/h2></code></pre>
+
+	 * 
+	 * The popular <a href='http://awardwinningfjords.com/2010/08/09/mustache-for-javascriptmvc-3.html'>Mustache</a> 
+	 * template engine is supported in a 2nd party plugin.
+	 * 
+	 * ## Using other Template Engines
+	 * 
+	 * It's easy to integrate your favorite template into $.View and Steal.  Read 
+	 * how in [jQuery.View.register].
+	 * 
+	 * @constructor
+	 * 
+	 * Looks up a template, processes it, caches it, then renders the template
+	 * with data and optional helpers.
+	 * 
+	 * With [stealjs StealJS], views are typically bundled in the production build.
+	 * This makes it ok to use views synchronously like:
+	 * 
+	 * @codestart
+	 * $.View("//myplugin/views/init.ejs",{message: "Hello World"})
+	 * @codeend
+	 * 
+	 * If you aren't using StealJS, it's best to use views asynchronously like:
+	 * 
+	 * @codestart
+	 * $.View("//myplugin/views/init.ejs",
+	 *        {message: "Hello World"}, function(result){
+	 *   // do something with result
+	 * })
+	 * @codeend
+	 * 
+	 * @param {String} view The url or id of an element to use as the template's source.
+	 * @param {Object} data The data to be passed to the view.
+	 * @param {Object} [helpers] Optional helper functions the view might use. Not all
+	 * templates support helpers.
+	 * @param {Object} [callback] Optional callback function.  If present, the template is 
+	 * retrieved asynchronously.  This is a good idea if you aren't compressing the templates
+	 * into your view.
+	 * @return {String} The rendered result of the view or if deferreds are passed, a deferred that will contain
+	 * the rendered result of the view.
+	 */
+
+	var $view, render, checkText, get, getRenderer
+		isDeferred = function(obj){
+			return obj && $.isFunction(obj.always) // check if obj is a $.Deferred
+		},
+		// gets an array of deferreds from an object
+		// this only goes one level deep
+		getDeferreds =  function(data){
+			var deferreds = [];
+		
+			// pull out deferreds
+			if(isDeferred(data)){
+				return [data]
+			}else{
+				for(var prop in data) {
+					if(isDeferred(data[prop])) {
+						deferreds.push(data[prop]);
+					}
+				}
+			}
+			return deferreds;
+		},
+		// gets the useful part of deferred
+		// this is for Models and $.ajax that give arrays
+		usefulPart = function(resolved){
+			return $.isArray(resolved) && 
+					resolved.length ===3 && 
+					resolved[1] === 'success' ?
+						resolved[0] : resolved
+		};
+
+	$view = $.View = function( view, data, helpers, callback ) {
+		if ( typeof helpers === 'function' ) {
+			callback = helpers;
+			helpers = undefined;
+		}
+		
+		// see if we got passed any deferreds
+		var deferreds = getDeferreds(data);
+		
+		
+		if(deferreds.length) { // does data contain any deferreds?
+			
+			// the deferred that resolves into the rendered content ...
+			var deferred = $.Deferred();
+			
+			// add the view request to the list of deferreds
+			deferreds.push(get(view, true))
+			
+			// wait for the view and all deferreds to finish
+			$.when.apply($, deferreds).then(function(resolved) {
+				var objs = $.makeArray(arguments),
+					renderer = objs.pop()[0],
+					result; //get the view render function
+				
+				// make data look like the resolved deferreds
+				if (isDeferred(data)) {
+					data = usefulPart(resolved);
+				}
+				else {
+					for (var prop in data) {
+						if (isDeferred(data[prop])) {
+							data[prop] = usefulPart(objs.shift());
+						}
+					}
+				}
+				result = renderer(data, helpers);
+				
+				//resolve with the rendered view
+				deferred.resolve( result ); // this does not work as is...
+				callback && callback(result);
+			});
+			// return the deferred ....
+			return deferred.promise();
+		}
+		else {
+
+			var response,
+				async = typeof callback === "function",
+				deferred = get(view, async);
+			
+			if(async){
+				response = deferred;
+				deferred.done(function(renderer){
+					callback(renderer(data, helpers))
+				})
+			} else {
+				deferred.done(function(renderer){
+					response = renderer(data, helpers);
+				});
+			}
+			
+			return response;
+		}
+	};
+	// makes sure there's a template
+	checkText = function( text, url ) {
+		if (!text.match(/[^\s]/) ) {
+			steal.dev.log("There is no template or an empty template at " + url)
+			throw "$.View ERROR: There is no template or an empty template at " + url;
+		}
+	};
+	get = function(url , async){
+		return $.ajax({
+				url: url,
+				dataType : "view",
+				async : async
+		});
+	};
+	
+	// you can request a view renderer (a function you pass data to and get html)
+	$.ajaxTransport("view", function(options, orig){
+		var view = orig.url,
+			suffix = view.match(/\.[\w\d]+$/),
+			type, el, id, renderer, url = view,
+			jqXHR,
+			response = function(text){
+				var func = type.renderer(id, text);
+				if ( $view.cache ) {
+					$view.cached[id] = func;
+				}
+				return {
+					view: func
+				};
+			};
+			
+        // if we have an inline template, derive the suffix from the 'text/???' part
+        // this only supports '<script></script>' tags
+        if ( el = document.getElementById(view)) {
+          suffix = el.type.match(/\/[\d\w]+$/)[0].replace(/^\//, '.');
+        }
+		
+		//if there is no suffix, add one
+		if (!suffix ) {
+			suffix = $view.ext;
+			url = url + $view.ext;
+		}
+
+		//convert to a unique and valid id
+		id = toId(url);
+
+		//if a absolute path, use steal to get it
+		if ( url.match(/^\/\//) ) {
+			if (typeof steal === "undefined") {
+				url = "/"+url.substr(2);
+			}
+			else {
+				url = steal.root.join(url.substr(2));
+			}
+		}
+
+		//get the template engine
+		type = $view.types[suffix];
+
+		return {
+			send : function(headers, callback){
+				if($view.cached[id]){
+					return callback( 200, "success", {view: $view.cached[id]} );
+				} else if( el  ) {
+					callback( 200, "success", response(el.innerHTML) );
+				} else {
+					jqXHR = $.ajax({
+						async : orig.async,
+						url: url,
+						dataType: "text",
+						error: function() {
+							checkText("", url);
+							callback(404);
+						},
+						success: function( text ) {
+							checkText(text, url);
+							callback(200, "success", response(text) )
+						}
+					});
+				}
+			},
+			abort : function(){
+				jqXHR && jqXHR.abort();
+			}
+		}
+	})
+	$.extend($view, {
+		/**
+		 * @attribute hookups
+		 * @hide
+		 * A list of pending 'hookups'
+		 */
+		hookups: {},
+		/**
+		 * @function hookup
+		 * Registers a hookup function that can be called back after the html is 
+		 * put on the page.  Typically this is handled by the template engine.  Currently
+		 * only EJS supports this functionality.
+		 * 
+		 *     var id = $.View.hookup(function(el){
+		 *            //do something with el
+		 *         }),
+		 *         html = "<div data-view-id='"+id+"'>"
+		 *     $('.foo').html(html);
+		 * 
+		 * 
+		 * @param {Function} cb a callback function to be called with the element
+		 * @param {Number} the hookup number
+		 */
+		hookup: function( cb ) {
+			var myid = ++id;
+			$view.hookups[myid] = cb;
+			return myid;
+		},
+		/**
+		 * @attribute cached
+		 * @hide
+		 * Cached are put in this object
+		 */
+		cached: {},
+		/**
+		 * @attribute cache
+		 * Should the views be cached or reloaded from the server. Defaults to true.
+		 */
+		cache: true,
+		/**
+		 * @function register
+		 * Registers a template engine to be used with 
+		 * view helpers and compression.  
+		 * 
+		 * ## Example
+		 * 
+		 * @codestart
+		 * $.View.register({
+		 * 	suffix : "tmpl",
+		 * 	renderer: function( id, text ) {
+		 * 		return function(data){
+		 * 			return jQuery.render( text, data );
+		 * 		}
+		 * 	},
+		 * 	script: function( id, text ) {
+		 * 		var tmpl = $.tmpl(text).toString();
+		 * 		return "function(data){return ("+
+		 * 		  	tmpl+
+		 * 			").call(jQuery, jQuery, data); }";
+		 * 	}
+		 * })
+		 * @codeend
+		 * Here's what each property does:
+		 * 
+ 		 *    * suffix - files that use this suffix will be processed by this template engine
+ 		 *    * renderer - returns a function that will render the template provided by text
+ 		 *    * script - returns a string form of the processed template function.
+		 * 
+		 * @param {Object} info a object of method and properties 
+		 * 
+		 * that enable template integration:
+		 * <ul>
+		 *   <li>suffix - the view extension.  EX: 'ejs'</li>
+		 *   <li>script(id, src) - a function that returns a string that when evaluated returns a function that can be 
+		 *    used as the render (i.e. have func.call(data, data, helpers) called on it).</li>
+		 *   <li>renderer(id, text) - a function that takes the id of the template and the text of the template and
+		 *    returns a render function.</li>
+		 * </ul>
+		 */
+		register: function( info ) {
+			this.types["." + info.suffix] = info;
+		},
+		types: {},
+		/**
+		 * @attribute ext
+		 * The default suffix to use if none is provided in the view's url.  
+		 * This is set to .ejs by default.
+		 */
+		ext: ".ejs",
+		/**
+		 * Returns the text that 
+		 * @hide 
+		 * @param {Object} type
+		 * @param {Object} id
+		 * @param {Object} src
+		 */
+		registerScript: function( type, id, src ) {
+			return "$.View.preload('" + id + "'," + $view.types["." + type].script(id, src) + ");";
+		},
+		/**
+		 * @hide
+		 * Called by a production script to pre-load a renderer function
+		 * into the view cache.
+		 * @param {String} id
+		 * @param {Function} renderer
+		 */
+		preload: function( id, renderer ) {
+			$view.cached[id] = function( data, helpers ) {
+				return renderer.call(data, data, helpers);
+			};
+		}
+
+	});
+
+
+	//---- ADD jQUERY HELPERS -----
+	//converts jquery functions to use views	
+	var convert, modify, isTemplate, getCallback, hookupView, funcs;
+
+	convert = function( func_name ) {
+		var old = $.fn[func_name];
+
+		$.fn[func_name] = function() {
+			var args = $.makeArray(arguments),
+				callbackNum, 
+				callback, 
+				self = this,
+				result;
+
+			//check if a template
+			if ( isTemplate(args) ) {
+
+				// if we should operate async
+				if ((callbackNum = getCallback(args))) {
+					callback = args[callbackNum];
+					args[callbackNum] = function( result ) {
+						modify.call(self, [result], old);
+						callback.call(self, result);
+					};
+					$view.apply($view, args);
+					return this;
+				}
+				result = $view.apply($view, args);
+				if(!isDeferred( result ) ){
+					args = [result];
+				}else{
+					result.done(function(res){
+						modify.call(self, [res], old);
+					})
+					return this;
+				}
+				//otherwise do the template now
+				
+			}
+
+			return modify.call(this, args, old);
+		};
+	};
+	// modifies the html of the element
+	modify = function( args, old ) {
+		var res, stub, hooks;
+
+		//check if there are new hookups
+		for ( var hasHookups in $view.hookups ) {
+			break;
+		}
+
+		//if there are hookups, get jQuery object
+		if ( hasHookups ) {
+			hooks = $view.hookups;
+			$view.hookups = {};
+			args[0] = $(args[0]);
+		}
+		res = old.apply(this, args);
+
+		//now hookup hookups
+		if ( hasHookups ) {
+			hookupView(args[0], hooks);
+		}
+		return res;
+	};
+
+	// returns true or false if the args indicate a template is being used
+	isTemplate = function( args ) {
+		var secArgType = typeof args[1];
+
+		return typeof args[0] == "string" && (secArgType == 'object' || secArgType == 'function') && !args[1].nodeType && !args[1].jquery;
+	};
+
+	//returns the callback if there is one (for async view use)
+	getCallback = function( args ) {
+		return typeof args[3] === 'function' ? 3 : typeof args[2] === 'function' && 2;
+	};
+
+	hookupView = function( els , hooks) {
+		//remove all hookups
+		var hookupEls, 
+			len, i = 0,
+			id, func;
+		els = els.filter(function(){
+			return this.nodeType != 3; //filter out text nodes
+		})
+		hookupEls = els.add("[data-view-id]", els);
+		len = hookupEls.length;
+		for (; i < len; i++ ) {
+			if ( hookupEls[i].getAttribute && (id = hookupEls[i].getAttribute('data-view-id')) && (func = hooks[id]) ) {
+				func(hookupEls[i], id);
+				delete hooks[id];
+				hookupEls[i].removeAttribute('data-view-id');
+			}
+		}
+		//copy remaining hooks back
+		$.extend($view.hookups, hooks);
+	};
+
+	/**
+	 *  @add jQuery.fn
+	 */
+	funcs = [
+	/**
+	 *  @function prepend
+	 *  @parent jQuery.View
+	 *  abc
+	 */
+	"prepend",
+	/**
+	 *  @function append
+	 *  @parent jQuery.View
+	 *  abc
+	 */
+	"append",
+	/**
+	 *  @function after
+	 *  @parent jQuery.View
+	 *  abc
+	 */
+	"after",
+	/**
+	 *  @function before
+	 *  @parent jQuery.View
+	 *  abc
+	 */
+	"before",
+	/**
+	 *  @function text
+	 *  @parent jQuery.View
+	 *  abc
+	 */
+	"text",
+	/**
+	 *  @function html
+	 *  @parent jQuery.View
+	 *  abc
+	 */
+	"html",
+	/**
+	 *  @function replaceWith
+	 *  @parent jQuery.View
+	 *  abc
+	 */
+	"replaceWith", 
+	"val"];
+
+	//go through helper funcs and convert
+	for ( var i = 0; i < funcs.length; i++ ) {
+		convert(funcs[i]);
+	}
+
+});

Added: openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/steal/dev/dev.js
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/steal/dev/dev.js?rev=1149378&view=auto
==============================================================================
--- openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/steal/dev/dev.js (added)
+++ openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/steal/dev/dev.js Thu Jul 21 21:42:07 2011
@@ -0,0 +1,95 @@
+/*global  window: false, console: true, opera: true */
+/**
+ * @class steal.dev
+ * @parent stealjs
+ * Provides helper functions for development that get removed when put in production mode.
+ * This means you can leave <code>steal.dev.log("hello world")</code> in your code and it
+ * will get removed in prodution.
+ * <h3>Examples</h3>
+ * @codestart
+ * steal.dev.log("Something is happening");
+ * steal.dev.warn("Something bad is happening");
+ * @codeend
+ */
+steal.dev = {
+	regexps: {
+		colons: /::/,
+		words: /([A-Z]+)([A-Z][a-z])/g,
+		lowerUpper: /([a-z\d])([A-Z])/g,
+		dash: /([a-z\d])([A-Z])/g
+	},
+	underscore: function( s ) {
+		var regs = this.regexps;
+		return s.replace(regs.colons, '/').
+		replace(regs.words, '$1_$2').
+		replace(regs.lowerUpper, '$1_$2').
+		replace(regs.dash, '_').toLowerCase();
+	},
+	isHappyName: function( name ) {
+		//make sure names are close to the current path
+		var path = steal.cur().path.replace(/\.[^$]+$/, "").split('/'),
+			//make sure parts in name match
+			parts = name.split('.');
+		
+		for ( var i = 0; i < parts.length && path.length; i++ ) {
+			if (path[i] && parts[i].toLowerCase() != path[i] && this.underscore(parts[i]) != path[i] && this.underscore(parts[i]) != path[i].replace(/_controller/, "") ) {
+				this.warn("Are you sure " + name + " belongs in " + steal.cur().path);
+			}
+		}
+		
+		
+	},
+
+	logLevel : 0,
+	/**
+	 * Adds a warning message to the console.
+	 * @codestart
+	 * steal.dev.warn("something evil");
+	 * @codeend
+	 * @param {String} out the message
+	 */
+	warn: function( out ) {
+		if(steal.options.logLevel < 2){
+			if ( window.console && console.log ) {
+				console.log("steal.js WARNING: " + out);
+			} else if ( window.opera && window.opera.postError ) {
+				opera.postError("steal.js WARNING: " + out);
+			}
+		}
+		
+	},
+	/**
+	 * Adds a message to the console.
+	 * @codestart
+	 * steal.dev.log("hi");
+	 * @codeend
+	 * @param {String} out the message
+	 */
+	log: function( out ) {
+		if (steal.options.logLevel < 1) {
+			if (window.console && console.log) {
+				console.log("steal.js INFO: " + out);
+			}
+			else if (window.opera && window.opera.postError) {
+				opera.postError("steal.js INFO: " + out);
+			}
+		}
+	}
+};
+
+//stuff for jmvc
+/**
+ * @class jQuery
+ * @constructor blah
+ */
+
+//
+/**
+ * @class jQuery.fn
+ * @constructor blah
+ */
+//
+/**
+ * @class jQuery.event.special
+ */
+// as fasf sa
\ No newline at end of file

Added: openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/steal/steal.js
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/steal/steal.js?rev=1149378&view=auto
==============================================================================
--- openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/steal/steal.js (added)
+++ openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/steal/steal.js Thu Jul 21 21:42:07 2011
@@ -0,0 +1,1376 @@
+/*
+ * JavaScriptMVC - steal.js
+ * (c) 2010 Jupiter JavaScript Consulting
+ * 
+ * steal provides dependency management
+ * steal('path/to/file').then(function(){
+ *   //do stuff with file
+ * })
+ */
+
+/*jslint evil: true */
+/*global steal: true, window: false */
+//put everything in function to keep space clean
+(function() {
+
+	if ( typeof steal != 'undefined' && steal.nodeType ) {
+		throw ("steal is defined an element's id!");
+	}
+
+	// HELPERS (if you are trying to understand steal, skip this part)
+	// keep a reference to the old steal
+	var oldsteal = window.steal,
+		// returns the document head (creates one if necessary)
+		head = function() {
+			var d = document,
+				de = d.documentElement,
+				heads = d.getElementsByTagName("head");
+			if ( heads.length > 0 ) {
+				return heads[0];
+			}
+			var head = d.createElement('head');
+			de.insertBefore(head, de.firstChild);
+			return head;
+		},
+		// creates a script tag
+		scriptTag = function() {
+			var start = document.createElement('script');
+			start.type = 'text/javascript';
+			return start;
+		},
+		extend = function( d, s ) {
+			for ( var p in s ) {
+				d[p] = s[p];
+			}
+			return d;
+		},
+		getLastPart = function( p ) {
+			return p.match(/[^\/]+$/)[0];
+		},
+		browser = {
+			msie: !! (window.attachEvent && !window.opera),
+			opera: !! window.opera,
+			safari: navigator.userAgent.indexOf('AppleWebKit/') > -1,
+			firefox: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
+			mobilesafari: !! navigator.userAgent.match(/Apple.*Mobile.*Safari/),
+			rhino: navigator.userAgent.match(/Rhino/) && true
+		},
+		factory = function() {
+			return window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
+		},
+		// writes a steal to the page in a way that steal.end gets called after the script gets run
+		insert = function( options ) {
+			// source we need to know how to get to steal, then load 
+			// relative to path to steal
+			options = extend({
+				id: options.src && steal.cleanId(options.src)
+			}, options);
+
+			var text = "",
+				scriptTag = '<script ',
+				bodyText;
+			if ( options.src ) {
+				var src_file = steal.File(options.src);
+				if (!src_file.isLocalAbsolute() && !src_file.protocol() ) {
+					options.src = steal.root.join(options.src);
+				}
+			}
+
+
+			if ( options.type && options.process ) {
+				text = steal.request(options.src);
+				if (!text ) {
+					throw "steal.js there is nothing at " + options.src;
+				}
+				bodyText = options.process(text);
+				options.type = 'text/javascript';
+				delete options.process;
+				delete options.src;
+
+			} else if ( options.type && options.type != 'text/javascript' && !browser.rhino ) {
+				text = steal.request(options.src);
+				if (!text ) {
+					throw "steal.js there is nothing at " + options.src;
+				}
+				options.text = text;
+				delete options.src;
+			}
+
+			for ( var attr in options ) {
+				scriptTag += attr + "='" + options[attr] + "' ";
+			}
+			if ( steal.support.load && !steal.browser.rhino && !bodyText ) {
+				scriptTag += steal.loadErrorTimer(options);
+			}
+			scriptTag += '>' + (bodyText || '') + '</script>';
+			if ( steal.support.load && !browser.msie) {
+				scriptTag += '<script type="text/javascript"' + '>steal.end()</script>';
+			}
+			else { // this is here b/c IE will run a script above right away (before the script above it loads)
+				scriptTag += '<script type="text/javascript" src="' + steal.root.join('steal/end.js') + '"></script>';
+			}
+			document.write((options.src || bodyText ? scriptTag : ''));
+		};
+
+	/**
+	 * @class steal
+	 * @parent stealjs
+	 * <p>Steal makes JavaScript dependency management and resource loading easy.</p>
+	 * <p>This page details the steal script (<code>steal/steal.js</code>), 
+	 * and steal function which are used to load files into your page.  
+	 * For documentation of other Steal projects, read [stealjs StealJS].</p>
+	 * <h3>Quick Overview</h3>
+	 * 
+	 * <p>To start using steal, add the steal script to your page, and tell it the first
+	 * file to load:</p>
+	 * </p>
+	 * @codestart html
+	 *&lt;script type='text/javascript'
+	 *        src='public/steal/steal.js?<u><b>myapp/myapp.js</b></u>'>&lt;/script>
+	 * @codeend
+	 * 
+	 * <p>In the file (<code>public/myapp/myapp.js</code>), 
+	 * 'steal' all other files that you need like:</p>
+	 * @codestart
+	 * steal("anotherFile")           //loads myapp/anotherFiles.js
+	 *    .css('style')               //      myapp/style.css
+	 *    .plugins('jquery/view',     //      jquery/view/view.js
+	 *             'steal/less')      //      steal/less/less.js
+	 *    .then(function(){           //called when all prior files have completed
+	 *       steal.less('myapp')      //loads myapp/myapp.less
+	 *    })
+	 *    .views('//myapp/show.ejs')  //loads myapp/show.ejs
+	 * @codeend
+	 * <p>Finally compress your page's JavaScript and CSS with:</p>
+	 * @codestart
+	 * > js steal/buildjs path/to/mypage.html
+	 * @codeend
+	 * <h2>Use</h2>
+	 * Use of steal.js is broken into 5 parts:
+	 * <ul>
+	 * <li>Loading steal.js </li> 
+	 *  <li>Loading your 'application' file.</li>
+	 *    <li>"Stealing" scripts</li>
+	 *    <li>Building (Concatenating+Compressing) the app</li>
+	 *    <li>Switching to the production build</li>
+	 * </ul>
+	 * 
+	 * 
+	 * <h3>Loading <code>steal.js</code></h3>
+	 * <p>First, you need to [download download JavaScriptMVC] (or steal standalone) and unzip it into a
+	 *    public folder on your server.  For this example, lets assume you have the steal script in
+	 *    <code>public/steal/steal.js</code>.   
+	 * </p>
+	 * <p>Next, you need to load the <code>steal.js</code> script in your html page.  We suggest 
+	 *    [http://developer.yahoo.com/performance/rules.html#js_bottom bottom loading] your scripts.
+	 *    For example, if your page is in <code>pages/myapp.html</code>, you can get steal like:
+	 * </p>
+	 * @codestart html
+	 * &lt;script type='text/javascript'
+	 *     src='../public/steal/steal.js'>
+	 * &lt;/script>
+	 * @codeend
+	 * <h3>Loading your 'application' file</h3>
+	 * <p>The first file your application loads
+	 * is referred to as an "application" file.  It loads all the files and resources
+	 * that your application needs.  For this example, we'll put our application file in:
+	 * <code>public/myapp/myapp.js</code>
+	 * </p>
+	 * <p>You have to tell steal where to find it by configuring [steal.static.options].
+	 * There are a lot of ways to configure steal to load your app file, but we've made it really easy:</p>
+	 * @codestart html
+	 * &lt;script type='text/javascript'
+	 *     src='../public/steal/steal.js?<u><b>myapp/myapp.js</b></u>'>
+	 * &lt;/script>
+	 * @codeend
+	 * This sets ...
+	 * @codestart
+	 * steal.options.startFile = 'myapp/myapp.js'
+	 * @codeend
+	 * 
+	 * ... and results in steal loading 
+	 * <code>public/myapp/myapp.js</code>.</p>
+	 * 
+	 * <div class='whisper'>
+	 *    TIP: If startFile doesn't end with <code>.js</code> (ex: myapp), steal assumes
+	 *    you are using JavaScriptMVC's folder pattern and will load:
+	 *    <code>myapp/myapp.js</code> just to save you 9 characters.
+	 * </div>
+	 * <h3>Stealing Scripts</h3>
+	 * In your files, use the steal function and its helpers
+	 *  to load dependencies then describe your functionality.
+	 * Typically, most of the 'stealing' is done in your application file.  Loading 
+	 * jQuery and jQuery.UI from google, a local helpers.js 
+	 * and then adding tabs might look something like this:
+	 * @codestart
+	 * steal( 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js',
+	 *        'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/jquery-ui.js',
+	 *        'helpers')
+	 * .then( function(){
+	 *   $('#tabs').tabs();
+	 * });
+	 * @codeend
+	 * 
+	 * There's a few things to notice:
+	 * 
+	 *   - the steal function can take multiple arguments.  Each argument 
+	 *    can be a string, object, or function.  Learn more about what can be passed to 
+	 *    steal in the [steal.prototype.init] documentation. 
+	 *   - steal can load cross domain</li>
+	 *   - steal loads relative to the current file</li>
+	 *   - steal adds .js if not present</li>
+	 *   - steal is chainable (most function return steal)
+     * 
+	 * ### Building the app
+	 * 
+	 * Building the app means combining and compressing your apps JavaScript and CSS into a single file.
+	 * A lot more details can be found on building in the 
+	 * [steal.build steal.build documentation].  But, if you used JavaScriptMVC's app or plugin
+	 * generator, you can build
+	 * your app's JS and CSS with:
+	 * 
+	 * 
+	 * @codestart no-highlight
+	 * js myapp\scripts\compress.js
+	 * @codeend
+	 * 
+	 * Or if you are using steal without JavaScriptMVC:
+	 * 
+	 * @codestart no-highlight
+	 * js steal/buildjs pages/myapp.html -to public/myapp
+	 * @codeend
+	 * 
+	 * This creates <code>public/myapp/production.js</code> and <code>public/myapp/production.css</code>.
+	 * 
+	 * ### Switching to the production build
+	 * 
+	 * To use the production files, load steal.production.js instead of steal.js in your html file:
+	 * 
+	 * @codestart html
+	 * &lt;script type='text/javascript'
+	 *         src='../public/steal/<u><b>steal.production.js</b></u>?myapp/myapp.js'>
+	 * &lt;/script>
+	 * @codeend
+	 * 
+	 * ## Steal helpers
+	 * 
+	 * There are a number of steal helper functions that can be used to load files in a particular location
+	 * or of a type other than JavaScript:
+	 * 
+	 *  * [steal.static.coffee] - loads  
+	 *     [http://jashkenas.github.com/coffee-script/ CoffeeScript] scripts.
+	 *  * [steal.static.controllers] - loads controllers relative to the current path.
+	 *  * [steal.static.css] - loads a css file.
+	 *  * [steal.static.less] - loads [http://lesscss.org/ Less] style sheets.
+	 *  * [steal.static.models] - loads models relative to the current path.
+	 *  * [steal.static.plugins] - loads JavaScript files relative to steal's root folder.
+	 *  * [steal.static.resources] - loads a script in a relative resources folder.
+	 *  * [steal.static.views] - loads a client side template to be compiled into the production build.
+	 * 
+	 * ## Script Load Order
+	 * 
+	 * The load order for your scripts follows a consistent last-in first-out order across all browsers. 
+	 * This is the same way the following document.write would work in msie, Firefox, or Safari:
+	 * @codestart
+	 * document.write('&lt;script type="text/javascript" src="some_script.js"></script>')
+	 * @codeend
+	 * An example helps illustrate this.<br/>
+	 * <img src='http://wiki.javascriptmvc.com/images/last_in_first_out.png'/>
+	 * <table class="options">
+	 * <tr class="top">
+	 * <th>Load Order</th>
+	 * <th class="right">File</th>
+	 * </tr>
+	 * <tbody>
+	 * <tr>
+	 * <td>1</td>
+	 * <td class="right">1.js</td>
+	 * </tr>
+	 * <tr>
+	 * <td>2</td>
+	 * <td class="right">3.js</td>
+	 * </tr>
+	 * <tr>
+	 * <td>3</td>
+	 * <td class="right">4.js</td>
+	 * </tr>
+	 * <tr>
+	 * <td>4</td>
+	 * <td class="right">2.js</td>
+	 * </tr>
+	 * <tr>
+	 * <td>5</td>
+	 * <td class="right">5.js</td>
+	 * </tr>
+	 * <tr class="bottom">
+	 * <td>6</td>
+	 * <td class="right">6.js</td>
+	 * </tr>
+	 *</tbody></table>
+	 * @constructor 
+	 * Loads files or runs functions after all previous files and functions have been loaded.
+	 * @param {String|Object|Function+} resource Each argument represents a resource or function.
+	 * Arguments can be a String, Object, or Function.
+	 * <table class='options'>
+	 *  <tr>
+	 *  <th>Type</th><th>Description</th>
+	 *  </tr>
+	 *  <tr><td>String</td>
+	 * <td>A path to a JavaScript file.  The path can optionally end in '.js'.<br/>  
+	 * Paths are typically assumed to be relative to the current JavaScript file. But paths, that start
+	 * with: 
+	 * <ul>
+	 * <li><code>http(s)://</code> are absolutely referenced.</li>
+	 * <li><code>/</code> are referenced from the current domain.</li>
+	 * <li><code>//</code> are referenced from the ROOT folder.</li>
+	 * 
+	 * </td></tr>
+	 *  <tr><td>Object</td>
+	 *  <td>An Object with the following properties:
+	 *  <ul>
+	 *  <li>path {String} - relative path to a JavaScript file.  </li>
+	 *  <li>type {optional:String} - Script type (defaults to text/javascript)</li>
+	 *  <li>skipInsert {optional:Boolean} - Include not added as script tag</li>
+	 *  <li>compress {optional:String} - "false" if you don't want to compress script</li>
+	 *  <li>package {optional:String} - Script package name (defaults to production.js)</li> 
+	 *  </ul>
+	 *  </td></tr>
+	 *  <tr><td>Function</td><td>A function to run after all the prior steals have finished loading</td></tr>
+	 * </table>
+	 * @return {steal} returns itself for chaining.
+	 */
+	steal = function() {
+		for ( var i = 0; i < arguments.length; i++ ) {
+			steal.add(new steal.fn.init(arguments[i]));
+		}
+		return steal;
+	};
+
+	(function() {
+		var eventSupported = function( eventName, tag ) {
+			var el = document.createElement(tag);
+			eventName = "on" + eventName;
+
+			var isSupported = (eventName in el);
+			if (!isSupported ) {
+				el.setAttribute(eventName, "return;");
+				isSupported = typeof el[eventName] === "function";
+			}
+			el = null;
+			return isSupported;
+		};
+		steal.support = {
+			load: eventSupported("load", "script"),
+			readystatechange: eventSupported("readystatechange", "script"),
+			error: eventSupported("readystatechange", "script")
+		};
+	})();
+
+
+	steal.fn = steal.prototype = {
+		// sets up a steal instance and records the current path, etc
+		init: function( options ) {
+			if ( typeof options == 'function' ) {
+				var path = steal.getCurrent();
+				this.path = path;
+				this.func = function() {
+					steal.curDir(path);
+					options(steal.send || window.jQuery || steal); //should return what was steald before 'then'
+				};
+				this.options = options;
+				return;
+			}
+			if ( typeof options == 'string' ) {
+				if (/\.js$/i.test(options) ) {
+					options = {
+						path: options
+					};
+				} else {
+					options = {
+						path: options + '.js'
+					};
+				}
+			}
+			extend(this, options);
+
+			this.options = options; //TODO: needed?
+			this.originalPath = this.path;
+
+			//get actual path
+			var pathFile = steal.File(this.path);
+
+			this.path = pathFile.normalize();
+			if ( this.originalPath.match(/^\/\//) ) {
+				this.absolute = steal.root.join(this.originalPath.substr(2));
+			}
+			else {
+				this.absolute = pathFile.relative() ? pathFile.joinFrom(steal.getAbsolutePath(), true) : this.path;
+			}
+
+			this.dir = steal.File(this.path).dir();
+		},
+		/**
+		 * Adds a script tag to the dom, loading and running the steal's JavaScript file.
+		 * @hide
+		 */
+		run: function() {
+			//set next to current so other includes will be added to it
+			steal.cur(this);
+			//only load if actually pulled, this helps us mark only once
+			this.dependencies = [];
+			var isProduction = (steal.options.env == "production"),
+				options = extend({
+					type: "text/javascript",
+					compress: "true",
+					"package": "production.js"
+				}, extend({
+					src: this.path
+				}, this.options));
+
+			if ( this.func ) {
+				//console.log("run FUNCTION")
+				//run function and continue to next steald
+				this.func();
+				steal.end();
+			} else if (!isProduction || this.force ) { //force is for packaging
+				//console.log("run INSERT",this.path)
+				if ( this.type ) {
+					insert(options);
+				} else {
+					steal.curDir(this.path);
+					insert(this.skipInsert ? undefined : options);
+				}
+			} else {
+				//console.log("run VIRTUAL ",this.path)
+				if (!this.type ) {
+					steal.curDir(this.path);
+				}
+			}
+
+		},
+		/**
+		 * Loads the steal code immediately.  This is typically used after DOM has loaded.
+		 * @hide
+		 */
+		runNow: function() {
+			steal.curDir(this.path);
+
+			return browser.rhino ? load(this.path) : steal.insertHead(steal.root.join(this.path));
+		}
+
+	};
+	steal.fn.init.prototype = steal.fn;
+	//where the root steal folder is
+	steal.root = null;
+	//where the page is
+	steal.pageDir = null;
+	//provide extend to others
+	steal.extend = extend;
+	//save a reference to the browser
+	steal.browser = browser;
+
+
+	/**
+	 * @class
+	 * Used for getting information out of a path
+	 * @constructor
+	 * Takes a path
+	 * @param {String} path 
+	 */
+	steal.File = function( path ) {
+		if ( this.constructor != steal.File ) {
+			return new steal.File(path);
+		}
+		this.path = path;
+	};
+	var File = steal.File;
+	extend(File.prototype,
+	/* @prototype */
+	{
+		/**
+		 * Removes hash and params
+		 * @return {String}
+		 */
+		clean: function() {
+			return this.path.match(/([^\?#]*)/)[1];
+		},
+		/**
+		 * Returns everything before the last /
+		 */
+		dir: function() {
+			var last = this.clean().lastIndexOf('/'),
+				dir = (last != -1) ? this.clean().substring(0, last) : '',
+				parts = dir !== '' && dir.match(/^(https?:\/|file:\/)$/);
+			return parts && parts[1] ? this.clean() : dir;
+		},
+		/**
+		 * Returns the domain for the current path.
+		 * Returns null if the domain is a file.
+		 */
+		domain: function() {
+			if ( this.path.indexOf('file:') === 0 ) {
+				return null;
+			}
+			var http = this.path.match(/^(?:https?:\/\/)([^\/]*)/);
+			return http ? http[1] : null;
+		},
+		/**
+		 * Joins a url onto a path.  One way of understanding this is that your File object represents your current location, and calling join() is analogous to "cd" on a command line.
+		 * @codestart
+		 * new steal.File("d/e").join("../a/b/c"); // Yields the path "d/a/b/c"
+		 * @codeend
+		 * @param {String} url
+		 */
+		join: function( url ) {
+			return File(url).joinFrom(this.path);
+		},
+		/**
+		 * Returns the path of this file referenced from another url or path.
+		 * @codestart
+		 * new steal.File('a/b.c').joinFrom('/d/e')//-> /d/e/a/b.c
+		 * @codeend
+		 * @param {String} url
+		 * @param {Boolean} expand if the path should be expanded
+		 * @return {String} 
+		 */
+		joinFrom: function( url, expand ) {
+			var u = File(url);
+			if ( this.protocol() ) { //if we are absolutely referenced
+				//try to shorten the path as much as possible:
+				if ( this.domain() && this.domain() == u.domain() ) {
+					return this.afterDomain();
+				}
+				else if ( this.domain() == u.domain() ) { // we are from a file
+					return this.toReferenceFromSameDomain(url);
+				} else {
+					return this.path;
+				}
+
+			} else if ( url == steal.pageDir && !expand ) {
+
+				return this.path;
+
+			} else if ( this.isLocalAbsolute() ) { // we are a path like /page.js
+				if (!u.domain() ) {
+					return this.path;
+				}
+
+				return u.protocol() + "//" + u.domain() + this.path;
+
+			}
+			else { //we have 2 relative paths, remove folders with every ../
+				if ( url === '' ) {
+					return this.path.replace(/\/$/, '');
+				}
+				var urls = url.split('/'),
+					paths = this.path.split('/'),
+					path = paths[0];
+				
+				//if we are joining from a folder like cookbook/, remove the last empty part
+				if ( url.match(/\/$/) ) {
+					urls.pop();
+				}
+				// for each .. remove one folder
+				while ( path == '..' && paths.length > 0 ) {
+					// if we've emptied out, folders, just break
+					// leaving any additional ../s
+					if(! urls.pop() ){ 
+						break;
+					}
+					paths.shift();
+					
+					path = paths[0];
+				}
+				return urls.concat(paths).join('/');
+			}
+		},
+		/**
+		 * Joins the file to the current working directory.
+		 */
+		joinCurrent: function() {
+			return this.joinFrom(steal.curDir());
+		},
+		/**
+		 * Returns true if the file is relative
+		 */
+		relative: function() {
+			return this.path.match(/^(https?:|file:|\/)/) === null;
+		},
+		/**
+		 * Returns the part of the path that is after the domain part
+		 */
+		afterDomain: function() {
+			return this.path.match(/https?:\/\/[^\/]*(.*)/)[1];
+		},
+		/**
+		 * Returns the relative path between two paths with common folders.
+		 * @codestart
+		 * new steal.File('a/b/c/x/y').toReferenceFromSameDomain('a/b/c/d/e')//-> ../../x/y
+		 * @codeend
+		 * @param {Object} url
+		 * @return {String} 
+		 */
+		toReferenceFromSameDomain: function( url ) {
+			var parts = this.path.split('/'),
+				other_parts = url.split('/'),
+				result = '';
+			while ( parts.length > 0 && other_parts.length > 0 && parts[0] == other_parts[0] ) {
+				parts.shift();
+				other_parts.shift();
+			}
+			for ( var i = 0; i < other_parts.length; i++ ) {
+				result += '../';
+			}
+			return result + parts.join('/');
+		},
+		/**
+		 * Is the file on the same domain as our page.
+		 */
+		isCrossDomain: function() {
+			return this.isLocalAbsolute() ? false : this.domain() != File(window.location.href).domain();
+		},
+		isLocalAbsolute: function() {
+			return this.path.indexOf('/') === 0;
+		},
+		protocol: function() {
+			var match = this.path.match(/^(https?:|file:)/);
+			return match && match[0];
+		},
+		/**
+		 * For a given path, a given working directory, and file location, update the path so 
+		 * it points to a location relative to steal's root.
+		 */
+		normalize: function() {
+
+			var current = steal.curDir(),
+				//if you are cross domain from the page, and providing a path that doesn't have an domain
+				path = this.path;
+
+			if (/^\/\//.test(this.path) ) { //if path is rooted from steal's root 
+				path = this.path.substr(2);
+
+			} else if ( this.relative() || (steal.isCurrentCrossDomain() && //if current file is on another domain and
+			!this.protocol()) ) { //this file doesn't have a protocol
+				path = this.joinFrom(current);
+
+			}
+			return path;
+		}
+	});
+	/**
+	 *  @add steal
+	 */
+	// break
+	/* @static */
+	//break
+	/**
+	 * @attribute pageDir
+	 * @hide
+	 * The current page's folder's path.
+	 */
+	steal.pageDir = File(window.location.href).dir();
+
+	//find steal
+	/**
+	 * @attribute options
+	 * Options that deal with steal
+	 * <table class='options'>
+	 * <tr>
+	 *     <th>Option</th><th>Default</th><th>Description</th>
+	 * </tr>
+	 * <tr><td>env</td><td>development</td><td>Which environment is currently running</td></tr>
+	 * <tr><td>encoding</td><td>utf-8</td><td>What encoding to use for script loading</td></tr>
+	 * <tr><td>cacheInclude</td><td>true</td><td>true if you want to let browser determine if it should cache script; false will always load script</td></tr>
+	 * 
+	 * <tr><td>done</td><td>null</td><td>If a function is present, calls function when all steals have been loaded</td></tr>
+	 * <tr><td>documentLocation</td><td>null</td><td>If present, ajax request will reference this instead of the current window location.  
+	 * Set this in run_unit, to force unit tests to use a real server for ajax requests. </td></tr>
+	 * <tr><td>logLevel</td><td>0</td><td>0 - Log everything<br/>1 - Log Warnings<br/>2 - Log Nothing</td></tr>
+	 * <tr><td>startFile</td><td>null</td><td>This is the first file to load.  It is typically determined from the first script option parameter 
+	 * in the inclue script. </td></tr>
+	 * </table>
+	 * <ul>
+	 *    <li><code>steal.options.startFile</code> - the first file steal loads.  This file
+	 *    loads all other scripts needed by your application.</li>
+	 *    <li><code>steal.options.env</code> - the environment (development or production)
+	 *     that determines if steal loads your all your script files or a single
+	 *     compressed file.
+	 *    </li>
+	 * </ul>
+	 * <p><code>steal.options</code> can be configured by:</p>
+	 * <ul>
+	 *    <li>The steal.js script tag in your page (most common pattern).</li>
+	 *    <li>An existing steal object in the window object</li>
+	 *    <li><code>window.location.hash</code></li>
+	 * </ul>
+	 * <p>
+	 *    The steal.js script tag is by far the most common approach. 
+	 *    For the other methods,
+	 *    check out [steal.static.options] documentation.
+	 *    To load <code>myapp/myapp.js</code> in development mode, your 
+	 *    script tag would look like:
+	 * </p>
+	 * 
+	 * @codestart
+	 * &lt;script type='text/javascript'
+	 *     src='path/to/steal.js?<u><b>myapp/myapp.js</b></u>,<u><b>development</b></u>'>
+	 * &lt;/script>
+	 * @codeend
+	 * <div class='whisper'>
+	 * Typically you want this script tag right before the closing body tag (<code>&lt;/body></code>) of your page.
+	 * </div>
+	 * <p>Note that the path to <code>myapp/myapp.js</code> 
+	 * is relative to the 'steal' folder's parent folder.  This
+	 * is typically called the JavaScriptMVC root folder or just root folder if you're cool.</p>
+	 * <p>And since JavaScriptMVC likes folder structures like:</p>
+	 * @codestart text
+	 * \myapp
+	 *    \myapp.js
+	 * \steal
+	 *    \steal.js
+	 * @codeend
+	 * <p>If your path doesn't end with <code>.js</code>, JavaScriptMVC assumes you are loading an 
+	 * application and will add <code>/myapp.js</code> on for you.  This means that this does the same thing too:</p>
+	 * @codestart
+	 * &lt;script type='text/javascript'
+	 *        src='path/to/steal.js?<u><b>myapp</b></u>'>&lt;/script>
+	 * @codeend
+	 * <div class='whisper'>Steal, and everything else in JavaScriptMVC, provide these little shortcuts
+	 * when you are doing things 'right'.  In this case, you save 9 characters 
+	 * (<code>/myapp.js</code>) by organizing your app the way, JavaScriptMVC expects.</div>
+	 * </div>
+	 */
+	steal.options = {
+		loadProduction: true,
+		env: 'development',
+		production: null,
+		encoding: "utf-8",
+		cacheInclude: true,
+		logLevel: 0
+	};
+
+	// variables used while including
+	var first = true,
+		//If we haven't steald a file yet
+		first_wave_done = false,
+		//a list of all steald paths
+		cwd = '',
+		//  the current steal
+		cur = null,
+		//where we are currently including
+		steals = [],
+		//    
+		current_steals = [],
+		//steals that are pending to be steald
+		total = [],
+		//mapping of loaded css files
+		css = {};
+	extend(steal, {
+		/**
+		 * Sets options from script
+		 * @hide
+		 */
+		setScriptOptions: function() {
+			var scripts = document.getElementsByTagName("script"),
+				scriptOptions, 
+				commaSplit, 
+				stealReg = /steal\.(production\.)?js/;
+
+			//find the steal script and setup initial paths.
+			for ( var i = 0; i < scripts.length; i++ ) {
+				var src = scripts[i].src;
+				if ( src && stealReg.test(src) ) { //if script has steal.js
+					var mvc_root = File(File(src).joinFrom(steal.pageDir)).dir(),
+						loc = /\.\.$/.test(mvc_root) ? mvc_root + '/..' : mvc_root.replace(/steal$/, '');
+
+					if (/.+\/$/.test(loc) ) {
+						loc = loc.replace(/\/$/, '');
+					}
+
+					if (/steal\.production\.js/.test(src) ) {
+						steal.options.env = "production";
+					}
+					steal.root = File(loc);
+					if ( src.indexOf('?') != -1 ) {
+						scriptOptions = src.split('?')[1];
+					}
+					steal.options.evalAfter = /\w+/.test(scripts[i].text) && scripts[i].text
+				}
+
+			}
+
+			//if there is stuff after ?
+			if ( scriptOptions ) {
+				// if it looks like steal[xyz]=bar, add those to the options
+				if ( scriptOptions.indexOf('=') > -1 ) {
+					scriptOptions.replace(/steal\[([^\]]+)\]=([^&]+)/g, function( whoe, prop, val ) {
+						steal.options[prop] = val;
+					});
+				} else {
+					//set with comma style
+					commaSplit = scriptOptions.split(",");
+					if ( commaSplit[0] && commaSplit[0].lastIndexOf('.js') > 0 ) {
+						steal.options.startFile = commaSplit[0];
+					} else if ( commaSplit[0] ) {
+						steal.options.app = commaSplit[0];
+					}
+					if ( commaSplit[1] && steal.options.env != "production" ) {
+						steal.options.env = commaSplit[1];
+					}
+				}
+
+			}
+
+		},
+		setOldIncludeOptions: function() {
+			extend(steal.options, oldsteal);
+		},
+		setHashOptions: function() {
+			window.location.hash.replace(/steal\[(\w+)\]=(\w+)/g, function( whoe, prop, val ) {
+				steal.options[prop] = val;
+			});
+		},
+		/**
+		 * Starts including files, sets options.
+		 * @hide
+		 */
+		init: function() {
+			this.setScriptOptions();
+			//force into development mode to prevent errors
+			if ( steal.browser.rhino ) {
+				steal.options.env = 'development';
+			}
+			this.setOldIncludeOptions();
+			this.setHashOptions();
+			//clean up any options
+			if ( steal.options.app ) {
+				steal.options.startFile = steal.options.app + "/" + steal.options.app.match(/[^\/]+$/)[0] + ".js";
+			}
+			if ( steal.options.ignoreControllers ) {
+				steal.controllers = function() {
+					return steal;
+				};
+				steal.controller = function() {
+					return steal;
+				};
+			}
+			//calculate production location;
+			if (!steal.options.production && steal.options.startFile ) {
+				steal.options.production = "//" + File(steal.options.startFile).dir() + '/production';
+			}
+			if ( steal.options.production ) {
+				steal.options.production = steal.options.production + (steal.options.production.indexOf('.js') == -1 ? '.js' : '');
+			}
+			//we only load things with force = true
+			if ( steal.options.env == 'production' ) {
+				
+				// if we have a production script and we haven't been told not to load it
+				if ( steal.options.production && steal.options.loadProduction ) {
+					first = false; //makes it so we call close after
+					//steal(steal.options.startFile);
+					steal({
+						path: steal.options.production,
+						force: true
+					});
+				}
+
+			} else {
+
+				var current_path = steal.getCurrent();
+				steal({
+					path: 'steal/dev/dev.js',
+					ignore: true
+				});
+				steal.curDir(current_path);
+
+
+
+
+				//if you have a startFile load it
+				if ( steal.options.startFile ) {
+					first = false; //makes it so we call close after
+					//steal(steal.options.startFile);
+					steal._start = new steal.fn.init(steal.options.startFile);
+					steal.add(steal._start);
+				}
+
+			}
+
+
+
+			if ( steal.options.startFile ) {
+				steal.start();
+			}
+		},
+		/**
+		 * Gets or sets the current directory your relative steals will reference.
+		 * @param {String} [path] the new current directory path
+		 * @return {String|steal} the path of the current directory or steal for chaining.
+		 */
+		curDir: function( path ) {
+			if ( path !== undefined ) {
+				cwd = path;
+				return steal;
+			} else {
+				var dir = File(cwd).dir();
+				//make sure it has a /
+				return dir ? dir + (dir.lastIndexOf('/') === dir.length - 1 ? '' : '/') : dir;
+			}
+
+		},
+		cur: function( steal ) {
+			if ( steal !== undefined ) {
+				return (cur = steal);
+			} else {
+				return cur;
+			}
+		},
+		//is the current folder cross domain from our folder?
+		isCurrentCrossDomain: function() {
+			return File(steal.getAbsolutePath()).isCrossDomain();
+		},
+		getCurrent: function() {
+			return cwd;
+		},
+		getAbsolutePath: function() {
+			var dir = this.curDir(),
+				fwd = File(this.curDir());
+			return fwd.relative() ? fwd.joinFrom(steal.root.path, true) : dir;
+		},
+		// Adds a steal to the pending list of steals.
+		add: function( newInclude ) {
+			//If steal is a function, add to list, and unshift
+			if ( typeof newInclude.func == 'function' ) {
+				//console.log("add","FUNCTION")
+				current_steals.unshift(newInclude); //add to the front
+				return;
+			}
+			var cur = steal.cur(), 
+				existing = steal.exists(newInclude);
+
+			
+			//if we have already performed loads, insert new steals in head
+			//now we should check if it has already been steald or added earlier in this file
+			if ( !existing ) {
+				if ( cur ) {
+					cur.dependencies.push(newInclude);
+				}
+				if ( first_wave_done ) {
+					return newInclude.runNow();
+				}
+				//but the file could still be in the list of steals but we need it earlier, so remove it and add it here
+				var path = newInclude.absolute || newInclude.path;
+				for ( var i = 0; i < steals.length; i++ ) {
+					if ( steals[i].absolute == path ) {
+						steals.splice(i, 1);
+						break;
+					}
+				}
+				//console.log("add FILE",newInclude.path)
+				current_steals.unshift(newInclude);
+			}else{
+				cur.dependencies.push(existing);
+			}
+		},
+		//this should probably be kept as a hash.
+		//returns the steal if the steal already exists
+		exists: function( inc ) {
+			var path = inc.absolute || inc.path,
+				i;
+			for ( i = 0; i < total.length; i++ ) {
+				if ( total[i].absolute == path ) {
+					return total[i];
+				}
+			}
+			for ( i = 0; i < current_steals.length; i++ ) {
+				if ( current_steals[i].absolute == path ) {
+					return current_steals[i];
+				}
+			}
+			return;
+		},
+		done: function() {
+			if ( steal.options.evalAfter ){
+				eval(steal.options.evalAfter);
+			}
+			if ( typeof steal.options.done == "function" ) {
+				steal.options.done(total);
+			}
+		},
+		// Called after every file is loaded.  Gets the next file and steals it.
+		end: function( src ) {
+			//prevents warning of bad includes
+			clearTimeout(steal.timer);
+			// add steals that were just added to the end of the list
+			steals = steals.concat(current_steals);
+			
+
+			// take the last one
+			var next = steals.pop();
+
+			// if there are no more
+			if (!next ) {
+				first_wave_done = true;
+				steal.done();
+			} else {
+				//add to the total list of things that have been steald, and clear current steals
+				total.push(next);
+				current_steals = [];
+				next.run();
+
+			}
+
+		},
+
+		/**
+		 * Starts loading files.  This is useful when steal is being used without providing an initial file or app to load.
+		 * You can steal files, but then call steal.start() to start actually loading them.
+		 * 
+		 * <h3>Example:</h3>
+		 * @codestart html
+		 * &lt;script src='steal/steal.js'>&lt;/script>
+		 * &lt;script type='text/javascript'>
+		 *    steal.plugins('controller')
+		 *    steal.start();
+		 * &lt;/script>
+		 * @codeend
+		 * The above code loads steal, then uses steal to load the plugin controller.
+		 */
+		start: function() {
+			steal.end();
+		},
+		/**
+		 * Loads css files from the given relative path.
+		 * @codestart
+		 * steal.css('mystyles') //loads mystyles.css
+		 * @codeend
+		 * Styles loaded in this way will be compressed into a single style.
+		 * @param {String+} relative URL(s) to stylesheets
+		 * @return {steal} steal for chaining
+		 */
+		css: function() {
+			//if production, 
+			if ( steal.options.env == 'production' ) {
+				if ( steal.loadedProductionCSS ) {
+					return steal;
+				} else {
+					var productionCssPath = steal.File(steal.options.production.replace(".js", ".css")).normalize();
+					productionCssPath = steal.root.join(productionCssPath);
+					steal.createLink(productionCssPath);
+					steal.loadedProductionCSS = true;
+					return steal;
+				}
+			}
+			var current;
+			for ( var i = 0; i < arguments.length; i++ ) {
+				current = steal.root.join( File(arguments[i] + ".css").joinCurrent() );
+				if(!css[current]){
+					steal.createLink(current);
+					css[current] = true;
+				}
+				
+			}
+			return this;
+		},
+		/**
+		 * Creates a css link and appends it to head.
+		 * @hide
+		 * @param {Object} location
+		 * @return {HTMLLinkElement}
+		 */
+		createLink: function( location, options ) {
+			options = options || {};
+			var link = document.createElement('link');
+			link.rel = options.rel || "stylesheet";
+			link.href = location;
+			link.type = options.type || 'text/css';
+			head().appendChild(link);
+			return link;
+		},
+		/**
+		 * @hide
+		 * Synchronously requests a file.  This is here to read a file for other types.	 * 
+		 * @param {String} path path of file you want to load
+		 * @param {optional:String} content_type optional content type
+		 * @return {String} text of file
+		 */
+		request: function( path, content_type ) {
+			var contentType = (content_type || "application/x-www-form-urlencoded; charset=" + steal.options.encoding),
+				request = factory();
+			request.open("GET", path, false);
+			request.setRequestHeader('Content-type', contentType);
+			if ( request.overrideMimeType ) {
+				request.overrideMimeType(contentType);
+			}
+
+			try {
+				request.send(null);
+			}
+			catch (e) {
+				return null;
+			}
+			if ( request.status === 500 || request.status === 404 || request.status === 2 || (request.status === 0 && request.responseText === '') ) {
+				return null;
+			}
+			return request.responseText;
+		},
+		/**
+		 * Inserts a script tag in head with the encoding.
+		 * @hide
+		 * @param {Object} src
+		 * @param {Object} encode
+		 */
+		insertHead: function( src, encode, type, text, id ) {
+			encode = encode || "UTF-8";
+			var script = scriptTag();
+			if ( src ) {
+				script.src = src;
+			}
+			if ( id ) {
+				script.id = id;
+			}
+			script.charset = encode;
+			script.type = type || "text/javascript";
+			if ( text ) {
+				script.text = text;
+			}
+			head().appendChild(script);
+		},
+		write: function( src, encode ) {
+			encode = encode || "UTF-8";
+			document.write('<script type="text/javascript" src="' + src + '" encode="+encode+"></script>');
+		},
+		resetApp: function( f ) {
+			return function( name ) {
+				var current_path = steal.getCurrent();
+				steal.curDir("");
+				if ( name.path ) {
+					name.path = f(name.path);
+				} else {
+					name = f(name);
+				}
+				steal(name);
+				steal.curDir(current_path);
+				return steal;
+			};
+		},
+		callOnArgs: function( f ) {
+			return function() {
+				for ( var i = 0; i < arguments.length; i++ ) {
+					f(arguments[i]);
+				}
+				return steal;
+			};
+
+		},
+		// Returns a function that applies a function to a list of arguments.  Then steals those
+		// arguments.
+		applier: function( f ) {
+			return function() {
+				var args = [];
+				for ( var i = 0; i < arguments.length; i++ ) {
+					if ( typeof arguments[i] == "function" ) {
+						args[i] = arguments[i];
+					} else {
+						args[i] = f(arguments[i]);
+					}
+
+				}
+				steal.apply(null, args);
+				return steal;
+			};
+		},
+		/**
+		 * @function then
+		 * A chainable alias for [steal].
+		 */
+		then: steal,
+		total: total
+	});
+	var stealPlugin = steal.resetApp(function( p ) {
+		return p + '/' + getLastPart(p);
+	});
+	steal.packs = function() {
+		for ( var i = 0; i < arguments.length; i++ ) {
+			if ( typeof arguments[i] == "function" ) {
+				steal(arguments[i]);
+			} else {
+				steal({
+					force: true,
+					path: "//packages/" + arguments[i] + ".js"
+				});
+			}
+		}
+		return this;
+	};
+
+	extend(steal, {
+
+		/**
+		 * @function plugins
+		 * Loads a list of plugins given a path relative to steal's ROOT folder.
+		 * 
+		 * Steal.plugins is used to load relative to ROOT no matter where the current file is 
+		 * located.  For example, if you want to load the 'foo/bar' plugin that is located like:
+		 * 
+		 * @codestart
+		 * steal\
+		 * foo\
+		 *    bar\
+		 *       bar.js
+		 * @codeend
+		 * 
+		 * You can load it like:
+		 * 
+		 * @codestart
+		 * steal.plugins('foo/bar');
+		 * @codeend
+		 * 
+		 * It should be noted that plugins always looks for a JS file that shares the name of the
+		 * plugin's folder (bar.js is in bar).
+		 * 
+		 * @param {String} plugin_location location of a plugin, ex: jquery/dom/history.
+		 * @return {steal} a new steal object
+		 * 
+		 */
+		plugins: steal.callOnArgs(stealPlugin),
+
+
+		/**
+		 * @function controllers
+		 * Loads controllers from the current file's <b>controllers</b> directory.
+		 * <br>
+		 * <code>steal.controllers</code> adds the suffix <code>_controller.js</code> to each name passed in.
+		 * <br>
+		 * <br>
+		 * Example:
+		 * <br>
+		 * If you want to load controllers/recipe_controller.js and controllers/ingredient_controller.js,
+		 * write:
+		 * @codestart 
+		 *  steal.controllers('recipe',
+		 *                    'ingredient')
+		 * @codeend
+		 * @param {String+} controller the name of of the {NAME}_controller.js file to load. You can pass multiple controller names.
+		 * @return {steal} the steal function for chaining.    
+		 */
+		controllers: steal.applier(function( i ) {
+			if ( i.match(/^\/\//) ) {
+				i = steal.root.join(i.substr(2));
+				return i;
+			}
+			return 'controllers/' + i + '_controller';
+		}),
+
+		/**
+		 * @function models
+		 * Loads models  from the current file's <b>models</b> directory.
+		 * <br>
+		 * <br>
+		 * Example:
+		 * <br>
+		 * If you want to include models/recipe.js and models/ingredient.js,
+		 * write:
+		 * @codestart 
+		 *  steal.models('recipe',
+		 *               'ingredient')
+		 * @codeend
+		 * @param {String+} model The name of the model file you want to load.  You can pass multiple model names.
+		 * @return {steal} the steal function for chaining.
+		 */
+		models: steal.applier(function( i ) {
+			if ( i.match(/^\/\//) ) {
+				i = steal.root.join(i.substr(2));
+				return i;
+			}
+			return 'models/' + i;
+		}),
+
+		/**
+		 * @function resources
+		 * Loads resources from the current file's <b>resources</b> directory.
+		 * <br>
+		 * <br>
+		 * Example:
+		 * <br>
+		 * If you want to load resources/i18n.js, write:
+		 * @codestart 
+		 *  steal.resources('i18n')
+		 * @codeend
+		 * @param {String+} resource The name of the resource file you want to load.  You can pass multiple model names.
+		 * @return {steal} the steal function for chaining.
+		 */
+		resources: steal.applier(function( i ) {
+			if ( i.match(/^\/\//) ) {
+				i = steal.root.join(i.substr(2));
+				return i;
+			}
+			return 'resources/' + i;
+		}),
+
+		/**
+		 * @function views
+		 * Loads views to be added to the production build.  Paths must be given from steal's ROOT folder.
+		 * <br>
+		 * <br>
+		 * Example:
+		 * <br>
+		 * The following loads, coookbook/views/recipe/show.ejs and coookbook/views/recipe/list.ejs:
+		 * @codestart 
+		 *  steal.views('//coookbook/views/recipe/show.ejs',
+		 *              '//coookbook/views/recipe/list.ejs')
+		 * @codeend
+		 * @param {String} path The view's path rooted from steal's root folder.
+		 * @return {steal} the steal function for chaining.   
+		 */
+		views: function() {
+			// Only includes views for compression and docs (when running in rhino)
+			if ( browser.rhino || steal.options.env == "production" ) {
+				for ( var i = 0; i < arguments.length; i++ ) {
+					steal.view(arguments[i]);
+				}
+			}
+			return steal;
+		},
+
+		timerCount: 0,
+		view: function( path ) {
+			var type = path.match(/\.\w+$/gi)[0].replace(".", "");
+			if( path.indexOf("//") !== 0 ){
+				path = "views/"+path;
+			}
+			steal({
+				path: path,
+				type: "text/" + type,
+				compress: "false"
+			});
+			return steal;
+		},
+		timers: {},
+		//tracks the last script
+		ct: function( id ) { //for clear timer
+			clearTimeout(steal.timers[id]);
+			delete steal.timers[id];
+		},
+		loadErrorTimer: function( options ) {
+			var count = ++steal.timerCount;
+			steal.timers[count] = setTimeout(function() {
+				throw "steal.js Could not load " + options.src + ".  Are you sure you have the right path?";
+			}, 5000);
+			return "onLoad='steal.ct(" + count + ")' ";
+		},
+		cleanId: function( id ) {
+			return id.replace(/[\/\.]/g, "_");
+		}
+	});
+	//for integration with other build types
+	if (!steal.build ) {
+		steal.build = {
+			types: {}
+		};
+	}
+
+	steal.loadedProductionCSS = false;
+
+	steal.init();
+})();