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 [4/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/lang/json/json.js
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/json/json.js?rev=1149378&view=auto
==============================================================================
--- openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/json/json.js (added)
+++ openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/json/json.js Thu Jul 21 21:42:07 2011
@@ -0,0 +1,201 @@
+/*
+ * jQuery JSON Plugin
+ * version: 2.1 (2009-08-14)
+ *
+ * This document is licensed as free software under the terms of the
+ * MIT License: http://www.opensource.org/licenses/mit-license.php
+ *
+ * Brantley Harris wrote this plugin. It is based somewhat on the JSON.org 
+ * website's http://www.json.org/json2.js, which proclaims:
+ * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
+ * I uphold.
+ *
+ * It is also influenced heavily by MochiKit's serializeJSON, which is 
+ * copyrighted 2005 by Bob Ippolito.
+ */
+ steal.plugins('jquery').then(function(){
+(function($) {
+    /** jQuery.toJSON( json-serializble )
+        Converts the given argument into a JSON respresentation.
+
+        If an object has a "toJSON" function, that will be used to get the representation.
+        Non-integer/string keys are skipped in the object, as are keys that point to a function.
+
+        json-serializble:
+            The *thing* to be converted.
+     **/
+    $.toJSON = function(o, replacer, space, recurse)
+    {
+        if (typeof(JSON) == 'object' && JSON.stringify)
+            return JSON.stringify(o, replacer, space);
+
+        if (!recurse && $.isFunction(replacer))
+            o = replacer("", o);
+
+        if (typeof space == "number")
+            space = "          ".substring(0, space);
+        space = (typeof space == "string") ? space.substring(0, 10) : "";
+        
+        var type = typeof(o);
+    
+        if (o === null)
+            return "null";
+    
+        if (type == "undefined" || type == "function")
+            return undefined;
+        
+        if (type == "number" || type == "boolean")
+            return o + "";
+    
+        if (type == "string")
+            return $.quoteString(o);
+    
+        if (type == 'object')
+        {
+            if (typeof o.toJSON == "function") 
+                return $.toJSON( o.toJSON(), replacer, space, true );
+            
+            if (o.constructor === Date)
+            {
+                var month = o.getUTCMonth() + 1;
+                if (month < 10) month = '0' + month;
+
+                var day = o.getUTCDate();
+                if (day < 10) day = '0' + day;
+
+                var year = o.getUTCFullYear();
+                
+                var hours = o.getUTCHours();
+                if (hours < 10) hours = '0' + hours;
+                
+                var minutes = o.getUTCMinutes();
+                if (minutes < 10) minutes = '0' + minutes;
+                
+                var seconds = o.getUTCSeconds();
+                if (seconds < 10) seconds = '0' + seconds;
+                
+                var milli = o.getUTCMilliseconds();
+                if (milli < 100) milli = '0' + milli;
+                if (milli < 10) milli = '0' + milli;
+
+                return '"' + year + '-' + month + '-' + day + 'T' +
+                             hours + ':' + minutes + ':' + seconds + 
+                             '.' + milli + 'Z"'; 
+            }
+
+            var process = ($.isFunction(replacer)) ?
+                function (k, v) { return replacer(k, v); } :
+                function (k, v) { return v; },
+                nl = (space) ? "\n" : "",
+                sp = (space) ? " " : "";
+
+            if (o.constructor === Array) 
+            {
+                var ret = [];
+                for (var i = 0; i < o.length; i++)
+                    ret.push(( $.toJSON( process(i, o[i]), replacer, space, true ) || "null" ).replace(/^/gm, space));
+
+                return "[" + nl + ret.join("," + nl) + nl + "]";
+            }
+        
+            var pairs = [], proplist;
+            if ($.isArray(replacer)) {
+                proplist = $.map(replacer, function (v) {
+                    return (typeof v == "string" || typeof v == "number") ?
+                        v + "" :
+                        null;
+                });
+            }
+            for (var k in o) {
+                var name, val, type = typeof k;
+
+                if (proplist && $.inArray(k + "", proplist) == -1)
+                    continue;
+
+                if (type == "number")
+                    name = '"' + k + '"';
+                else if (type == "string")
+                    name = $.quoteString(k);
+                else
+                    continue;  //skip non-string or number keys
+            
+                val = $.toJSON( process(k, o[k]), replacer, space, true );
+            
+                if (typeof val == "undefined")
+                    continue;  //skip pairs where the value is a function.
+            
+                pairs.push((name + ":" + sp + val).replace(/^/gm, space));
+            }
+
+            return "{" + nl + pairs.join("," + nl) + nl + "}";
+        }
+    };
+
+    /** jQuery.evalJSON(src)
+        Evaluates a given piece of json source.
+     **/
+    $.evalJSON = function(src)
+    {
+        if (typeof(JSON) == 'object' && JSON.parse)
+            return JSON.parse(src);
+        return eval("(" + src + ")");
+    };
+    
+    /** jQuery.secureEvalJSON(src)
+        Evals JSON in a way that is *more* secure.
+    **/
+    $.secureEvalJSON = function(src)
+    {
+        if (typeof(JSON) == 'object' && JSON.parse)
+            return JSON.parse(src);
+        
+        var filtered = src;
+        filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
+        filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
+        filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
+        
+        if (/^[\],:{}\s]*$/.test(filtered))
+            return eval("(" + src + ")");
+        else
+            throw new SyntaxError("Error parsing JSON, source is not valid.");
+    };
+
+    /** jQuery.quoteString(string)
+        Returns a string-repr of a string, escaping quotes intelligently.  
+        Mostly a support function for toJSON.
+    
+        Examples:
+            >>> jQuery.quoteString("apple")
+            "apple"
+        
+            >>> jQuery.quoteString('"Where are we going?", she asked.')
+            "\"Where are we going?\", she asked."
+     **/
+    $.quoteString = function(string)
+    {
+        if (string.match(_escapeable))
+        {
+            return '"' + string.replace(_escapeable, function (a) 
+            {
+                var c = _meta[a];
+                if (typeof c === 'string') return c;
+                c = a.charCodeAt();
+                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
+            }) + '"';
+        }
+        return '"' + string + '"';
+    };
+    
+    var _escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
+    
+    var _meta = {
+        '\b': '\\b',
+        '\t': '\\t',
+        '\n': '\\n',
+        '\f': '\\f',
+        '\r': '\\r',
+        '"' : '\\"',
+        '\\': '\\\\'
+    };
+})(jQuery);
+})
\ No newline at end of file

Added: openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/lang.js
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/lang.js?rev=1149378&view=auto
==============================================================================
--- openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/lang.js (added)
+++ openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/lang.js Thu Jul 21 21:42:07 2011
@@ -0,0 +1,160 @@
+//string helpers
+steal.plugins('jquery').then(function( $ ) {
+	// Several of the methods in this plugin use code adapated from Prototype
+	//  Prototype JavaScript framework, version 1.6.0.1
+	//  (c) 2005-2007 Sam Stephenson
+	var regs = {
+		undHash: /_|-/,
+		colons: /::/,
+		words: /([A-Z]+)([A-Z][a-z])/g,
+		lowUp: /([a-z\d])([A-Z])/g,
+		dash: /([a-z\d])([A-Z])/g,
+		replacer: /\{([^\}]+)\}/g,
+		dot: /\./
+	},
+		getNext = function(current, nextPart, add){
+			return current[nextPart] || ( add && (current[nextPart] = {}) );
+		},
+		isContainer = function(current){
+			var type = typeof current;
+			return type && (  type == 'function' || type == 'object' );
+		},
+		getObject = function( objectName, roots, add ) {
+			
+			var parts = objectName ? objectName.split(regs.dot) : [],
+				length =  parts.length,
+				currents = $.isArray(roots) ? roots : [roots || window],
+				current,
+				ret, 
+				i,
+				c = 0,
+				type;
+			
+			if(length == 0){
+				return currents[0];
+			}
+			while(current = currents[c++]){
+				for (i =0; i < length - 1 && isContainer(current); i++ ) {
+					current = getNext(current, parts[i], add);
+				}
+				if( isContainer(current) ) {
+					
+					ret = getNext(current, parts[i], add); 
+					
+					if( ret !== undefined ) {
+						
+						if ( add === false ) {
+							delete current[parts[i]];
+						}
+						return ret;
+						
+					}
+					
+				}
+			}
+		},
+
+		/** 
+		 * @class jQuery.String
+		 * 
+		 * A collection of useful string helpers.
+		 * 
+		 */
+		str = $.String = $.extend( $.String || {} , {
+			/**
+			 * @function
+			 * Gets an object from a string.
+			 * @param {String} name the name of the object to look for
+			 * @param {Array} [roots] an array of root objects to look for the name
+			 * @param {Boolean} [add] true to add missing objects to 
+			 *  the path. false to remove found properties. undefined to 
+			 *  not modify the root object
+			 */
+			getObject : getObject,
+			/**
+			 * Capitalizes a string
+			 * @param {String} s the string.
+			 * @return {String} a string with the first character capitalized.
+			 */
+			capitalize: function( s, cache ) {
+				return s.charAt(0).toUpperCase() + s.substr(1);
+			},
+			/**
+			 * Capitalizes a string from something undercored. Examples:
+			 * @codestart
+			 * jQuery.String.camelize("one_two") //-> "oneTwo"
+			 * "three-four".camelize() //-> threeFour
+			 * @codeend
+			 * @param {String} s
+			 * @return {String} a the camelized string
+			 */
+			camelize: function( s ) {
+				s = str.classize(s);
+				return s.charAt(0).toLowerCase() + s.substr(1);
+			},
+			/**
+			 * Like camelize, but the first part is also capitalized
+			 * @param {String} s
+			 * @return {String} the classized string
+			 */
+			classize: function( s , join) {
+				var parts = s.split(regs.undHash),
+					i = 0;
+				for (; i < parts.length; i++ ) {
+					parts[i] = str.capitalize(parts[i]);
+				}
+
+				return parts.join(join || '');
+			},
+			/**
+			 * Like [jQuery.String.classize|classize], but a space separates each 'word'
+			 * @codestart
+			 * jQuery.String.niceName("one_two") //-> "One Two"
+			 * @codeend
+			 * @param {String} s
+			 * @return {String} the niceName
+			 */
+			niceName: function( s ) {
+				str.classize(parts[i],' ');
+			},
+
+			/**
+			 * Underscores a string.
+			 * @codestart
+			 * jQuery.String.underscore("OneTwo") //-> "one_two"
+			 * @codeend
+			 * @param {String} s
+			 * @return {String} the underscored string
+			 */
+			underscore: function( s ) {
+				return s.replace(regs.colons, '/').replace(regs.words, '$1_$2').replace(regs.lowUp, '$1_$2').replace(regs.dash, '_').toLowerCase();
+			},
+			/**
+			 * Returns a string with {param} replaced values from data.
+			 * 
+			 *     $.String.sub("foo {bar}",{bar: "far"})
+			 *     //-> "foo far"
+			 *     
+			 * @param {String} s The string to replace
+			 * @param {Object} data The data to be used to look for properties.  If it's an array, multiple
+			 * objects can be used.
+			 * @param {Boolean} [remove] if a match is found, remove the property from the object
+			 */
+			sub: function( s, data, remove ) {
+				var obs = [];
+				obs.push(s.replace(regs.replacer, function( whole, inside ) {
+					//convert inside to type
+					var ob = getObject(inside, data, typeof remove == 'boolean' ? !remove : remove),
+						type = typeof ob;
+					if((type === 'object' || type === 'function') && type !== null){
+						obs.push(ob);
+						return "";
+					}else{
+						return ""+ob;
+					}
+				}));
+				return obs.length <= 1 ? obs[0] : obs;
+			}
+		});
+
+});
\ No newline at end of file

Added: openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/openajax/openajax.js
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/openajax/openajax.js?rev=1149378&view=auto
==============================================================================
--- openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/openajax/openajax.js (added)
+++ openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/openajax/openajax.js Thu Jul 21 21:42:07 2011
@@ -0,0 +1,202 @@
+//@steal-clean
+/*******************************************************************************
+ * OpenAjax.js
+ *
+ * Reference implementation of the OpenAjax Hub, as specified by OpenAjax Alliance.
+ * Specification is under development at: 
+ *
+ *   http://www.openajax.org/member/wiki/OpenAjax_Hub_Specification
+ *
+ * Copyright 2006-2008 OpenAjax Alliance
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
+ * use this file except in compliance with the License. You may obtain a copy 
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0 . Unless 
+ * required by applicable law or agreed to in writing, software distributed 
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+ * specific language governing permissions and limitations under the License.
+ *
+ ******************************************************************************/
+steal.then(function(){
+// prevent re-definition of the OpenAjax object
+if(!window["OpenAjax"]){
+	/**
+	 * @class OpenAjax
+	 * Use OpenAjax.hub to publish and subscribe to messages.
+	 */
+    OpenAjax = new function(){
+		var t = true;
+		var f = false;
+		var g = window;
+		var ooh = "org.openajax.hub.";
+
+		var h = {};
+		this.hub = h;
+		h.implementer = "http://openajax.org";
+		h.implVersion = "1.0";
+		h.specVersion = "1.0";
+		h.implExtraData = {};
+		var libs = {};
+		h.libraries = libs;
+
+		h.registerLibrary = function(prefix, nsURL, version, extra){
+			libs[prefix] = {
+				prefix: prefix,
+				namespaceURI: nsURL,
+				version: version,
+				extraData: extra 
+			};
+			this.publish(ooh+"registerLibrary", libs[prefix]);
+		}
+		h.unregisterLibrary = function(prefix){
+			this.publish(ooh+"unregisterLibrary", libs[prefix]);
+			delete libs[prefix];
+		}
+
+		h._subscriptions = { c:{}, s:[] };
+		h._cleanup = [];
+		h._subIndex = 0;
+		h._pubDepth = 0;
+
+		h.subscribe = function(name, callback, scope, subscriberData, filter)			
+		{
+			if(!scope){
+				scope = window;
+			}
+			var handle = name + "." + this._subIndex;
+			var sub = { scope: scope, cb: callback, fcb: filter, data: subscriberData, sid: this._subIndex++, hdl: handle };
+			var path = name.split(".");
+	 		this._subscribe(this._subscriptions, path, 0, sub);
+			return handle;
+		}
+
+		h.publish = function(name, message)		
+		{
+			var path = name.split(".");
+			this._pubDepth++;
+			this._publish(this._subscriptions, path, 0, name, message);
+			this._pubDepth--;
+			if((this._cleanup.length > 0) && (this._pubDepth == 0)) {
+				for(var i = 0; i < this._cleanup.length; i++) 
+					this.unsubscribe(this._cleanup[i].hdl);
+				delete(this._cleanup);
+				this._cleanup = [];
+			}
+		}
+
+		h.unsubscribe = function(sub) 
+		{
+			var path = sub.split(".");
+			var sid = path.pop();
+			this._unsubscribe(this._subscriptions, path, 0, sid);
+		}
+		
+		h._subscribe = function(tree, path, index, sub) 
+		{
+			var token = path[index];
+			if(index == path.length) 	
+				tree.s.push(sub);
+			else { 
+				if(typeof tree.c == "undefined")
+					 tree.c = {};
+				if(typeof tree.c[token] == "undefined") {
+					tree.c[token] = { c: {}, s: [] }; 
+					this._subscribe(tree.c[token], path, index + 1, sub);
+				}
+				else 
+					this._subscribe( tree.c[token], path, index + 1, sub);
+			}
+		}
+
+		h._publish = function(tree, path, index, name, msg, pcb, pcid) {
+			if(typeof tree != "undefined") {
+				var node;
+				if(index == path.length) {
+					node = tree;
+				} else {
+					this._publish(tree.c[path[index]], path, index + 1, name, msg, pcb, pcid);
+					this._publish(tree.c["*"], path, index + 1, name, msg, pcb, pcid);			
+					node = tree.c["**"];
+				}
+				if(typeof node != "undefined") {
+					var callbacks = node.s;
+					var max = callbacks.length;
+					for(var i = 0; i < max; i++) {
+						if(callbacks[i].cb) {
+							var sc = callbacks[i].scope;
+							var cb = callbacks[i].cb;
+							var fcb = callbacks[i].fcb;
+							var d = callbacks[i].data;
+							var sid = callbacks[i].sid;
+							var scid = callbacks[i].cid;
+							if(typeof cb == "string"){
+								// get a function object
+								cb = sc[cb];
+							}
+							if(typeof fcb == "string"){
+								// get a function object
+								fcb = sc[fcb];
+							}
+							if((!fcb) || (fcb.call(sc, name, msg, d))) {
+							  if((!pcb) || (pcb(name, msg, pcid, scid))) {
+								  cb.call(sc, name, msg, d, sid);
+							  }
+							}
+						}
+					}
+				}
+			}
+		}
+			
+		h._unsubscribe = function(tree, path, index, sid) {
+			if(typeof tree != "undefined") {
+				if(index < path.length) {
+					var childNode = tree.c[path[index]];
+					this._unsubscribe(childNode, path, index + 1, sid);
+					if(childNode.s.length == 0) {
+						for(var x in childNode.c) 
+					 		return;		
+						delete tree.c[path[index]];	
+					}
+					return;
+				}
+				else {
+					var callbacks = tree.s;
+					var max = callbacks.length;
+					for(var i = 0; i < max; i++) 
+						if(sid == callbacks[i].sid) {
+							if(this._pubDepth > 0) {
+								callbacks[i].cb = null;	
+								this._cleanup.push(callbacks[i]);						
+							}
+							else
+								callbacks.splice(i, 1);
+							return; 	
+						}
+				}
+			}
+		}
+		// The following function is provided for automatic testing purposes.
+		// It is not expected to be deployed in run-time OpenAjax Hub implementations.
+		h.reinit = function()
+		{
+			for (var lib in OpenAjax.hub.libraries) {
+				delete OpenAjax.hub.libraries[lib];
+			}
+			OpenAjax.hub.registerLibrary("OpenAjax", "http://openajax.org/hub", "1.0", {});
+
+			delete OpenAjax._subscriptions;
+			OpenAjax._subscriptions = {c:{},s:[]};
+			delete OpenAjax._cleanup;
+			OpenAjax._cleanup = [];
+			OpenAjax._subIndex = 0;
+			OpenAjax._pubDepth = 0;
+		}
+	};
+	// Register the OpenAjax Hub itself as a library.
+	OpenAjax.hub.registerLibrary("OpenAjax", "http://openajax.org/hub", "1.0", {});
+
+}
+OpenAjax.hub.registerLibrary("JavaScriptMVC", "http://JavaScriptMVC.com", "3.0", {});
+});
\ No newline at end of file

Added: openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/rsplit/rsplit.js
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/rsplit/rsplit.js?rev=1149378&view=auto
==============================================================================
--- openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/rsplit/rsplit.js (added)
+++ openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/lang/rsplit/rsplit.js Thu Jul 21 21:42:07 2011
@@ -0,0 +1,35 @@
+steal.plugins('jquery/lang').then(function( $ ) {
+	/**
+	 * @add jQuery.String
+	 */
+	$.String.
+	/**
+	 * Splits a string with a regex correctly cross browser
+	 * 
+	 *     $.String.rsplit("a.b.c.d", /\./) //-> ['a','b','c','d']
+	 * 
+	 * @param {String} string The string to split
+	 * @param {RegExp} regex A regular expression
+	 * @return {Array} An array of strings
+	 */
+	rsplit = function( string, regex ) {
+		var result = regex.exec(string),
+			retArr = [],
+			first_idx, last_idx;
+		while ( result !== null ) {
+			first_idx = result.index;
+			last_idx = regex.lastIndex;
+			if ( first_idx !== 0 ) {
+				retArr.push(string.substring(0, first_idx));
+				string = string.slice(first_idx);
+			}
+			retArr.push(result[0]);
+			string = string.slice(result[0].length);
+			result = regex.exec(string);
+		}
+		if ( string !== '' ) {
+			retArr.push(string);
+		}
+		return retArr;
+	};
+});
\ No newline at end of file

Added: openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/model/model.js
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/model/model.js?rev=1149378&view=auto
==============================================================================
--- openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/model/model.js (added)
+++ openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/model/model.js Thu Jul 21 21:42:07 2011
@@ -0,0 +1,1638 @@
+/*global OpenAjax: true */
+
+steal.plugins('jquery/class', 'jquery/lang').then(function() {
+	
+	//helper stuff for later.  Eventually, might not need jQuery.
+	var underscore = $.String.underscore,
+		classize = $.String.classize,
+		isArray = $.isArray,
+		makeArray = $.makeArray,
+		extend = $.extend,
+		each = $.each,
+		reqType = /GET|POST|PUT|DELETE/i,
+		ajax = function(ajaxOb, attrs, success, error, fixture, type, dataType){
+			var dataType = dataType || "json",
+				src = "",
+				tmp;
+			if(typeof ajaxOb == "string"){
+				var sp = ajaxOb.indexOf(" ")
+				if( sp > 2 && sp <7){
+					tmp = ajaxOb.substr(0,sp);
+					if(reqType.test(tmp)){
+						type = tmp;
+					}else{
+						dataType = tmp;
+					}
+					src = ajaxOb.substr(sp+1)
+				}else{
+					src = ajaxOb;
+				}
+			}
+			attrs = extend({},attrs)
+			
+			var url = $.String.sub(src, attrs, true)
+			return $.ajax({
+				url : url,
+				data : attrs,
+				success : success,
+				error: error,
+				type : type || "post",
+				dataType : dataType,
+				fixture: fixture
+			});
+		},
+		addId = function(attrs, id){
+			attrs = attrs || {};
+			var identity = this.id;
+			if(attrs[identity] && attrs[identity] !== id){
+				attrs["new"+$.String.capitalize(id)] = attrs[identity];
+				delete attrs[identity];
+			}
+			attrs[identity] = id;
+			return attrs;
+		},
+		getList = function(type){
+			var listType = type || $.Model.List || Array;
+			return new listType();
+		},
+		getId = function(inst){
+			return inst[inst.Class.id]
+		},
+		unique = function(items){
+	        var collect = [];
+	        for(var i=0; i < items.length; i++){
+	            if(!items[i]["__u Nique"]){
+	                collect.push(items[i]);
+	                items[i]["__u Nique"] = true;
+	            }
+	        }
+	        for(i=0; i< collect.length; i++){
+	            delete collect[i]["__u Nique"];
+	        }
+	        return collect;
+	    },
+		// makes a deferred request
+		makeRequest = function(self, type, success, error, method){
+			var deferred = $.Deferred(),
+				resolve = function(data){
+					self[method || type+"d"](data);
+					deferred.resolveWith(self,[self, data, type]);
+				},
+				reject = function(data){
+					deferred.rejectWith(self, [data])
+				},
+				args = [self.attrs(), resolve, reject];
+				
+			if(type == 'destroy'){
+				args.shift();
+			}	
+				
+			if(type !== 'create' ){
+				args.unshift(getId(self))
+			} 
+			
+			deferred.then(success);
+			deferred.fail(error);
+			
+			self.Class[type].apply(self.Class, args);
+				
+			return deferred.promise();
+		},
+		// a quick way to tell if it's an object and not some string
+		isObject = function(obj){
+			return typeof obj === 'object' && obj !== null && obj;
+		},
+		$method = function(name){
+			return function( eventType, handler ) {
+				$.fn[name].apply($([this]), arguments);
+				return this;
+			}
+		},
+		bind = $method('bind'),
+		unbind = $method('unbind');
+	/**
+	 * @class jQuery.Model
+	 * @tag core
+	 * @download  http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/model/model.js
+	 * @test jquery/model/qunit.html
+	 * @plugin jquery/model
+	 * 
+	 * Models wrap an application's data layer.  In large applications, a model is critical for:
+	 * 
+	 *  - [jquery.model.encapsulate Encapsulating] services so controllers + views don't care where data comes from.
+	 *    
+	 *  - Providing helper functions that make manipulating and abstracting raw service data easier.
+	 * 
+	 * This is done in two ways:
+	 * 
+	 *  - Requesting data from and interacting with services
+	 *  
+	 *  - Converting or wrapping raw service data into a more useful form.
+	 * 
+	 * 
+	 * ## Basic Use
+	 * 
+	 * The [jQuery.Model] class provides a basic skeleton to organize pieces of your application's data layer.
+	 * First, consider doing Ajax <b>without</b> a model.  In our imaginary app, you:
+	 * 
+	 *  - retrieve a list of tasks</li>
+	 *  - display the number of days remaining for each task
+	 *  - mark tasks as complete after users click them
+	 * 
+	 * Let's see how that might look without a model:
+	 * 
+	 * @codestart
+	 * $.Controller("Tasks",
+	 * {
+	 *   // get tasks when the page is ready 
+	 *   init: function() {
+	 *     $.get('/tasks.json', this.callback('gotTasks'), 'json')
+	 *   },
+	 *  |* 
+	 *   * assume json is an array like [{name: "trash", due_date: 1247111409283}, ...]
+	 *   *|
+	 *  gotTasks: function( json ) { 
+	 *     for(var i =0; i < json.length; i++){
+	 *       var taskJson = json[i];
+	 *       
+	 *       //calculate time remaining
+	 *       var remaininTime = new Date() - new Date(taskJson.due_date);
+	 *       
+	 *       //append some html
+	 *       $("#tasks").append("&lt;div class='task' taskid='"+taskJson.id+"'>"+
+	 *                           "&lt;label>"+taskJson.name+"&lt;/label>"+
+	 *                           "Due Date = "+remaininTime+"&lt;/div>")
+	 *     }
+	 *   },
+	 *   // when a task is complete, get the id, make a request, remove it
+	 *   ".task click" : function( el ) {
+	 *     $.post('/tasks/'+el.attr('data-taskid')+'.json',
+	 *     	 {complete: true}, 
+	 *       function(){
+	 *         el.remove();
+	 *       })
+	 *   }
+	 * })
+	 * @codeend
+	 * 
+	 * This code might seem fine for right now, but what if:
+	 * 
+	 *  - The service changes?
+	 *  - Other parts of the app want to calculate <code>remaininTime</code>?
+	 *  - Other parts of the app want to get tasks?</li>
+	 *  - The same task is represented multiple palces on the page?
+	 * 
+	 * The solution is of course a strong model layer.  Lets look at what a
+	 * a good model does for a controller before we learn how to make one:
+	 * 
+	 * @codestart
+	 * $.Controller("Tasks",
+	 * {
+	 *   init: function() {
+	 *     Task.findAll({}, this.callback('tasks'));
+	 *   },
+	 *   list : function(todos){
+	 *     this.element.html("tasks.ejs", todos );
+	 *   },
+	 *   ".task click" : function( el ) {
+	 *     el.model().update({complete: true},function(){
+	 *       el.remove();
+	 *     });
+	 *   }
+	 * });
+	 * @codeend
+	 * 
+	 * In tasks.ejs
+	 * 
+	 * @codestart html
+	 * &lt;% for(var i =0; i &lt; tasks.length; i++){ %>
+	 * &lt;div &lt;%= tasks[i] %>>
+	 *    &lt;label>&lt;%= tasks[i].name %>&lt;/label>
+	 *    &lt;%= tasks[i].<b>timeRemaining</b>() %>
+	 * &lt;/div>
+	 * &lt;% } %>
+	 * @codeend
+	 * 
+	 * Isn't that better!  Granted, some of the improvement comes because we used a view, but we've
+	 * also made our controller completely understandable.  Now lets take a look at the model:
+	 * 
+	 * @codestart
+	 * $.Model("Task",
+	 * {
+	 *  findAll: "/tasks.json",
+	 *  update: "/tasks/{id}.json"
+	 * },
+	 * {
+	 *  timeRemaining: function() {
+	 *   return new Date() - new Date(this.due_date)
+	 *  }
+	 * })
+	 * @codeend
+	 * 
+	 * Much better!  Now you have a single place where you 
+	 * can organize Ajax functionality and
+	 * wrap the data that it returned.  Lets go through 
+	 * each bolded item in the controller and view.
+	 * 
+	 * ### Task.findAll
+	 * 
+	 * The findAll function requests data from "/tasks.json".  When the data is returned, 
+	 * it converted by the [jQuery.Model.static.models models] function before being 
+	 * passed to the success callback.
+	 * 
+	 * ### el.model
+	 * 
+	 * [jQuery.fn.model] is a jQuery helper that returns a model instance from an element.  The 
+	 * list.ejs template assings tasks to elements with the following line:
+	 * 
+	 * @codestart html
+	 * &lt;div &lt;%= tasks[i] %>> ... &lt;/div>
+	 * @codeend
+	 * 
+	 * ### timeRemaining
+	 * 
+	 * timeRemaining is an example of wrapping your model's raw data with more useful functionality.
+	 * 
+	 * ## Other Good Stuff
+	 * 
+	 * This is just a tiny taste of what models can do.  Check out these other features:
+	 * 
+	 * ### [jquery.model.encapsulate Encapsulation]
+	 * 
+	 * Learn how to connect to services.
+	 * 
+	 *     $.Model("Task",{
+	 *       findAll : "/tasks.json",    
+	 *       findOne : "/tasks/{id}.json", 
+	 *       create : "/tasks.json",
+	 *       update : "/tasks/{id}.json"
+	 *     },{})
+	 * 
+	 * ### [jquery.model.typeconversion Type Conversion]
+	 * 
+	 * Convert data like "10-20-1982" into new Date(1982,9,20) auto-magically:
+	 * 
+	 *     $.Model("Task",{
+	 *       attributes : {birthday : "date"}
+	 *       convert : {
+	 *         date : function(raw){ ... }
+	 *       }
+	 *     },{})
+	 * 
+	 * ### [jQuery.Model.List]
+	 * 
+	 * Learn how to handle multiple instances with ease.
+	 * 
+	 *     $.Model.List("Task.List",{
+	 *       destroyAll : function(){
+	 *         var ids = this.map(function(c){ return c.id });
+	 *         $.post("/destroy",
+	 *           ids,
+	 *           this.callback('destroyed'),
+	 *           'json')
+	 *       },
+	 *       destroyed : function(){
+	 *         this.each(function(){ this.destroyed() });
+	 *       }
+	 *     });
+	 *     
+	 *     ".destroyAll click" : function(){
+	 *       this.find('.destroy:checked')
+	 *           .closest('.task')
+	 *           .models()
+	 *           .destroyAll();
+	 *     }
+	 * 
+	 * ### [jquery.model.validations Validations]
+	 * 
+	 * Validate your model's attributes.
+	 * 
+	 *     $.Model("Contact",{
+	 *     init : function(){
+	 *         this.validate("birthday",function(){
+	 *             if(this.birthday > new Date){
+	 *                 return "your birthday needs to be in the past"
+	 *             }
+	 *         })
+	 *     }
+	 *     ,{});
+	 *     
+	 *     
+	 */
+		// methods that we'll weave into model if provided
+		ajaxMethods = 
+		/** 
+	     * @Static
+	     */
+		{
+		create: function(str  ) {
+			/**
+			 * @function create
+			 * Create is used to create a model instance on the server.  By implementing 
+			 * create along with the rest of the [jquery.model.services service api], your models provide an abstract
+			 * API for services.  
+			 * 
+			 * Create is called by save to create a new instance.  If you want to be able to call save on an instance
+			 * you have to implement create.
+			 * 
+			 * The easiest way to implement create is to just give it the url to post data to:
+			 * 
+			 *     $.Model("Recipe",{
+			 *       create: "/recipes"
+			 *     },{})
+			 *     
+			 * This lets you create a recipe like:
+			 *  
+			 *     new Recipe({name: "hot dog"}).save(function(){
+			 *       this.name //this is the new recipe
+			 *     }).save(callback)
+			 *  
+			 * You can also implement create by yourself.  You just need to call success back with
+			 * an object that contains the id of the new instance and any other properties that should be
+			 * set on the instance.
+			 *  
+			 * For example, the following code makes a request 
+			 * to '/recipes.json?name=hot+dog' and gets back
+			 * something that looks like:
+			 *  
+			 *     { 
+			 *       id: 5,
+			 *       createdAt: 2234234329
+			 *     }
+			 * 
+			 * The code looks like:
+			 * 
+			 *     $.Model("Recipe", {
+			 *       create : function(attrs, success, error){
+			 *         $.post("/recipes.json",attrs, success,"json");
+			 *       }
+			 *     },{})
+			 * 
+			 * ## API
+			 * 
+			 * @param {Object} attrs Attributes on the model instance
+			 * @param {Function} success(attrs) the callback function, it must be called with an object 
+			 * that has the id of the new instance and any other attributes the service needs to add.
+			 * @param {Function} error a function to callback if something goes wrong.  
+			 */
+			return function(attrs, success, error){
+				return ajax(str, attrs, success, error, "-restCreate")
+			};
+		},
+		update: function( str ) {
+			/**
+			 * @function update
+			 * Update is used to update a model instance on the server.  By implementing 
+			 * update along with the rest of the [jquery.model.services service api], your models provide an abstract
+			 * API for services.  
+			 * 
+			 * Update is called by [jQuery.Model.prototype.save] or [jQuery.Model.prototype.update] 
+			 * on an existing model instance.  If you want to be able to call save on an instance
+			 * you have to implement update.
+			 * 
+			 * The easist way to implement update is to just give it the url to put data to:
+			 * 
+			 *     $.Model("Recipe",{
+			 *       create: "/recipes/{id}"
+			 *     },{})
+			 *     
+			 * This lets you update a recipe like:
+			 *  
+			 *     // PUT /recipes/5 {name: "Hot Dog"}
+			 *     recipe.update({name: "Hot Dog"},
+			 *       function(){
+			 *         this.name //this is the updated recipe
+			 *       })
+			 *  
+			 * If your server doesn't use PUT, you can change it to post like:
+			 * 
+			 *     $.Model("Recipe",{
+			 *       create: "POST /recipes/{id}"
+			 *     },{})
+			 * 
+			 * Your server should send back an object with any new attributes the model 
+			 * should have.  For example if your server udpates the "updatedAt" property, it
+			 * should send back something like:
+			 * 
+			 *     // PUT /recipes/4 {name: "Food"} ->
+			 *     {
+			 *       updatedAt : "10-20-2011"
+			 *     }
+			 * 
+			 * You can also implement create by yourself.  You just need to call success back with
+			 * an object that contains any properties that should be
+			 * set on the instance.
+			 *  
+			 * For example, the following code makes a request 
+			 * to '/recipes/5.json?name=hot+dog' and gets back
+			 * something that looks like:
+			 *  
+			 *     { 
+			 *       updatedAt: "10-20-2011"
+			 *     }
+			 * 
+			 * The code looks like:
+			 * 
+			 *     $.Model("Recipe", {
+			 *       update : function(id, attrs, success, error){
+			 *         $.post("/recipes/"+id+".json",attrs, success,"json");
+			 *       }
+			 *     },{})
+			 * 
+			 * ## API
+			 * 
+			 * @param {String} id the id of the model instance
+			 * @param {Object} attrs Attributes on the model instance
+			 * @param {Function} success(attrs) the callback function, it must be called with an object 
+			 * that has the id of the new instance and any other attributes the service needs to add.
+			 * @param {Function} error a function to callback if something goes wrong.  
+			 */
+			return function(id, attrs, success, error){
+				return ajax(str, addId.call(this,attrs, id), success, error, "-restUpdate","put")
+			}
+		},
+		destroy: function( str ) {
+			/**
+			 * @function destroy
+			 * Destroy is used to remove a model instance from the server. By implementing 
+			 * destroy along with the rest of the [jquery.model.services service api], your models provide an abstract
+			 * service API.
+			 * 
+			 * You can implement destroy with a string like:
+			 * 
+			 *     $.Model("Thing",{
+			 *       destroy : "POST /thing/destroy/{id}"
+			 *     })
+			 * 
+			 * Or you can implement destroy manually like:
+			 * 
+			 *     $.Model("Thing",{
+			 *       destroy : function(id, success, error){
+			 *         $.post("/thing/destroy/"+id,{}, success);
+			 *       }
+			 *     })
+			 * 
+			 * You just have to call success if the destroy was successful.
+			 * 
+			 * @param {String|Number} id the id of the instance you want destroyed
+			 * @param {Function} success the callback function, it must be called with an object 
+			 * that has the id of the new instance and any other attributes the service needs to add.
+			 * @param {Function} error a function to callback if something goes wrong.  
+			 */
+			return function( id, success, error ) {
+				var attrs = {};
+				attrs[this.id] = id;
+				return ajax(str, attrs, success, error, "-restDestroy","delete")
+			}
+		},
+		
+		findAll: function( str ) {
+			/**
+			 * @function findAll
+			 * FindAll is used to retrive a model instances from the server. By implementing 
+			 * findAll along with the rest of the [jquery.model.services service api], your models provide an abstract
+			 * service API.
+			 * findAll returns a deferred ($.Deferred)
+			 * 
+			 * You can implement findAll with a string:
+			 * 
+			 *     $.Model("Thing",{
+			 *       findAll : "/things.json"
+			 *     },{})
+			 * 
+			 * Or you can implement it yourself.  The 'dataType' attribute is used to convert a JSON array of attributes
+			 * to an array of instances.  For example:
+			 * 
+			 *     $.Model("Thing",{
+			 *       findAll : function(params, success, error){
+			 *         return $.ajax({
+			 *         	 url: '/things.json',
+			 *           type: 'get',
+			 *           dataType: 'json thing.models',
+			 *           data: params,
+			 *           success: success,
+			 *           error: error})
+			 *       }
+			 *     },{})
+			 * 
+			 * ## API
+			 * 
+			 * @param {Object} params data to refine the results.  An example might be passing {limit : 20} to
+			 * limit the number of items retrieved.
+			 * @param {Function} success(items) called with an array (or Model.List) of model instances.
+			 * @param {Function} error
+			 */
+			return function(params, success, error){
+				return ajax(str || this.shortName+"s.json", 
+					params, 
+					success, 
+					error, 
+					fixture.call(this,"s"),
+					"get",
+					"json "+this._shortName+".models");
+			};
+		},
+		findOne: function( str ) {
+			/**
+			 * @function findOne
+			 * FindOne is used to retrive a model instances from the server. By implementing 
+			 * findOne along with the rest of the [jquery.model.services service api], your models provide an abstract
+			 * service API.
+			 * 
+			 * You can implement findOne with a string:
+			 * 
+			 *     $.Model("Thing",{
+			 *       findOne : "/things/{id}.json"
+			 *     },{})
+			 * 
+			 * Or you can implement it yourself. 
+			 * 
+			 *     $.Model("Thing",{
+			 *       findOne : function(params, success, error){
+			 *         var self = this,
+			 *             id = params.id;
+			 *         delete params.id;
+			 *         return $.get("/things/"+id+".json",
+			 *           params,
+			 *           success,
+			 *           "json thing.model")
+			 *       }
+			 *     },{})
+			 * 
+			 * ## API
+			 * 
+			 * @param {Object} params data to refine the results. This is often something like {id: 5}.
+			 * @param {Function} success(item) called with a model instance
+			 * @param {Function} error
+			 */
+			return function(params, success, error){
+				return ajax(str,
+					params, 
+					success,
+					error, 
+					fixture.call(this),
+					"get",
+					"json "+this._shortName+".model");
+			};
+		}
+	};
+
+
+
+
+
+	jQuery.Class("jQuery.Model",	{
+		setup: function( superClass , stat, proto) {
+			//we do not inherit attributes (or associations)
+			var self=this;
+			each(["attributes","associations","validations"],function(i,name){
+				if (!self[name] || superClass[name] === self[name] ) {
+					self[name] = {};
+				}
+			})
+
+			//add missing converters
+			if ( superClass.convert != this.convert ) {
+				this.convert = extend(superClass.convert, this.convert);
+			}
+
+
+			this._fullName = underscore(this.fullName.replace(/\./g, "_"));
+			this._shortName = underscore(this.shortName);
+
+			if ( this.fullName.substr(0, 7) == "jQuery." ) {
+				return;
+			}
+
+			//add this to the collection of models
+			//jQuery.Model.models[this._fullName] = this;
+
+			if ( this.listType ) {
+				this.list = new this.listType([]);
+			}
+			//@steal-remove-start
+			if (! proto ) {
+				steal.dev.warn("model.js "+this.fullName+" has no static properties.  You probably need  ,{} ")
+			}
+			//@steal-remove-end
+			for(var name in ajaxMethods){
+				if(typeof this[name] !== 'function'){
+					this[name] = ajaxMethods[name](this[name]);
+				}
+			}
+			
+			//add ajax converters
+			var converters = {},
+				convertName = "* "+this._shortName+".model";
+			converters[convertName+"s"] = this.callback('models');
+			converters[convertName] = this.callback('model');
+			$.ajaxSetup({
+				converters : converters
+			});				
+		},
+		/**
+		 * @attribute attributes
+		 * Attributes contains a list of properties and their types
+		 * for this model.  You can use this in conjunction with 
+		 * [jQuery.Model.static.convert] to provide automatic 
+		 * [jquery.model.typeconversion type conversion].  
+		 * 
+		 * The following converts dueDates to JavaScript dates:
+		 * 
+		 * @codestart
+		 * $.Model("Contact",{
+		 *   attributes : { 
+		 *     birthday : 'date'
+		 *   },
+		 *   convert : {
+		 *     date : function(raw){
+		 *       if(typeof raw == 'string'){
+		 *         var matches = raw.match(/(\d+)-(\d+)-(\d+)/)
+		 *         return new Date( matches[1], 
+		 *                  (+matches[2])-1, 
+		 *                 matches[3] )
+		 *       }else if(raw instanceof Date){
+		 *           return raw;
+		 *       }
+		 *     }
+		 *   }
+		 * },{})
+		 * @codeend
+		 */
+		attributes: {},
+		/**
+		 * @function wrap
+		 * @hide
+		 * @tag deprecated
+		 * __warning__ : wrap is deprecated in favor of [jQuery.Model.static.model].  They 
+		 * provide the same functionality; however, model works better with Deferreds.
+		 * 
+		 * Wrap is used to create a new instance from data returned from the server.
+		 * It is very similar to doing <code> new Model(attributes) </code> 
+		 * except that wrap will check if the data passed has an
+		 * 
+		 * - attributes,
+		 * - data, or
+		 * - <i>singularName</i>
+		 * 
+		 * property.  If it does, it will use that objects attributes.
+		 * 
+		 * Wrap is really a convience method for servers that don't return just attributes.
+		 * 
+		 * @param {Object} attributes
+		 * @return {Model} an instance of the model
+		 */
+		// wrap place holder
+		/**
+		 * $.Model.model is used as a [http://api.jquery.com/extending-ajax/#Converters Ajax converter] 
+		 * to convert the response of a [jQuery.Model.static.findOne] request 
+		 * into a model instance.  
+		 * 
+		 * You will never call this method directly.  Instead, you tell $.ajax about it in findOne:
+		 * 
+		 *     $.Model('Recipe',{
+		 *       findOne : function(params, success, error ){
+		 *         return $.ajax({
+		 *           url: '/services/recipes/'+params.id+'.json',
+		 *           type: 'get',
+		 *           
+		 *           dataType : 'json recipe.model' //LOOK HERE!
+		 *         });
+		 *       }
+		 *     },{})
+		 * 
+		 * This makes the result of findOne a [http://api.jquery.com/category/deferred-object/ $.Deferred]
+		 * that resolves to a model instance:
+		 * 
+		 *     var deferredRecipe = Recipe.findOne({id: 6});
+		 *     
+		 *     deferredRecipe.then(function(recipe){
+		 *       console.log('I am '+recipes.description+'.');
+		 *     })
+		 * 
+		 * ## Non-standard Services
+		 * 
+		 * $.jQuery.model expects data to be name-value pairs like:
+		 * 
+		 *     {id: 1, name : "justin"}
+		 *     
+		 * It can also take an object with attributes in a data, attributes, or
+		 * 'shortName' property.  For a App.Models.Person model the following will  all work:
+		 * 
+		 *     { data : {id: 1, name : "justin"} }
+		 *     
+		 *     { attributes : {id: 1, name : "justin"} }
+		 *     
+		 *     { person : {id: 1, name : "justin"} }
+		 * 
+		 * 
+		 * ### Overwriting Model
+		 * 
+		 * If your service returns data like:
+		 * 
+		 *     {id : 1, name: "justin", data: {foo : "bar"} }
+		 *     
+		 * This will confuse $.Model.model.  You will want to overwrite it to create 
+		 * an instance manually:
+		 * 
+		 *     $.Model('Person',{
+		 *       model : function(data){
+		 *         return new this(data);
+		 *       }
+		 *     },{})
+		 *     
+		 * ## API
+		 * 
+		 * @param {Object} attributes An object of name-value pairs or an object that has a 
+		 *  data, attributes, or 'shortName' property that maps to an object of name-value pairs.
+		 * @return {Model} an instance of the model
+		 */
+		model: function( attributes ) {
+			if (!attributes ) {
+				return null;
+			}
+			return new this(
+				// checks for properties in an object (like rails 2.0 gives);
+				isObject(attributes[this._shortName]) ||
+				isObject(attributes.data) || 
+				isObject(attributes.attributes) || 
+				attributes);
+		},
+		/**
+		 * @function wrapMany
+		 * @hide
+		 * @tag deprecated
+		 * 
+		 * __warning__ : wrapMany is deprecated in favor of [jQuery.Model.static.models].  They 
+		 * provide the same functionality; however, models works better with Deferreds.
+		 * 
+		 * $.Model.wrapMany converts a raw array of JavaScript Objects into an array (or [jQuery.Model.List $.Model.List]) of model instances.
+		 * 
+		 *     // a Recipe Model wi
+		 *     $.Model("Recipe",{
+		 *       squareId : function(){
+		 *         return this.id*this.id;
+		 *       }
+		 *     })
+		 * 
+		 *     var recipes = Recipe.wrapMany([{id: 1},{id: 2}])
+		 *     recipes[0].squareId() //-> 1
+		 * 
+		 * If an array is not passed to wrapMany, it will look in the object's .data
+		 * property.  
+		 * 
+		 * For example:
+		 * 
+		 *     var recipes = Recipe.wrapMany({data: [{id: 1},{id: 2}]})
+		 *     recipes[0].squareId() //-> 1
+		 * 
+		 * 
+		 * Often wrapMany is used with this.callback inside a model's [jQuery.Model.static.findAll findAll]
+		 * method like:
+		 * 
+		 *     findAll : function(params, success, error){
+		 *       $.get('/url',
+		 *             params,
+		 *             this.callback(['wrapMany',success]), 'json' )
+		 *     }
+		 * 
+		 * If you are having problems getting your model to callback success correctly,
+		 * make sure a request is being made (with firebug's net tab).  Also, you 
+		 * might not use this.callback and instead do:
+		 * 
+		 *     findAll : function(params, success, error){
+		 *       self = this;
+		 *       $.get('/url',
+		 *             params,
+		 *             function(data){
+		 *               var wrapped = self.wrapMany(data);
+		 *               success(wrapped)
+		 *             },
+		 *             'json')
+		 *     }
+		 * 
+		 * ## API
+		 * 
+		 * @param {Array} instancesRawData an array of raw name - value pairs like
+		 * 
+		 *     [{name: "foo", id: 4},{name: "bar", id: 5}]
+		 *     
+		 * @return {Array} a JavaScript array of instances or a [jQuery.Model.List list] of instances
+		 *  if the model list plugin has been included.
+		 */
+		// wrapMany placeholder
+		/**
+		 * $.Model.models is used as a [http://api.jquery.com/extending-ajax/#Converters Ajax converter] 
+		 * to convert the response of a [jQuery.Model.static.findAll] request 
+		 * into an array (or [jQuery.Model.List $.Model.List]) of model instances.  
+		 * 
+		 * You will never call this method directly.  Instead, you tell $.ajax about it in findAll:
+		 * 
+		 *     $.Model('Recipe',{
+		 *       findAll : function(params, success, error ){
+		 *         return $.ajax({
+		 *           url: '/services/recipes.json',
+		 *           type: 'get',
+		 *           data: params
+		 *           
+		 *           dataType : 'json recipe.models' //LOOK HERE!
+		 *         });
+		 *       }
+		 *     },{})
+		 * 
+		 * This makes the result of findAll a [http://api.jquery.com/category/deferred-object/ $.Deferred]
+		 * that resolves to a list of model instances:
+		 * 
+		 *     var deferredRecipes = Recipe.findAll({});
+		 *     
+		 *     deferredRecipes.then(function(recipes){
+		 *       console.log('I have '+recipes.length+'recipes.');
+		 *     })
+		 * 
+		 * ## Non-standard Services
+		 * 
+		 * $.jQuery.models expects data to be an array of name-value pairs like:
+		 * 
+		 *     [{id: 1, name : "justin"},{id:2, name: "brian"}, ...]
+		 *     
+		 * It can also take an object with additional data about the array like:
+		 * 
+		 *     {
+		 *       count: 15000 //how many total items there might be
+		 *       data: [{id: 1, name : "justin"},{id:2, name: "brian"}, ...]
+		 *     }
+		 * 
+		 * In this case, models will return an array of instances found in 
+		 * data, but with additional properties as expandos on the array:
+		 * 
+		 *     var people = Person.models({
+		 *       count : 1500,
+		 *       data : [{id: 1, name: 'justin'}, ...]
+		 *     })
+		 *     people[0].name // -> justin
+		 *     people.count // -> 1500
+		 * 
+		 * ### Overwriting Models
+		 * 
+		 * If your service returns data like:
+		 * 
+		 *     {ballers: [{name: "justin", id: 5}]}
+		 * 
+		 * You will want to overwrite models to pass the base models what it expects like:
+		 * 
+		 *     $.Model('Person',{
+		 *       models : function(data){
+		 *         this._super(data.ballers);
+		 *       }
+		 *     },{})
+		 * 
+		 * @param {Array} instancesRawData an array of raw name - value pairs.
+		 * @return {Array} a JavaScript array of instances or a [jQuery.Model.List list] of instances
+		 *  if the model list plugin has been included.
+		 */
+		models: function( instancesRawData ) {
+			if (!instancesRawData ) {
+				return null;
+			}
+			var res = getList(this.List),
+				arr = isArray(instancesRawData),
+				raw = arr ? instancesRawData : instancesRawData.data,
+				length = raw.length,
+				i = 0;
+			//@steal-remove-start
+			if (! length ) {
+				steal.dev.warn("model.js models has no data.  If you have one item, use model")
+			}
+			//@steal-remove-end
+			res._use_call = true; //so we don't call next function with all of these
+			for (; i < length; i++ ) {
+				res.push(this.model(raw[i]));
+			}
+			if (!arr ) { //push other stuff onto array
+				for ( var prop in instancesRawData ) {
+					if ( prop !== 'data' ) {
+						res[prop] = instancesRawData[prop];
+					}
+
+				}
+			}
+			return res;
+		},
+		/**
+		 * The name of the id field.  Defaults to 'id'. Change this if it is something different.
+		 * 
+		 * For example, it's common in .NET to use Id.  Your model might look like:
+		 * 
+		 * @codestart
+		 * $.Model("Friends",{
+		 *   id: "Id"
+		 * },{});
+		 * @codeend
+		 */
+		id: 'id',
+		//if null, maybe treat as an array?
+		/**
+		 * Adds an attribute to the list of attributes for this class.
+		 * @hide
+		 * @param {String} property
+		 * @param {String} type
+		 */
+		addAttr: function( property, type ) {
+			var stub;
+
+			if ( this.associations[property] ) {
+				return;
+			}
+			
+			stub = this.attributes[property] || (this.attributes[property] = type);
+			return type;
+		},
+		// a collection of all models
+		_models: {},
+		/**
+		 * If OpenAjax is available,
+		 * publishes to OpenAjax.hub.  Always adds the shortName.event.
+		 * 
+		 * @codestart
+		 * // publishes contact.completed
+		 * Namespace.Contact.publish("completed",contact);
+		 * @codeend
+		 * 
+		 * @param {String} event The event name to publish
+		 * @param {Object} data The data to publish
+		 */
+		publish: function( event, data ) {
+			//@steal-remove-start
+			steal.dev.log("Model.js - publishing " + this._shortName + "." + event);
+			//@steal-remove-end
+			if ( window.OpenAjax ) {
+				OpenAjax.hub.publish(this._shortName + "." + event, data);
+			}
+
+		},
+		guessType : function(){
+			return "string"
+		},
+		/**
+		 * @attribute convert
+		 * @type Object
+		 * An object of name-function pairs that are used to convert attributes.
+		 * Check out [jQuery.Model.static.attributes] or 
+		 * [jquery.model.typeconversion type conversion]
+		 * for examples.
+		 */
+		convert: {
+			"date": function( str ) {
+				return typeof str === "string" ? (isNaN(Date.parse(str)) ? null : Date.parse(str)) : str;
+			},
+			"number": function( val ) {
+				return parseFloat(val);
+			},
+			"boolean": function( val ) {
+				return Boolean(val);
+			}
+		},
+		bind: bind,
+		unbind: unbind
+	},
+	/**
+	 * @Prototype
+	 */
+	{
+		/**
+		 * Setup is called when a new model instance is created.
+		 * It adds default attributes, then whatever attributes
+		 * are passed to the class.
+		 * Setup should never be called directly.
+		 * 
+		 * @codestart
+		 * $.Model("Recipe")
+		 * var recipe = new Recipe({foo: "bar"});
+		 * recipe.foo //-> "bar"
+		 * recipe.attr("foo") //-> "bar"
+		 * @codeend
+		 * 
+		 * @param {Object} attributes a hash of attributes
+		 */
+		setup: function( attributes ) {
+			// so we know not to fire events
+			this._init = true;
+			this.attrs(extend({},this.Class.defaults,attributes));
+			delete this._init;
+		},
+		/**
+		 * Sets the attributes on this instance and calls save.
+		 * The instance needs to have an id.  It will use
+		 * the instance class's [jQuery.Model.static.update update]
+		 * method.
+		 * 
+		 * @codestart
+		 * recipe.update({name: "chicken"}, success, error);
+		 * @codeend
+		 * 
+		 * If OpenAjax.hub is available, the model will also
+		 * publish a "<i>modelName</i>.updated" message with
+		 * the updated instance.
+		 * 
+		 * @param {Object} attrs the model's attributes
+		 * @param {Function} success called if a successful update
+		 * @param {Function} error called if there's an error
+		 */
+		update: function( attrs, success, error ) {
+			this.attrs(attrs);
+			return this.save(success, error); //on success, we should 
+		},
+		/**
+		 * Runs the validations on this model.  You can
+		 * also pass it an array of attributes to run only those attributes.
+		 * It returns nothing if there are no errors, or an object
+		 * of errors by attribute.
+		 * 
+		 * To use validations, it's suggested you use the 
+		 * model/validations plugin.
+		 * 
+		 * @codestart
+		 * $.Model("Task",{
+		 *   init : function(){
+		 *     this.validatePresenceOf("dueDate")
+		 *   }
+		 * },{});
+		 * 
+		 * var task = new Task(),
+		 *     errors = task.errors()
+		 * 
+		 * errors.dueDate[0] //-> "can't be empty"
+		 * @codeend
+		 */
+		errors: function( attrs ) {
+			if ( attrs ) {
+				attrs = isArray(attrs) ? attrs : makeArray(arguments);
+			}
+			var errors = {},
+				self = this,
+				addErrors = function( attr, funcs ) {
+					each(funcs, function( i, func ) {
+						var res = func.call(self);
+						if ( res ) {
+							if (!errors.hasOwnProperty(attr) ) {
+								errors[attr] = [];
+							}
+
+							errors[attr].push(res);
+						}
+
+					});
+				};
+
+			each(attrs || this.Class.validations || {}, function( attr, funcs ) {
+				if ( typeof attr == 'number' ) {
+					attr = funcs;
+					funcs = self.Class.validations[attr];
+				}
+				addErrors(attr, funcs || []);
+			});
+
+			for ( var attr in errors ) {
+				if ( errors.hasOwnProperty(attr) ) {
+					return errors;
+				}
+			}
+			return null;
+		},
+		/**
+		 * Gets or sets an attribute on the model using setters and 
+		 * getters if available.
+		 * 
+		 * @codestart
+		 * $.Model("Recipe")
+		 * var recipe = new Recipe();
+		 * recipe.attr("foo","bar")
+		 * recipe.foo //-> "bar"
+		 * recipe.attr("foo") //-> "bar"
+		 * @codeend
+		 * 
+		 * ## Setters
+		 * 
+		 * If you add a set<i>AttributeName</i> method on your model,
+		 * it will be used to set the value.  The set method is called
+		 * with the value and is expected to return the converted value.
+		 * 
+		 * @codestart
+		 * $.Model("Recipe",{
+		 *   setCreatedAt : function(raw){
+		 *     return Date.parse(raw)
+		 *   }
+		 * })
+		 * var recipe = new Recipe();
+		 * recipe.attr("createdAt","Dec 25, 1995")
+		 * recipe.createAt //-> Date
+		 * @codeend
+		 * 
+		 * ## Asynchronous Setters
+		 * 
+		 * Sometimes, you want to perform an ajax request when 
+		 * you set a property.  You can do this with setters too.
+		 * 
+		 * To do this, your setter should return undefined and
+		 * call success with the converted value.  For example:
+		 * 
+		 * @codestart
+		 * $.Model("Recipe",{
+		 *   setTitle : function(title, success, error){
+		 *     $.post(
+		 *       "recipe/update/"+this.id+"/title",
+		 *       title,
+		 *       function(){
+		 *         success(title);
+		 *       },
+		 *       "json")
+		 *   }
+		 * })
+		 * 
+		 * recipe.attr("title","fish")
+		 * @codeend
+		 * 
+		 * ## Events
+		 * 
+		 * When you use attr, it can also trigger events.  This is
+		 * covered in [jQuery.Model.prototype.bind].
+		 * 
+		 * @param {String} attribute the attribute you want to set or get
+		 * @param {String|Number|Boolean} [value] value the value you want to set.
+		 * @param {Function} [success] an optional success callback.  
+		 *    This gets called if the attribute was successful.
+		 * @param {Function} [error] an optional success callback.  
+		 *    The error function is called with validation errors.
+		 */
+		attr: function( attribute, value, success, error ) {
+			var cap = classize(attribute),
+				get = "get" + cap;
+			if ( value !== undefined ) {
+				this._setProperty(attribute, value, success, error, cap);
+				return this;
+			}
+			return this[get] ? this[get]() : this[attribute];
+		},
+		/**
+		 * Binds to events on this model instance.  Typically 
+		 * you'll bind to an attribute name.  Handler will be called
+		 * every time the attribute value changes.  For example:
+		 * 
+		 * @codestart
+		 * $.Model("School")
+		 * var school = new School();
+		 * school.bind("address", function(ev, address){
+		 *   alert('address changed to '+address);
+		 * })
+		 * school.attr("address","1124 Park St");
+		 * @codeend
+		 * 
+		 * You can also bind to attribute errors.
+		 * 
+		 * @codestart
+		 * $.Model("School",{
+		 *   setName : function(name, success, error){
+		 *     if(!name){
+		 *        error("no name");
+		 *     }
+		 *     return error;
+		 *   }
+		 * })
+		 * var school = new School();
+		 * school.bind("error.name", function(ev, mess){
+		 *    mess // -> "no name";
+		 * })
+		 * school.attr("name","");
+		 * @codeend
+		 * 
+		 * You can also bind to created, updated, and destroyed events.
+		 * 
+		 * @param {String} eventType the name of the event.
+		 * @param {Function} handler a function to call back when an event happens on this model.
+		 * @return {model} the model instance for chaining
+		 */
+		bind: bind,
+		/**
+		 * Unbinds an event handler from this instance.
+		 * Read [jQuery.Model.prototype.bind] for 
+		 * more information.
+		 * @param {String} eventType
+		 * @param {Function} handler
+		 */
+		unbind: unbind,
+		/**
+		 * Checks if there is a set_<i>property</i> value.  If it returns true, lets it handle; otherwise
+		 * saves it.
+		 * @hide
+		 * @param {Object} property
+		 * @param {Object} value
+		 */
+		_setProperty: function( property, value, success, error, capitalized ) {
+			// the potential setter name
+			var setName = "set" + capitalized,
+				//the old value
+				old = this[property],
+				self = this,
+				errorCallback = function( errors ) {
+					var stub;
+					stub = error && error.call(self, errors);
+					$(self).triggerHandler("error." + property, errors);
+				};
+
+			// provides getter / setters
+			// 
+			if ( this[setName] && 
+				(value = this[setName](value, this.callback('_updateProperty', property, value, old, success, errorCallback), errorCallback)) === undefined ) {
+				return;
+			}
+			this._updateProperty(property, value, old, success, errorCallback);
+		},
+		/**
+		 * Triggers events when a property has been updated
+		 * @hide
+		 * @param {Object} property
+		 * @param {Object} value
+		 * @param {Object} old
+		 * @param {Object} success
+		 */
+		_updateProperty: function( property, value, old, success, errorCallback ) {
+			var Class = this.Class,
+				val, type = Class.attributes[property] || Class.addAttr(property, Class.guessType(value)),
+				//the converter
+				converter = Class.convert[type],
+				errors = null,
+				stub;
+
+			val = this[property] = (value === null ? //if the value is null or undefined
+			null : // it should be null
+			(converter ? converter.call(Class, value) : //convert it to something useful
+			value)); //just return it
+			//validate (only if not initializing, this is for performance)
+			if (!this._init ) {
+				errors = this.errors(property);
+			}
+
+			if ( errors ) {
+				//get an array of errors
+				errorCallback(errors);
+			} else {
+				if ( old !== val && !this._init ) {
+					$(this).triggerHandler(property, [val]);
+					$(this).triggerHandler("updated.attr", [property,val, old]); // this is for 3.1
+				}
+				stub = success && success(this);
+
+			}
+
+			//if this class has a global list, add / remove from the list.
+			if ( property === Class.id && val !== null && Class.list ) {
+				// if we didn't have an old id, add ourselves
+				if (!old ) {
+					Class.list.push(this);
+				} else if ( old != val ) {
+					// if our id has changed ... well this should be ok
+					Class.list.remove(old);
+					Class.list.push(this);
+				}
+			}
+
+		},
+		/**
+		 * Gets or sets a list of attributes. 
+		 * Each attribute is set with [jQuery.Model.prototype.attr attr].
+		 * 
+		 * @codestart
+		 * recipe.attrs({
+		 *   name: "ice water",
+		 *   instructions : "put water in a glass"
+		 * })
+		 * @codeend
+		 * 
+		 * This can be used nicely with [jquery.model.events].
+		 * 
+		 * @param {Object} [attributes]  if present, the list of attributes to send
+		 * @return {Object} the current attributes of the model
+		 */
+		attrs: function( attributes ) {
+			var key;
+			if (!attributes ) {
+				attributes = {};
+				for ( key in this.Class.attributes ) {
+					if ( this.Class.attributes.hasOwnProperty(key) ) {
+						attributes[key] = this.attr(key);
+					}
+				}
+			} else {
+				var idName = this.Class.id;
+				//always set the id last
+				for ( key in attributes ) {
+					if ( key != idName ) {
+						this.attr(key, attributes[key]);
+					}
+				}
+				if ( idName in attributes ) {
+					this.attr(idName, attributes[idName]);
+				}
+
+			}
+			return attributes;
+		},
+		/**
+		 * Returns if the instance is a new object.  This is essentially if the
+		 * id is null or undefined.
+		 * 
+		 *     new Recipe({id: 1}).isNew() //-> false
+		 * @return {Boolean} false if an id is set, true if otherwise.
+		 */
+		isNew: function() {
+			var id = getId(this);
+			return (id === undefined || id === null); //if null or undefined
+		},
+		/**
+		 * Saves the instance if there are no errors.  
+		 * If the instance is new, [jQuery.Model.static.create] is
+		 * called; otherwise, [jQuery.Model.static.update] is
+		 * called.
+		 * 
+		 * @codestart
+		 * recipe.save(success, error);
+		 * @codeend
+		 * 
+		 * If OpenAjax.hub is available, after a successful create or update, 
+		 * "<i>modelName</i>.created" or "<i>modelName</i>.updated" is published.
+		 * 
+		 * @param {Function} [success] called if a successful save.
+		 * @param {Function} [error] called if the save was not successful.
+		 */
+		save: function( success, error ) {
+			return makeRequest(this, this.isNew()  ? 'create' : 'update' , success, error);
+		},
+
+		/**
+		 * Destroys the instance by calling 
+		 * [jQuery.Model.static.destroy] with the id of the instance.
+		 * 
+		 * @codestart
+		 * recipe.destroy(success, error);
+		 * @codeend
+		 * 
+		 * If OpenAjax.hub is available, after a successful
+		 * destroy "<i>modelName</i>.destroyed" is published
+		 * with the model instance.
+		 * 
+		 * @param {Function} [success] called if a successful destroy
+		 * @param {Function} [error] called if an unsuccessful destroy
+		 */
+		destroy: function( success, error ) {
+			return makeRequest(this, 'destroy' , success, error , 'destroyed');
+		},
+		
+
+		/**
+		 * Returns a unique identifier for the model instance.  For example:
+		 * @codestart
+		 * new Todo({id: 5}).identity() //-> 'todo_5'
+		 * @codeend
+		 * Typically this is used in an element's shortName property so you can find all elements
+		 * for a model with [jQuery.Model.prototype.elements elements].
+		 * @return {String}
+		 */
+		identity: function() {
+			var id = getId(this);
+			return this.Class._fullName + '_' + (this.Class.escapeIdentity ? encodeURIComponent(id) : id);
+		},
+		/**
+		 * Returns elements that represent this model instance.  For this to work, your element's should
+		 * us the [jQuery.Model.prototype.identity identity] function in their class name.  Example:
+		 * 
+		 *     <div class='todo <%= todo.identity() %>'> ... </div>
+		 * 
+		 * This also works if you hooked up the model:
+		 * 
+		 *     <div <%= todo %>> ... </div>
+		 *     
+		 * Typically, you'll use this as a response of an OpenAjax message:
+		 * 
+		 *     "todo.destroyed subscribe": function(called, todo){
+		 *       todo.elements(this.element).remove();
+		 *     }
+		 * 
+		 * ## API
+		 * 
+		 * @param {String|jQuery|element} context If provided, only elements inside this element
+		 * that represent this model will be returned.
+		 * 
+		 * @return {jQuery} Returns a jQuery wrapped nodelist of elements that have this model instances
+		 *  identity in their class name.
+		 */
+		elements: function( context ) {
+			return $("." + this.identity(), context);
+		},
+		/**
+		 * Publishes to OpenAjax.hub
+		 * 
+		 *     $.Model('Task', {
+		 *       complete : function(cb){
+		 *         var self = this;
+		 *         $.post('/task/'+this.id,
+		 *           {complete : true},
+		 *           function(){
+		 *             self.attr('completed', true);
+		 *             self.publish('completed');
+		 *           })
+		 *       }
+		 *     })
+		 *     
+		 *     
+		 * @param {String} event The event type.  The model's short name will be automatically prefixed.
+		 * @param {Object} [data] if missing, uses the instance in {data: this}
+		 */
+		publish: function( event, data ) {
+			this.Class.publish(event, data || this);
+		},
+		hookup: function( el ) {
+			var shortName = this.Class._shortName,
+				models = $.data(el, "models") || $.data(el, "models", {});
+			$(el).addClass(shortName + " " + this.identity());
+			models[shortName] = this;
+		}
+	});
+	// map wrapMany
+	$.Model.wrapMany = $.Model.models;
+	$.Model.wrap = $.Model.model;
+
+
+	each([
+	/**
+	 * @function created
+	 * @hide
+	 * Called by save after a new instance is created.  Publishes 'created'.
+	 * @param {Object} attrs
+	 */
+	"created",
+	/**
+	 * @function updated
+	 * @hide
+	 * Called by save after an instance is updated.  Publishes 'updated'.
+	 * @param {Object} attrs
+	 */
+	"updated",
+	/**
+	 * @function destroyed
+	 * @hide
+	 * Called after an instance is destroyed.  
+	 *   - Publishes "shortName.destroyed".
+	 *   - Triggers a "destroyed" event on this model.
+	 *   - Removes the model from the global list if its used.
+	 * 
+	 */
+	"destroyed"], function( i, funcName ) {
+		$.Model.prototype[funcName] = function( attrs ) {
+			var stub;
+
+			if ( funcName === 'destroyed' && this.Class.list ) {
+				this.Class.list.remove(getId(this));
+			}
+			stub = attrs && typeof attrs == 'object' && this.attrs(attrs.attrs ? attrs.attrs() : attrs);
+			$(this).triggerHandler(funcName);
+			this.publish(funcName, this);
+			$([this.Class]).triggerHandler(funcName, this);
+			return [this].concat(makeArray(arguments)); // return like this for this.callback chains
+		};
+	});
+
+	/**
+	 *  @add jQuery.fn
+	 */
+	// break
+	/**
+	 * @function models
+	 * Returns a list of models.  If the models are of the same
+	 * type, and have a [jQuery.Model.List], it will return 
+	 * the models wrapped with the list.
+	 * 
+	 * @codestart
+	 * $(".recipes").models() //-> [recipe, ...]
+	 * @codeend
+	 * 
+	 * @param {jQuery.Class} [type] if present only returns models of the provided type.
+	 * @return {Array|jQuery.Model.List} returns an array of model instances that are represented by the contained elements.
+	 */
+	$.fn.models = function( type ) {
+		//get it from the data
+		var collection = [],
+			kind, ret, retType;
+		this.each(function() {
+			each($.data(this, "models") || {}, function( name, instance ) {
+				//either null or the list type shared by all classes
+				kind = kind === undefined ? 
+					instance.Class.List || null : 
+					(instance.Class.List === kind ? kind : null);
+				collection.push(instance);
+			});
+		});
+
+		ret = getList(kind);
+
+		ret.push.apply(ret, unique(collection));
+		return ret;
+	};
+	/**
+	 * @function model
+	 * 
+	 * Returns the first model instance found from [jQuery.fn.models] or
+	 * sets the model instance on an element.
+	 * 
+	 *     //gets an instance
+	 *     ".edit click" : function(el) {
+	 *       el.closest('.todo').model().destroy()
+	 *     },
+	 *     // sets an instance
+	 *     list : function(items){
+	 *        var el = this.element;
+	 *        $.each(item, function(item){
+	 *          $('<div/>').model(item)
+	 *            .appendTo(el)
+	 *        })
+	 *     }
+	 * 
+	 * @param {Object} [type] The type of model to return.  If a model instance is provided
+	 * it will add the model to the element.
+	 */
+	$.fn.model = function( type ) {
+		if ( type && type instanceof $.Model ) {
+			type.hookup(this[0]);
+			return this;
+		} else {
+			return this.models.apply(this, arguments)[0];
+		}
+
+	};
+	/**
+	 * @page jquery.model.services Service APIs
+	 * @parent jQuery.Model
+	 * 
+	 * Models provide an abstract API for connecting to your Services.  
+	 * By implementing static:
+	 * 
+	 *  - [jQuery.Model.static.findAll] 
+	 *  - [jQuery.Model.static.findOne] 
+	 *  - [jQuery.Model.static.create] 
+	 *  - [jQuery.Model.static.update] 
+	 *  - [jQuery.Model.static.destroy]
+	 *  
+	 * You can find more details on how to implement each method.
+	 * Typically, you can just use templated service urls. But if you need to
+	 * implement these methods yourself, the following
+	 * is a useful quick reference:
+	 * 
+	 * ### create(attrs, success([attrs]), error()) -> deferred
+	 *  
+	 *  - <code>attrs</code> - an Object of attribute / value pairs
+	 *  - <code>success([attrs])</code> - Create calls success when the request has completed 
+	 *    successfully.  Success can be called back with an object that represents
+	 *    additional properties that will be set on the instance. For example, the server might 
+	 *    send back an updatedAt date.
+	 *  - <code>error</code> - Create should callback error if an error happens during the request
+	 *  - <code>deferred</code> - A deferred that gets resolved to any additional attrs
+	 *    that might need to be set on the model instance.
+	 * 
+	 * 
+	 * ### findAll( params, success(items), error) -> deferred
+	 * 
+	 * 
+	 *  - <code>params</code> - an Object that filters the items returned
+	 *  - <code>success(items)</code> - success should be called with an Array of Model instances.
+	 *  - <code>error</code> - called if an error happens during the request
+	 *  - <code>deferred</code> - A deferred that gets resolved to the list of items
+	 *          
+	 * ### findOne(params, success(items), error) -> deferred
+	 *          
+	 *  - <code>params</code> - an Object that filters the item returned
+	 *  - <code>success(item)</code> - success should be called with a model instance.
+	 *  - <code>error</code> - called if an error happens during the request
+	 *  - <code>deferred</code> - A deferred that gets resolved to a model instance
+	 *        
+	 * ### update(id, attrs, success([attrs]), error()) -> deferred
+	 *  
+	 *  - <code>id</code> - the id of the instance you are updating
+	 *  - <code>attrs</code> - an Object of attribute / value pairs
+	 *  - <code>success([attrs])</code> - Call success when the request has completed 
+	 *    successfully.  Success can be called back with an object that represents
+	 *    additional properties that will be set on the instance. For example, the server might 
+	 *    send back an updatedAt date.
+	 *  - <code>error</code> - Callback error if an error happens during the request
+	 *  - <code>deferred</code> - A deferred that gets resolved to any additional attrs
+	 *      that might need to be set on the model instance.
+	 *     
+	 * ### destroy(id, success([attrs]), error()) -> deferred
+	 *  
+	 *  - <code>id</code> - the id of the instance you are destroying
+	 *  - <code>success([attrs])</code> - Calls success when the request has completed 
+	 *      successfully.  Success can be called back with an object that represents
+	 *      additional properties that will be set on the instance. 
+	 *  - <code>error</code> - Create should callback error if an error happens during the request
+	 *  - <code>deferred</code> - A deferred that gets resolved to any additional attrs
+	 *      that might need to be set on the model instance.
+	 */
+});

Added: openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/view/ejs/ejs.js
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/view/ejs/ejs.js?rev=1149378&view=auto
==============================================================================
--- openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/view/ejs/ejs.js (added)
+++ openejb/trunk/openejb3/examples/webapps/rest-example/src/main/webapp/jquery/view/ejs/ejs.js Thu Jul 21 21:42:07 2011
@@ -0,0 +1,523 @@
+/*jslint evil: true */
+
+
+
+steal.plugins('jquery/view', 'jquery/lang/rsplit').then(function( $ ) {
+	var myEval = function(script){
+			eval(script);
+		},
+		chop = function( string ) {
+			return string.substr(0, string.length - 1);
+		},
+		rSplit = $.String.rsplit,
+		extend = $.extend,
+		isArray = $.isArray,
+		clean = function( content ) {
+				return content.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/"/g, '\\"');
+		}
+		// from prototype  http://www.prototypejs.org/
+		escapeHTML = function(content){
+			return content.replace(/&/g,'&amp;')
+					.replace(/</g,'&lt;')
+					.replace(/>/g,'&gt;')
+					.replace(/"/g, '&#34;')
+					.replace(/'/g, "&#39;");
+		},
+		EJS = function( options ) {
+			//returns a renderer function
+			if ( this.constructor != EJS ) {
+				var ejs = new EJS(options);
+				return function( data, helpers ) {
+					return ejs.render(data, helpers);
+				};
+			}
+			//so we can set the processor
+			if ( typeof options == "function" ) {
+				this.template = {};
+				this.template.process = options;
+				return;
+			}
+			//set options on self
+			extend(this, EJS.options, options);
+			this.template = compile(this.text, this.type, this.name);
+		};
+	/**
+	 * @class jQuery.EJS
+	 * 
+	 * @plugin jquery/view/ejs
+	 * @parent jQuery.View
+	 * @download  http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/view/ejs/ejs.js
+	 * @test jquery/view/ejs/qunit.html
+	 * 
+	 * 
+	 * Ejs provides <a href="http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/">ERB</a> 
+	 * style client side templates.  Use them with controllers to easily build html and inject
+	 * it into the DOM.
+	 * 
+	 * ###  Example
+	 * 
+	 * The following generates a list of tasks:
+	 * 
+	 * @codestart html
+	 * &lt;ul>
+	 * &lt;% for(var i = 0; i < tasks.length; i++){ %>
+	 *     &lt;li class="task &lt;%= tasks[i].identity %>">&lt;%= tasks[i].name %>&lt;/li>
+	 * &lt;% } %>
+	 * &lt;/ul>
+	 * @codeend
+	 * 
+	 * For the following examples, we assume this view is in <i>'views\tasks\list.ejs'</i>.
+	 * 
+	 * 
+	 * ## Use
+	 * 
+	 * ### Loading and Rendering EJS:
+	 * 
+	 * You should use EJS through the helper functions [jQuery.View] provides such as:
+	 * 
+	 *   - [jQuery.fn.after after]
+	 *   - [jQuery.fn.append append]
+	 *   - [jQuery.fn.before before]
+	 *   - [jQuery.fn.html html], 
+	 *   - [jQuery.fn.prepend prepend],
+	 *   - [jQuery.fn.replaceWith replaceWith], and 
+	 *   - [jQuery.fn.text text].
+	 * 
+	 * or [jQuery.Controller.prototype.view].
+	 * 
+	 * ### Syntax
+	 * 
+	 * EJS uses 5 types of tags:
+	 * 
+	 *   - <code>&lt;% CODE %&gt;</code> - Runs JS Code.
+	 *     For example:
+	 *     
+	 *         <% alert('hello world') %>
+	 *     
+	 *   - <code>&lt;%= CODE %&gt;</code> - Runs JS Code and writes the result into the result of the template.
+	 *     For example:
+	 *     
+	 *         <h1><%= 'hello world' %></h1>
+	 *        
+	 *   - <code>&lt;%~ CODE %&gt;</code> - Runs JS Code and writes the _escaped_ result into the result of the template.
+	 *     For example:
+	 *     
+	 *         <%~ 'hello world' %>
+	 *         
+	 *   - <code>&lt;%%= CODE %&gt;</code> - Writes <%= CODE %> to the result of the template.  This is very useful for generators.
+	 *     
+	 *         <%%= 'hello world' %>
+	 *         
+	 *   - <code>&lt;%# CODE %&gt;</code> - Used for comments.  This does nothing.
+	 *     
+	 *         <%# 'hello world' %>
+	 *        
+	 * ## Hooking up controllers
+	 * 
+	 * After drawing some html, you often want to add other widgets and plugins inside that html.
+	 * View makes this easy.  You just have to return the Contoller class you want to be hooked up.
+	 * 
+	 * @codestart
+	 * &lt;ul &lt;%= Mxui.Tabs%>>...&lt;ul>
+	 * @codeend
+	 * 
+	 * You can even hook up multiple controllers:
+	 * 
+	 * @codestart
+	 * &lt;ul &lt;%= [Mxui.Tabs, Mxui.Filler]%>>...&lt;ul>
+	 * @codeend
+	 * 
+	 * <h2>View Helpers</h2>
+	 * View Helpers return html code.  View by default only comes with 
+	 * [jQuery.EJS.Helpers.prototype.view view] and [jQuery.EJS.Helpers.prototype.text text].
+	 * You can include more with the view/helpers plugin.  But, you can easily make your own!
+	 * Learn how in the [jQuery.EJS.Helpers Helpers] page.
+	 * 
+	 * @constructor Creates a new view
+	 * @param {Object} options A hash with the following options
+	 * <table class="options">
+	 *     <tbody><tr><th>Option</th><th>Default</th><th>Description</th></tr>
+	 *     <tr>
+	 *      <td>url</td>
+	 *      <td>&nbsp;</td>
+	 *      <td>loads the template from a file.  This path should be relative to <i>[jQuery.root]</i>.
+	 *      </td>
+	 *     </tr>
+	 *     <tr>
+	 *      <td>text</td>
+	 *      <td>&nbsp;</td>
+	 *      <td>uses the provided text as the template. Example:<br/><code>new View({text: '&lt;%=user%>'})</code>
+	 *      </td>
+	 *     </tr>
+	 *     <tr>
+	 *      <td>element</td>
+	 *      <td>&nbsp;</td>
+	 *      <td>loads a template from the innerHTML or value of the element.
+	 *      </td>
+	 *     </tr>
+	 *     <tr>
+	 *      <td>type</td>
+	 *      <td>'<'</td>
+	 *      <td>type of magic tags.  Options are '&lt;' or '['
+	 *      </td>
+	 *     </tr>
+	 *     <tr>
+	 *      <td>name</td>
+	 *      <td>the element ID or url </td>
+	 *      <td>an optional name that is used for caching.
+	 *      </td>
+	 *     </tr>
+	 *     <tr>
+	 *      <td>cache</td>
+	 *      <td>true in production mode, false in other modes</td>
+	 *      <td>true to cache template.
+	 *      </td>
+	 *     </tr>
+	 *     
+	 *    </tbody></table>
+	 */
+	$.EJS = EJS;
+	/** 
+	 * @Prototype
+	 */
+	EJS.prototype = {
+		constructor: EJS,
+		/**
+		 * Renders an object with extra view helpers attached to the view.
+		 * @param {Object} object data to be rendered
+		 * @param {Object} extra_helpers an object with additonal view helpers
+		 * @return {String} returns the result of the string
+		 */
+		render: function( object, extraHelpers ) {
+			object = object || {};
+			this._extra_helpers = extraHelpers;
+			var v = new EJS.Helpers(object, extraHelpers || {});
+			return this.template.process.call(object, object, v);
+		}
+	};
+	/* @Static */
+
+
+	EJS.
+	/**
+	 * Used to convert what's in &lt;%= %> magic tags to a string
+	 * to be inserted in the rendered output.
+	 * 
+	 * Typically, it's a string, and the string is just inserted.  However,
+	 * if it's a function or an object with a hookup method, it can potentially be 
+	 * be ran on the element after it's inserted into the page.
+	 * 
+	 * This is a very nice way of adding functionality through the view.
+	 * Usually this is done with [jQuery.EJS.Helpers.prototype.plugin]
+	 * but the following fades in the div element after it has been inserted:
+	 * 
+	 * @codestart
+	 * &lt;%= function(el){$(el).fadeIn()} %>
+	 * @codeend
+	 * 
+	 * @param {String|Object|Function} input the value in between the
+	 * write majic tags: &lt;%= %>
+	 * @return {String} returns the content to be added to the rendered
+	 * output.  The content is different depending on the type:
+	 * 
+	 *   * string - a bac
+	 *   * foo - bar
+	 */
+	text = function( input ) {
+		if ( typeof input == 'string' ) {
+			return input;
+		}
+		if ( input === null || input === undefined ) {
+			return '';
+		}
+		var hook = 
+			(input.hookup && function( el, id ) {
+				input.hookup.call(input, el, id);
+			}) 
+			||
+			(typeof input == 'function' && input)
+			||
+			(isArray(input) && function( el, id ) {
+				for ( var i = 0; i < input.length; i++ ) {
+					var stub;
+					stub = input[i].hookup ? input[i].hookup(el, id) : input[i](el, id);
+				}
+			});
+		if(hook){
+			return "data-view-id='" + $.View.hookup(hook) + "'";
+		}
+		return input.toString ? input.toString() : "";
+	};
+	EJS.clean = function(text){
+		//return sanatized text
+		if(typeof text == 'string'){
+			return escapeHTML(text)
+		}else{
+			return "";
+		}
+	}
+	//returns something you can call scan on
+	var scan = function(scanner, source, block ) {
+		var source_split = rSplit(source, /\n/),
+			i=0;
+		for (; i < source_split.length; i++ ) {
+			scanline(scanner,  source_split[i], block);
+		}
+		
+	},
+	scanline= function(scanner,  line, block ) {
+		scanner.lines++;
+		var line_split = rSplit(line, scanner.splitter),
+			token;
+		for ( var i = 0; i < line_split.length; i++ ) {
+			token = line_split[i];
+			if ( token !== null ) {
+				block(token, scanner);
+			}
+		}
+	},
+	makeScanner = function(left, right){
+		var scanner = {};
+		extend(scanner, {
+			left: left + '%',
+			right: '%' + right,
+			dLeft: left + '%%',
+			dRight: '%%' + right,
+			eeLeft : left + '%==',
+			eLeft: left + '%=',
+			cmnt: left + '%#',
+			cleanLeft: left+"%~",
+			scan : scan,
+			lines : 0
+		});
+		scanner.splitter = new RegExp("(" + [scanner.dLeft, scanner.dRight, scanner.eeLeft, scanner.eLeft, scanner.cleanLeft,
+		scanner.cmnt, scanner.left, scanner.right + '\n', scanner.right, '\n'].join(")|(").
+			replace(/\[/g,"\\[").replace(/\]/g,"\\]") + ")");
+		return scanner;
+	},
+	// compiles a template
+	compile = function( source, left, name ) {
+		source = source.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
+		//normalize line endings
+		left = left || '<';
+		var put_cmd = "___v1ew.push(",
+			insert_cmd = put_cmd,
+			buff = new EJS.Buffer(['var ___v1ew = [];'], []),
+			content = '',
+			put = function( content ) {
+				buff.push(put_cmd, '"', clean(content), '");');
+			},
+			startTag = null,
+			empty = function(){
+				content = ''
+			};
+		
+		scan( makeScanner(left, left === '[' ? ']' : '>') , 
+			source||"", 
+			function( token, scanner ) {
+				// if we don't have a start pair
+				if ( startTag === null ) {
+					switch ( token ) {
+					case '\n':
+						content = content + "\n";
+						put(content);
+						buff.cr();
+						empty();
+						break;
+					case scanner.left:
+					case scanner.eLeft:
+					case scanner.eeLeft:
+					case scanner.cleanLeft:
+					case scanner.cmnt:
+						startTag = token;
+						if ( content.length > 0 ) {
+							put(content);
+						}
+						empty();
+						break;
+
+						// replace <%% with <%
+					case scanner.dLeft:
+						content += scanner.left;
+						break;
+					default:
+						content +=  token;
+						break;
+					}
+				}
+				else {
+					switch ( token ) {
+					case scanner.right:
+						switch ( startTag ) {
+						case scanner.left:
+							if ( content[content.length - 1] == '\n' ) {
+								content = chop(content);
+								buff.push(content, ";");
+								buff.cr();
+							}
+							else {
+								buff.push(content, ";");
+							}
+							break;
+						case scanner.cleanLeft : 
+							buff.push(insert_cmd, "(jQuery.EJS.clean(", content, ")));");
+							break;
+						case scanner.eLeft:
+							buff.push(insert_cmd, "(jQuery.EJS.text(", content, ")));");
+							break;
+						case scanner.eeLeft:
+							buff.push(insert_cmd, "(jQuery.EJS.text(", content, ")));");
+							break;
+						}
+						startTag = null;
+						empty();
+						break;
+					case scanner.dRight:
+						content += scanner.right;
+						break;
+					default:
+						content += token;
+						break;
+					}
+				}
+			})
+		if ( content.length > 0 ) {
+			// Should be content.dump in Ruby
+			buff.push(put_cmd, '"', clean(content) + '");');
+		}
+		var template = buff.close(),
+			out = {
+				out : 'try { with(_VIEW) { with (_CONTEXT) {' + template + " return ___v1ew.join('');}}}catch(e){e.lineNumber=null;throw e;}"
+			};
+		//use eval instead of creating a function, b/c it is easier to debug
+		myEval.call(out,'this.process = (function(_CONTEXT,_VIEW){' + out.out + '});\r\n//@ sourceURL='+name+".js");
+		return out;
+	};
+
+
+	// a line and script buffer
+	// we use this so we know line numbers when there
+	// is an error.  
+	// pre and post are setup and teardown for the buffer
+	EJS.Buffer = function( pre_cmd, post ) {
+		this.line = [];
+		this.script = [];
+		this.post = post;
+
+		// add the pre commands to the first line
+		this.push.apply(this, pre_cmd);
+	};
+	EJS.Buffer.prototype = {
+		//need to maintain your own semi-colons (for performance)
+		push: function() {
+			this.line.push.apply(this.line, arguments);
+		},
+
+		cr: function() {
+			this.script.push(this.line.join(''), "\n");
+			this.line = [];
+		},
+		//returns the script too
+		close: function() {
+			var stub;
+
+			if ( this.line.length > 0 ) {
+				this.script.push(this.line.join(''));
+				this.line = [];
+			}
+
+			stub = this.post.length && this.push.apply(this, this.post);
+
+			this.script.push(";"); //makes sure we always have an ending /
+			return this.script.join("");
+		}
+
+	};
+	
+
+	//type, cache, folder
+	/**
+	 * @attribute options
+	 * Sets default options for all views
+	 * <table class="options">
+	 * <tbody><tr><th>Option</th><th>Default</th><th>Description</th></tr>
+	 * <tr>
+	 * <td>type</td>
+	 * <td>'<'</td>
+	 * <td>type of magic tags.  Options are '&lt;' or '['
+	 * </td>
+	 * </tr>
+	 * <tr>
+	 * <td>cache</td>
+	 * <td>true in production mode, false in other modes</td>
+	 * <td>true to cache template.
+	 * </td>
+	 * </tr>
+	 * </tbody></table>
+	 * 
+	 */
+	EJS.options = {
+		type: '<',
+		ext: '.ejs'
+	};
+
+
+
+
+	/**
+	 * @class jQuery.EJS.Helpers
+	 * @parent jQuery.EJS
+	 * By adding functions to jQuery.EJS.Helpers.prototype, those functions will be available in the 
+	 * views.
+	 * @constructor Creates a view helper.  This function is called internally.  You should never call it.
+	 * @param {Object} data The data passed to the view.  Helpers have access to it through this._data
+	 */
+	EJS.Helpers = function( data, extras ) {
+		this._data = data;
+		this._extras = extras;
+		extend(this, extras);
+	};
+	/* @prototype*/
+	EJS.Helpers.prototype = {
+		/**
+		 * Hooks up a jQuery plugin on.
+		 * @param {String} name the plugin name
+		 */
+		plugin: function( name ) {
+			var args = $.makeArray(arguments),
+				widget = args.shift();
+			return function( el ) {
+				var jq = $(el);
+				jq[widget].apply(jq, args);
+			};
+		},
+		/**
+		 * Renders a partial view.  This is deprecated in favor of <code>$.View()</code>.
+		 */
+		view: function( url, data, helpers ) {
+			helpers = helpers || this._extras;
+			data = data || this._data;
+			return $.View(url, data, helpers); //new EJS(options).render(data, helpers);
+		}
+	};
+
+
+	$.View.register({
+		suffix: "ejs",
+		//returns a function that renders the view
+		script: function( id, src ) {
+			return "jQuery.EJS(function(_CONTEXT,_VIEW) { " + new EJS({
+				text: src
+			}).template.out + " })";
+		},
+		renderer: function( id, text ) {
+			var ejs = new EJS({
+				text: text,
+				name: id
+			});
+			return function( data, helpers ) {
+				return ejs.render.call(ejs, data, helpers);
+			};
+		}
+	});
+});
\ No newline at end of file