[galaxy-dev] [hg] galaxy 3626: - Update jQuery.jStore, JSON2

Greg Von Kuster greg at bx.psu.edu
Thu Apr 15 20:18:47 EDT 2010


details:   http://www.bx.psu.edu/hg/galaxy/rev/5536d57237a3
changeset: 3626:5536d57237a3
user:      Kanwei Li <kanwei at gmail.com>
date:      Fri Apr 09 18:09:54 2010 -0400
description:
- Update jQuery.jStore, JSON2
- Fix issue with all local prefs being deleted on "collapse all"
- Refactored history display code into galaxy.base

diffstat:

 static/jStore.Flash.html                   |    19 -
 static/jStore.swf                          |     0 
 static/scripts/class.js                    |    80 +
 static/scripts/galaxy.base.js              |    87 +
 static/scripts/jquery.jstore-all.js        |   748 -----------
 static/scripts/jquery.jstore.js            |  1810 ++++++++++++++++++++++++++++
 static/scripts/json2.js                    |    26 +-
 static/scripts/packed/class.js             |     7 +
 static/scripts/packed/galaxy.base.js       |     2 +-
 static/scripts/packed/jquery.jstore-all.js |     1 -
 static/scripts/packed/jquery.jstore.js     |    17 +
 static/scripts/packed/json2.js             |     2 +-
 templates/display_base.mako                |    29 +-
 templates/history/display.mako             |   264 +---
 templates/history/view.mako                |   259 +---
 templates/page/display.mako                |   272 +---
 templates/root/history.mako                |   222 +--
 templates/workflow/editor.mako             |    42 +-
 18 files changed, 2216 insertions(+), 1671 deletions(-)

diffs (truncated from 4199 to 3000 lines):

diff -r a9402fc7ce1b -r 5536d57237a3 static/jStore.Flash.html
--- a/static/jStore.Flash.html	Fri Apr 09 13:02:15 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
-	<head>
-		<title>Flash External Object</title>
-		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-		<script type="text/javascript">
-			/**
-			 * This function captures the flash_ready event. We need to relay this
-			 * back to the parent so it knows flash is ready.
-			 */
-			function flash_ready(){
-				parent.flash_ready();
-			}
-		</script>
-	</head>
-	<body>
-		<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" width="1" height="1" id="jStoreFlash"><param name="allowScriptAccess" value="always" /><param name="movie" value="jStore.swf" /><param name="quality" value="high" /><param name="bgcolor" value="#ffcc00" /><embed src="jStore.swf" quality="high" bgcolor="#ffcc00" width="1" height="1" name="jStoreFlash" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" /></object>
-	</body>
-</html>
\ No newline at end of file
diff -r a9402fc7ce1b -r 5536d57237a3 static/jStore.swf
Binary file static/jStore.swf has changed
diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/class.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/static/scripts/class.js	Fri Apr 09 18:09:54 2010 -0400
@@ -0,0 +1,80 @@
+/*!
+ *  Class definition
+ *
+ *  Copyright (c) 2008 John Resig (http://ejohn.org/blog/simple-javascript-inheritance/)
+ *  Inspired by base2 and Prototype
+ */
+
+"use strict";
+
+(function () {
+
+    var initializing = false, 
+    
+        fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
+    
+    // The base Class implementation (does nothing) 
+    this.Class = function(){};
+        
+    // Create a new Class that inherits from this class
+    Class.extend = function (prop)
+    {
+        var _super = this.prototype;
+        
+        // Instantiate a base class (but only create the instance, don't run the init constructor)
+        initializing = true;
+        
+        var prototype = new this();
+        
+        initializing = false;
+        
+        // Copy the properties over onto the new prototype
+        for (var name in prop) 
+        {
+        
+            // Check if we're overwriting an existing function
+            prototype[name] = (typeof prop[name] === "function" && typeof _super[name] === "function" && fnTest.test(prop[name]) ?
+            
+                (function(name, fn)
+                {
+                    return function()
+                    {
+                        var tmp = this._super;
+        
+                        // Add a new ._super() method that is the same method
+                        // but on the super-class
+                        this._super = _super[name];
+                        
+                        // The method only need to be bound temporarily, so we
+                        // remove it when we're done executing
+                        var ret = fn.apply(this, arguments);        
+                        this._super = tmp;
+                        
+                        return ret;
+                    };
+                }(name, prop[name])) : prop[name]);
+        }
+
+        // The dummy class constructor
+        function Class()
+        {
+            // All construction is actually done in the init method
+            if (!initializing && this.init)
+            {
+                this.init.apply(this, arguments);
+            }
+        }
+        
+        // Populate our constructed prototype object
+        Class.prototype = prototype;
+        
+        // Enforce the constructor to be what we expect
+        Class.constructor = Class;
+        
+        // And make this class extendable
+        Class.extend = arguments.callee;
+        
+        return Class;
+    };
+    
+}());
diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/galaxy.base.js
--- a/static/scripts/galaxy.base.js	Fri Apr 09 13:02:15 2010 -0400
+++ b/static/scripts/galaxy.base.js	Fri Apr 09 18:09:54 2010 -0400
@@ -275,6 +275,93 @@
     });
 }
 
+function init_history_items(historywrapper, noinit) {
+
+    var action = function() {
+        // Load saved state and show as necessary
+        try {
+            var stored = $.jStore.store("history_expand_state");
+            if (stored) {
+                for (var id in stored) {
+                    $("#" + id + " div.historyItemBody" ).show();
+                }
+            }
+        } catch(err) {
+            // Something was wrong with values in storage, so clear storage
+            $.jStore.remove("history_expand_state");
+        }
+
+        // If Mozilla, hide scrollbars in hidden items since they cause animation bugs
+        if ( $.browser.mozilla ) {
+            $( "div.historyItemBody" ).each( function() {
+                if ( ! $(this).is( ":visible" ) ) $(this).find( "pre.peek" ).css( "overflow", "hidden" );
+            })
+        }
+        
+        historywrapper.each( function() {
+            var id = this.id;
+            var body = $(this).children( "div.historyItemBody" );
+            var peek = body.find( "pre.peek" )
+            $(this).children( ".historyItemTitleBar" ).find( ".historyItemTitle" ).wrap( "<a href='#'></a>" ).click( function() {
+                if ( body.is(":visible") ) {
+                    // Hiding stuff here
+                    if ( $.browser.mozilla ) { peek.css( "overflow", "hidden" ) }
+                    body.slideUp( "fast" );
+                    
+                    if (!noinit) { // Ignore embedded item actions
+                        // Save setting
+                        var prefs = $.jStore.store("history_expand_state");
+                        if (prefs) {
+                            delete prefs[id];
+                            $.jStore.store("history_expand_state", prefs);
+                        }
+                    }
+                } else {
+                    // Showing stuff here
+                    body.slideDown( "fast", function() { 
+                        if ( $.browser.mozilla ) { peek.css( "overflow", "auto" ); } 
+                    });
+                    
+                    if (!noinit) {
+                        // Save setting
+                        var prefs = $.jStore.store("history_expand_state");
+                        if (prefs === undefined) { prefs = {}; }
+                        prefs[id] = true;
+                        $.jStore.store("history_expand_state", prefs);
+                    }
+                }
+                return false;
+            });
+        });
+        
+        // Generate 'collapse all' link
+        $("#top-links > a.toggle").click( function() {
+            var prefs = $.jStore.store("history_expand_state");
+            if (prefs === undefined) { prefs = {}; }
+            $( "div.historyItemBody:visible" ).each( function() {
+                if ( $.browser.mozilla ) {
+                    $(this).find( "pre.peek" ).css( "overflow", "hidden" );
+                }
+                $(this).slideUp( "fast" );
+                if (prefs) {
+                    delete prefs[$(this).parent().attr("id")];
+                }
+            });
+            $.jStore.store("history_expand_state", prefs);
+        }).show();
+    }
+    
+    if (noinit) {
+        action();
+    } else {
+        // Load jStore for local storage
+        $.jStore.init("galaxy"); // Auto-select best storage
+        $.jStore.engineReady(function() {
+            action();
+        });
+    }
+}
+
 $(document).ready( function() {
     // Links with confirmation
     $( "a[confirm]" ).click( function() {
diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/jquery.jstore-all.js
--- a/static/scripts/jquery.jstore-all.js	Fri Apr 09 13:02:15 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,748 +0,0 @@
-/*
- * jStore - Persistent Client-Side Storage
- *
- * Copyright (c) 2009 Eric Garside (http://eric.garside.name)
- * 
- * Dual licensed under:
- * 	MIT: http://www.opensource.org/licenses/mit-license.php
- *	GPLv3: http://www.opensource.org/licenses/gpl-3.0.html
- *//**
- * Javascript Class Framework
- * 
- * Copyright (c) 2008 John Resig (http://ejohn.org/blog/simple-javascript-inheritance/)
- * Inspired by base2 and Prototype
- */
-(function(){
-  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
-
-  // The base Class implementation (does nothing)
-  this.Class = function(){};
- 
-  // Create a new Class that inherits from this class
-  Class.extend = function(prop) {
-    var _super = this.prototype;
-   
-    // Instantiate a base class (but only create the instance,
-    // don't run the init constructor)
-    initializing = true;
-    var prototype = new this();
-    initializing = false;
-   
-    // Copy the properties over onto the new prototype
-    for (var name in prop) {
-      // Check if we're overwriting an existing function
-      prototype[name] = typeof prop[name] == "function" &&
-        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
-        (function(name, fn){
-          return function() {
-            var tmp = this._super;
-           
-            // Add a new ._super() method that is the same method
-            // but on the super-class
-            this._super = _super[name];
-           
-            // The method only need to be bound temporarily, so we
-            // remove it when we're done executing
-            var ret = fn.apply(this, arguments);       
-            this._super = tmp;
-           
-            return ret;
-          };
-        })(name, prop[name]) :
-        prop[name];
-    }
-   
-    // The dummy class constructor
-    function Class() {
-      // All construction is actually done in the init method
-      if ( !initializing && this.init )
-        this.init.apply(this, arguments);
-    }
-   
-    // Populate our constructed prototype object
-    Class.prototype = prototype;
-   
-    // Enforce the constructor to be what we expect
-    Class.constructor = Class;
-
-    // And make this class extendable
-    Class.extend = arguments.callee;
-   
-    return Class;
-  };
-})();
-/*
- * jStore Delegate Framework
- * Copyright (c) 2009 Eric Garside (http://eric.garside.name)
- */
-(function($){
-	
-	this.jStoreDelegate = Class.extend({
-		init: function(parent){
-			// The Object this delgate operates for
-			this.parent = parent;
-			// Container for callbacks to dispatch.
-			// eventType => [ callback, callback, ... ]
-			this.callbacks = {};
-		},
-		bind: function(event, callback){
-			if ( !$.isFunction(callback) ) return this;
-			if ( !this.callbacks[ event ] ) this.callbacks[ event ] = [];
-			
-			this.callbacks[ event ].push(callback);
-			
-			return this;
-		},
-		trigger: function(){
-			var parent = this.parent,
-				args = [].slice.call(arguments),
-				event = args.shift(),
-				handlers = this.callbacks[ event ];
-
-			if ( !handlers ) return false;
-			
-			$.each(handlers, function(){ this.apply(parent, args) });
-			return this;
-		}
-	});
-	
-})(jQuery);/**
- * jStore-jQuery Interface
- * Copyright (c) 2009 Eric Garside (http://eric.garside.name)
- */
-(function($){
-	
-	// Setup the jStore namespace in jQuery for options storage
-	$.jStore = {};
-	
-	// Seed the options in
-	$.extend($.jStore, {
-		EngineOrder: [],
-		// Engines should put their availability tests within jStore.Availability
-		Availability: {},
-		// Defined engines should enter themselves into the jStore.Engines
-		Engines: {},
-		// Instanciated engines should exist within jStore.Instances
-		Instances: {},
-		// The current engine to use for storage
-		CurrentEngine: null,
-		// Provide global settings for overwriting
-		defaults: {
-			project: null,
-			engine: null,
-			autoload: true,
-			flash: 'jStore.Flash.html'
-		},
-		// Boolean for ready state handling
-		isReady: false,
-		// Boolean for flash ready state handling
-		isFlashReady: false,
-		// An event delegate
-		delegate: new jStoreDelegate($.jStore)
-			.bind('jStore-ready', function(engine){
-				$.jStore.isReady = true;
-				if ($.jStore.defaults.autoload) engine.connect();
-			})
-			.bind('flash-ready', function(){
-				$.jStore.isFlashReady = true;
-			})			
-	});
-	
-	// Enable ready callback for jStore
-	$.jStore.ready = function(callback){
-		if ($.jStore.isReady) callback.apply($.jStore, [$.jStore.CurrentEngine]);
-		else $.jStore.delegate.bind('jStore-ready', callback);
-	}
-	
-	// Enable failure callback registration for jStore
-	$.jStore.fail = function(callback){
-		$.jStore.delegate.bind('jStore-failure', callback);
-	}
-	
-	// Enable ready callback for Flash
-	$.jStore.flashReady = function(callback){
-		if ($.jStore.isFlashReady) callback.apply($.jStore, [$.jStore.CurrentEngine]);
-		else $.jStore.delegate.bind('flash-ready', callback);
-	}
-	
-	// Enable and test an engine
-	$.jStore.use = function(engine, project, identifier){
-		project = project || $.jStore.defaults.project || location.hostname.replace(/\./g, '-') || 'unknown';
-		
-		var e = $.jStore.Engines[engine.toLowerCase()] || null,
-			name = (identifier ? identifier + '.' : '') + project + '.' + engine;
-		
-		if ( !e ) throw 'JSTORE_ENGINE_UNDEFINED';
-
-		// Instanciate the engine
-		e = new e(project, name);
-		
-		// Prevent against naming conflicts
-		if ($.jStore.Instances[name]) throw 'JSTORE_JRI_CONFLICT';
-		
-		// Test the engine
-		if (e.isAvailable()){
-			$.jStore.Instances[name] = e;	// The Easy Way
-			if (!$.jStore.CurrentEngine){
-				$.jStore.CurrentEngine = e;
-			}
-			$.jStore.delegate.trigger('jStore-ready', e);
-		} else {
-			if (!e.autoload)				// Not available
-				throw 'JSTORE_ENGINE_UNAVILABLE';
-			else { 							// The hard way
-				e.included(function(){
-					if (this.isAvailable()) { // Worked out
-						$.jStore.Instances[name] = this;
-						// If there is no current engine, use this one
-						if (!$.jStore.CurrentEngine){
-							$.jStore.CurrentEngine = this;
-						} 
-						$.jStore.delegate.trigger('jStore-ready', this);
-					}
-					else $.jStore.delegate.trigger('jStore-failure', this);
-				}).include();
-			}
-		}
-	}
-	
-	// Set the current storage engine
-	$.jStore.setCurrentEngine = function(name){
-		if (!$.jStore.Instances.length )				// If no instances exist, attempt to load one
-			return $.jStore.FindEngine();
-			
-		if (!name && $.jStore.Instances.length >= 1) { // If no name is specified, use the first engine
-			$.jStore.delegate.trigger('jStore-ready', $.jStore.Instances[0]);
-			return $.jStore.CurrentEngine = $.jStore.Instances[0];
-		}
-			
-		if (name && $.jStore.Instances[name]) { // If a name is specified and exists, use it
-			$.jStore.delegate.trigger('jStore-ready', $.jStore.Instances[name]);
-			return $.jStore.CurrentEngine = $.jStore.Instances[name];
-		}
-		
-		throw 'JSTORE_JRI_NO_MATCH';
-	}
-	
-	// Test all possible engines for straightforward useability
-	$.jStore.FindEngine = function(){
-		$.each($.jStore.EngineOrder, function(k){
-			if ($.jStore.Availability[this]()){ // Find the first, easiest option and use it.
-				$.jStore.use(this, $.jStore.defaults.project, 'default');
-				return false;
-			}
-		})
-	}
-	
-	// Provide a simple interface for storing/getting values
-	$.jStore.store = function(key, value){
-		if (!$.jStore.CurrentEngine) return false;
-		
-		if ( !value ) // Executing a get command
-			return $.jStore.CurrentEngine.get(key);
-		// Executing a set command
-			return $.jStore.CurrentEngine.set(key, value);
-	}
-	// Provide a simple interface for storing/getting values
-	$.jStore.remove = function(key){
-		if (!$.jStore.CurrentEngine) return false;
-		
-		return $.jStore.CurrentEngine.rem(key);
-	}
-	
-	// Provide a chainable interface for storing values/getting a value at the end of a chain
-	$.fn.store = function(key, value){
-		if (!$.jStore.CurrentEngine) return this;
-		
-		var result = $.jStore.store(key, value);
-		
-		return !value ? result : this;
-	}
-	
-	// Provide a chainable interface for removing values
-	$.fn.removeStore = function(key){
-		$.jStore.remove(key);
-		
-		return this;
-	}
-	
-	// Provide a way for users to call for auto-loading
-	$.jStore.load = function(){
-		if ($.jStore.defaults.engine)
-			return $.jStore.use($.jStore.defaults.engine, $.jStore.defaults.project, 'default');
-			
-		// Attempt to find a valid engine, and catch any exceptions if we can't
-		try {
-			$.jStore.FindEngine();
-		} catch (e) {}
-	}
-	
-})(jQuery);
-/**
- * jStore Engine Core
- * Copyright (c) 2009 Eric Garside (http://eric.garside.name)
- */
-(function($){
-	
-	this.StorageEngine = Class.extend({
-		init: function(project, name){
-			// Configure the project name
-			this.project = project;
-			// The JRI name given by the manager
-			this.jri = name;
-			// Cache the data so we can work synchronously
-			this.data = {};
-			// The maximum limit of the storage engine
-			this.limit = -1;
-			// Third party script includes
-			this.includes = [];
-			// Create an event delegate for users to subscribe to event triggers
-			this.delegate = new jStoreDelegate(this)
-				.bind('engine-ready', function(){
-					this.isReady = true;
-				})
-				.bind('engine-included', function(){
-					this.hasIncluded = true;
-				});
-			// If enabled, the manager will check availability, then run include(), then check again
-			this.autoload = false; // This should be changed by the engines, if they have required includes
-			// When set, we're ready to transact data
-			this.isReady = false;
-			// When the includer is finished, it will set this to true
-			this.hasIncluded = false;
-		},
-		// Performs all necessary script includes
-		include: function(){
-			var self = this,
-				total = this.includes.length,
-				count = 0;
-				
-			$.each(this.includes, function(){
-				$.ajax({type: 'get', url: this, dataType: 'script', cache: true, 
-					success: function(){
-						count++;
-						if (count == total)	self.delegate.trigger('engine-included');
-					}
-				})
-			});
-		},
-		// This should be overloaded with an actual functionality presence check
-		isAvailable: function(){
-			return false;
-		},
-		/** Event Subscription Shortcuts **/
-		ready: function(callback){
-			if (this.isReady) callback.apply(this);
-			else this.delegate.bind('engine-ready', callback);
-			return this;
-		},
-		included: function(callback){
-			if (this.hasIncluded) callback.apply(this);
-			else this.delegate.bind('engine-included', callback);
-			return this;
-		},
-		/** Cache Data Access **/
-		get: function(key){
-			return this.data[key] || null;
-		},
-		set: function(key, value){
-			this.data[key] = value;
-			return value;
-		},
-		rem: function(key){
-			var beforeDelete = this.data[key];
-			this.data[key] = null;
-			return beforeDelete;			
-		}
-	});
-	
-})(jQuery);
-/*
- * jStore DOM Storage Engine
- * Copyright (c) 2009 Eric Garside (http://eric.garside.name)
- */
-(function($){
-	
-	// Set up a static test function for this instance
-	var sessionAvailability = $.jStore.Availability.session = function(){
-			return !!window.sessionStorage;
-		},
-		localAvailability = $.jStore.Availability.local = function(){
-			return !!(window.localStorage || window.globalStorage);
-		};
-
-	this.jStoreDom = StorageEngine.extend({
-		init: function(project, name){			
-			// Call the parental init object
-			this._super(project, name);
-			
-			// The type of storage engine
-			this.type = 'DOM';
-			
-			// Set the Database limit
-			this.limit = 5 * 1024 * 1024;
-		},
-		connect: function(){
-			// Fire our delegate to indicate we're ready for data transactions
-			this.delegate.trigger('engine-ready');
-		},
-		get: function(key){
-			var out = this.db.getItem(key);
-			// Gecko's getItem returns {value: 'the value'}, WebKit returns 'the value'
-			return out && out.value ? out.value : out
-		},
-		set: function(key, value){
-			this.db.setItem(key,value); 
-			return value;
-		},
-		rem: function(key){
-			var out = this.get(key); 
-			this.db.removeItem(key); 
-			return out
-		}
-	})
-	
-	this.jStoreLocal = jStoreDom.extend({
-		connect: function(){
-			// Gecko uses a non-standard globalStorage[ www.example.com ] DOM access object for persistant storage.
-			this.db = !window.globalStorage ? window.localStorage : window.globalStorage[location.hostname];
-			this._super();
-		},
-		isAvailable: localAvailability
-	})
-	
-	this.jStoreSession = jStoreDom.extend({
-		connect: function(){
-			this.db = sessionStorage;
-			this._super();
-		},
-		isAvailable: sessionAvailability
-	})
-
-	$.jStore.Engines.local = jStoreLocal;
-	$.jStore.Engines.session = jStoreSession;
-
-	// Store the ordering preference
-	$.jStore.EngineOrder[ 1 ] = 'local';
-
-})(jQuery);
-/*
- * jStore Flash Storage Engine
- * Copyright (c) 2009 Eric Garside (http://eric.garside.name)
- * jStore.swf Copyright (c) 2008 Daniel Bulli (http://www.nuff-respec.com)
- */
-(function($){
-	
-	// Set up a static test function for this instance
-	var avilability = $.jStore.Availability.flash = function(){
-		return !!($.jStore.hasFlash('8.0.0'));
-	}
-	
-	this.jStoreFlash = StorageEngine.extend({
-		init: function(project, name){			
-			// Call the parental init object
-			this._super(project, name);
-			
-			// The type of storage engine
-			this.type = 'Flash';
-			
-			// Bind our flashReady function to the jStore Delegate
-			var self = this;
-			$.jStore.flashReady(function(){ self.flashReady() });
-		},
-		connect: function(){
-			var name = 'jstore-flash-embed-' + this.project;
-			
-			// To make Flash Storage work on IE, we have to load up an iFrame
-			// which contains an HTML page that embeds the object using an
-			// object tag wrapping an embed tag. Of course, this is unnecessary for
-			// all browsers except for IE, which, to my knowledge, is the only browser
-			// in existance where you need to complicate your code to fix bugs. Goddamnit. :(
-			$(document.body)
-				.append('<iframe style="height:1px;width:1px;position:absolute;left:0;top:0;margin-left:-100px;" ' + 
-					'id="jStoreFlashFrame" src="' +$.jStore.defaults.flash + '"></iframe>');
-		},
-		flashReady: function(e){
-			var iFrame = $('#jStoreFlashFrame')[0];
-			
-			// IE
-			if (iFrame.Document && $.isFunction(iFrame.Document['jStoreFlash'].f_get_cookie)) this.db = iFrame.Document['jStoreFlash'];
-			// Safari && Firefox
-			else if (iFrame.contentWindow && iFrame.contentWindow.document){
-				var doc = iFrame.contentWindow.document;
-				// Safari
-				if ($.isFunction($('object', $(doc))[0].f_get_cookie)) this.db = $('object', $(doc))[0];
-				// Firefox
-				else if ($.isFunction($('embed', $(doc))[0].f_get_cookie)) this.db = $('embed', $(doc))[0];
-			}
-
-			// We're ready to process data
-			if (this.db) this.delegate.trigger('engine-ready');
-		},
-		isAvailable: avilability,
-		get: function(key){
-			var out = this.db.f_get_cookie(key);
-			return out == 'null' ? null : out;
-		},
-		set: function(key, value){
-			this.db.f_set_cookie(key, value);
-			return value;
-		},
-		rem: function(key){
-			var beforeDelete = this.get(key);
-			this.db.f_delete_cookie(key);
-			return beforeDelete;
-		}
-	})
-
-	$.jStore.Engines.flash = jStoreFlash;
-
-	// Store the ordering preference
-	$.jStore.EngineOrder[ 2 ] = 'flash';
-
-	/**
- 	 * Flash Detection functions copied from the jQuery Flash Plugin
- 	 * Copyright (c) 2006 Luke Lutman (http://jquery.lukelutman.com/plugins/flash)
- 	 * Dual licensed under the MIT and GPL licenses.
- 	 * 	http://www.opensource.org/licenses/mit-license.php
- 	 * 	http://www.opensource.org/licenses/gpl-license.php 
- 	 */
-	$.jStore.hasFlash = function(version){
-		var pv = $.jStore.flashVersion().match(/\d+/g),
-			rv = version.match(/\d+/g);
-
-		for(var i = 0; i < 3; i++) {
-			pv[i] = parseInt(pv[i] || 0);
-			rv[i] = parseInt(rv[i] || 0);
-			// player is less than required
-			if(pv[i] < rv[i]) return false;
-			// player is greater than required
-			if(pv[i] > rv[i]) return true;
-		}
-		// major version, minor version and revision match exactly
-		return true;
-	}
-	
-	$.jStore.flashVersion = function(){
-		// ie
-		try {
-			try {
-				// avoid fp6 minor version lookup issues
-				// see: http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
-				var axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6');
-				try { axo.AllowScriptAccess = 'always';	} 
-				catch(e) { return '6,0,0'; }				
-			} catch(e) {}
-				return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
-		// other browsers
-		} catch(e) {
-			try {
-				if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){
-					return (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g, ",").match(/^,?(.+),?$/)[1];
-				}
-			} catch(e) {}		
-		}
-		return '0,0,0';
-	}
-
-})(jQuery);
-
-// Callback fired when ExternalInterface is established
-function flash_ready(){
-	$.jStore.delegate.trigger('flash-ready');
-}
-/*
- * jStore Google Gears Storage Engine
- * Copyright (c) 2009 Eric Garside (http://eric.garside.name)
- */
-(function($){
-	
-	// Set up a static test function for this instance
-	var avilability = $.jStore.Availability.gears = function(){
-		return !!(window.google && window.google.gears)
-	}
-	
-	this.jStoreGears = StorageEngine.extend({
-		init: function(project, name){			
-			// Call the parental init object
-			this._super(project, name);
-			
-			// The type of storage engine
-			this.type = 'Google Gears';
-			
-			// Add required third-party scripts
-			this.includes.push('http://code.google.com/apis/gears/gears_init.js');
-			
-			// Allow Autoloading on fail
-			this.autoload = true;
-		},
-		connect: function(){
-			// Create our database connection
-			var db = this.db = google.gears.factory.create('beta.database');
-			db.open( 'jstore-' + this.project );
-			db.execute( 'CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)' );
-			
-			// Cache the data from the table
-			this.updateCache();
-		},
-		updateCache: function(){
-			// Read the database into our cache object
-			var result = this.db.execute( 'SELECT k,v FROM jstore' );
-			while (result.isValidRow()){
-				this.data[result.field(0)] = result.field(1);
-				result.next();
-			} result.close();
-			
-			// Fire our delegate to indicate we're ready for data transactions
-			this.delegate.trigger('engine-ready');
-		},
-		isAvailable: avilability,
-		set: function(key, value){
-			// Update the database
-			var db = this.db;
-			db.execute( 'BEGIN' );
-			db.execute( 'INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)', [key,value] );
-			db.execute( 'COMMIT' );
-			return this._super(key, value);
-		},
-		rem: function(key){
-			// Update the database
-			var db = this.db;
-			db.execute( 'BEGIN' );
-			db.execute( 'DELETE FROM jstore WHERE k = ?', [key] );
-			db.execute( 'COMMIT' );
-			return this._super(key);
-		}
-	})
-
-	$.jStore.Engines.gears = jStoreGears;
-	
-	// Store the ordering preference
-	$.jStore.EngineOrder[ 3 ] = 'gears';
-
-})(jQuery);
-/*
- * jStore HTML5 Specification Storage Engine
- * Copyright (c) 2009 Eric Garside (http://eric.garside.name)
- */
-(function($){
-	
-	// Set up a static test function for this instance
-	var avilability = $.jStore.Availability.html5 = function(){
-		return !!window.openDatabase
-	}
-	
-	this.jStoreHtml5 = StorageEngine.extend({
-		init: function(project, name){			
-			// Call the parental init object
-			this._super(project, name);
-			
-			// The type of storage engine
-			this.type = 'HTML5';
-			
-			// Set the Database limit
-			this.limit = 1024 * 200;
-		},
-		connect: function(){
-			// Create our database connection
-			var db = this.db = openDatabase('jstore-' + this.project, '1.0', this.project, this.limit);
-			if (!db) throw 'JSTORE_ENGINE_HTML5_NODB';
-			db.transaction(function(db){
-				db.executeSql( 'CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)' );
-			});
-			
-			// Cache the data from the table
-			this.updateCache();
-		},
-		updateCache: function(){
-			var self = this;
-			// Read the database into our cache object
-			this.db.transaction(function(db){
-				db.executeSql( 'SELECT k,v FROM jstore', [], function(db, result){
-					var rows = result.rows, i = 0, row;
-					for (; i < rows.length; ++i){
-						row = rows.item(i);
-						self.data[row.k] = row.v;
-					}
-					
-					// Fire our delegate to indicate we're ready for data transactions
-					self.delegate.trigger('engine-ready');
-				});
-			});
-		},
-		isAvailable: avilability,
-		set: function(key, value){
-			// Update the database
-			this.db.transaction(function(db){
-				db.executeSql( 'INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)', [key,value]);
-			});
-			return this._super(key, value);
-		},
-		rem: function(key){
-			// Update the database
-			this.db.transaction(function(db){
-				db.executeSql( 'DELETE FROM jstore WHERE k = ?', [key] )
-			})
-			return this._super(key);
-		}
-	})
-
-	$.jStore.Engines.html5 = jStoreHtml5;
-
-	// Store the ordering preference
-	$.jStore.EngineOrder[ 0 ] = 'html5';
-
-})(jQuery);
-/*
- * jStore IE Storage Engine
- * Copyright (c) 2009 Eric Garside (http://eric.garside.name)
- */
-(function($){
-	
-	// Set up a static test function for this instance
-	var avilability = $.jStore.Availability.ie = function(){
-		return !!window.ActiveXObject;
-	}
-	
-	this.jStoreIE = StorageEngine.extend({
-		init: function(project, name){			
-			// Call the parental init object
-			this._super(project, name);
-			
-			// The type of storage engine
-			this.type = 'IE';
-			
-			// Allow Autoloading on fail
-			this.limit = 64 * 1024;
-		},
-		connect: function(){
-			// Create a hidden div to store attributes in
-			this.db = $('<div style="display:none;behavior:url(\'#default#userData\')" id="jstore-' + this.project + '"></div>')
-						.appendTo(document.body).get(0);
-			// Fire our delegate to indicate we're ready for data transactions
-			this.delegate.trigger('engine-ready');
-		},
-		isAvailable: avilability,
-		get: function(key){
-			this.db.load(this.project);
-			return this.db.getAttribute(key);
-		},
-		set: function(key, value){
-			this.db.setAttribute(key, value);
-			this.db.save(this.project);
-			return value;
-		},
-		rem: function(key){
-			var beforeDelete = this.get(key);
-			this.db.removeAttribute(key);
-			this.db.save(this.project);
-			return beforeDelete;
-		}
-	})
-
-	$.jStore.Engines.ie = jStoreIE;
-	
-	// Store the ordering preference
-	$.jStore.EngineOrder[ 4 ] = 'ie';
-
-})(jQuery);
diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/jquery.jstore.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/static/scripts/jquery.jstore.js	Fri Apr 09 18:09:54 2010 -0400
@@ -0,0 +1,1810 @@
+/*!
+ *  jStore 2.0 - Persistent Client Side Storage
+ *
+ *  Copyright (c) 2010 Eric Garside (http://eric.garside.name/)
+ *  Dual licensed under:
+ *      MIT: http://www.opensource.org/licenses/mit-license.php
+ *      GPLv3: http://www.opensource.org/licenses/gpl-3.0.html
+ *
+ *  ---------------------------
+ *
+ *  jStore Flash Storage Component
+ *
+ *  Copyright (c) 2006 Jeff Lerman (jeff at blip.tv)
+ *  Licensed under the Creative Commons Attribution 3.0 United States License:
+ *      http://creativecommons.org/licenses/by/3.0/us
+ */
+
+"use strict";
+
+/*global Class, window, jQuery, ActiveXObject, google */
+
+/*jslint white: true, browser: true, onevar: true, undef: true, eqeqeq: true, bitwise: true, regexp: false, strict: true, newcap: true, immed: true, maxerr: 50, indent: 4 */
+
+(function ($, window) {
+    
+    //------------------------------
+    //
+    //  Constants
+    //
+    //------------------------------
+    
+    //------------------------------
+    //  Exceptions
+    //------------------------------
+    
+        /**
+         *  An exception thrown by the StorageEngine class whenever its data accessor methods
+         *  are called before the engine is ready to transact data.
+         */
+    var EX_UNSTABLE = 'JSTORE_ENGINE_UNSTABLE',
+    
+        /**
+         *  An exception thrown by jStore whenever an undefined storage engine is referenced for
+         *  some task by an invalid JRI (jStore Resource Identifier).
+         */
+        EX_UNKNOWN = 'JSTORE_UNKNOWN_ENGINE_REQUESTED',
+        
+        /**
+         *  An exception thrown by jStore whenever a given flavor of storage is double defined.
+         */
+        EX_COLLISION = 'JSTORE_ENGINE_NAMESPACE_COLLISION',
+        
+        /**
+         *  An exception thrown by jStore whenever a jri is double applied to a resource.
+         */
+        EX_DUPLICATE = 'JSTORE_RESOURCE_NAMESPACE_COLLISION',
+        
+        /**
+         *  An exception thrown by jStore whenever a given flavor of storage has no defined engine.
+         */
+        EX_UNAVAILABLE = 'JSTORE_ENGINE_UNAVAILABLE',
+        
+        /**
+         *  An exception thrown by jStore whenever an invalid flavor type is used.
+         */
+        EX_INVALID = 'JSTORE_INVALID_FLAVOR',
+        
+    //------------------------------
+    //  Regular Expressions
+    //------------------------------
+    
+        /**
+         *  Regular expression to test property values for being JSON.
+         */
+        RX_JSON = (function ()
+        {
+            try 
+            {
+                return new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$');
+            }
+            catch (e)
+            {
+                return (/^(true|false|null|\[.*\]|\{.*\}|".*"|\d+|\d+\.\d+)$/);
+            }
+        }()),
+    
+    //------------------------------
+    //  Storage Flavors
+    //------------------------------
+        
+        /**
+         *  The storage flavor identifier for HTML5 local storage.
+         */
+        FLAVOR_LOCAL = 'jstore-html5-local',
+        
+        /**
+         *  The storage flavor identifier for HTML5 database storage.
+         */
+        FLAVOR_SQL = 'jstore-html5-sql',
+        
+        /**
+         *  The storage flavor identifier for Adobe Flash SharedObject storage.
+         */
+        FLAVOR_FLASH = 'jstore-flash',
+        
+        /**
+         *  The storage flavor identifier for Google Gears storage.
+         */
+        FLAVOR_GEARS = 'jstore-google-gears',
+        
+        /**
+         *  The storage flavor identifier for Internet Explorer storage, available to IE7 and IE6.
+         */
+        FLAVOR_MSIE = 'jstore-msie',
+    
+    //------------------------------
+    //
+    //  Property Declaration
+    //
+    //------------------------------
+    
+        /**
+         *  The base StorageEngine class which each "storage flavor" will extend to meet the
+         *  requirements for its specific implementation.
+         */
+        StorageEngine,
+        
+        /**
+         *  The jStore object. Internal to this closure, jStore is referenced by "_". It is
+         *  exposed to jQuery below, and made publicly accessible through jQuery.jStore
+         */
+        _ = {},
+        
+        /**
+         *  The engines available to jStore for use. These are the class definitions for flavored
+         *  storage engines.
+         *
+         *  Signature:
+         *  {
+         *      <storageFlavor>: <flavoredStorageEngineDefinition>,
+         *
+         *      ...
+         *  }
+         */
+        definitions = {},
+        
+        /**
+         *  Active engines instantiated by jStore, indexed by their JRI.
+         *
+         *  Signature:
+         *  {
+         *      <engineJRI>: <engineInstance>,
+         *
+         *      ...
+         *  }
+         */
+        engines = {},
+        
+        /**
+         *  If we are going to be using the flash storage engine, we want to postpone the jStore ready event until the jStore
+         *  isFlashReady flag is also true. This property is set whenever flash is determined to be the storage engine.
+         */
+        waitForFlash = false,
+        
+        /**
+         *  Storage for listeners, indexed by content and event type.
+         *
+         *  Signature:
+         *  {
+         *      <context>:
+         *      {
+         *          <eventType>: [<listener>, ...],
+         *
+         *          ...
+         *      },
+         *
+         *      ...
+         *  }
+         */
+        events = {},
+        
+        /**
+         *  The configuration for this implementation.
+         *
+         *  Signature:
+         *  {
+         *      project: <defaultProjectName>,
+         *
+         *      flash: <pathToFlashBootloader>,
+         *
+         *      json: <pathToJSONFile>,
+         *
+         *      errorCallback: <listenerToNotifyOnError>
+         *  }
+         */
+        configurations = 
+        {
+            project: undefined,
+            
+            flash: 'jStore.Flash.html',
+            
+            json: 'browser.json.js'
+        },
+        
+        /**
+         *  The active storage engine, being used to satisfy the get/set/remove functions on the jStore and jQuery
+         *  objects.
+         */
+        active;
+    
+    //------------------------------
+    //
+    //  Internal Methods
+    //
+    //------------------------------
+    
+    /**
+     *  Determine if the given flavor is valid.
+     *
+     *  @param flavor   The flavor to test.
+     *
+     *  @return True if the flavor is valid, false otherwise.
+     */
+    function validFlavor(flavor)
+    {
+        switch (flavor)
+        {
+        
+        case FLAVOR_LOCAL:
+        case FLAVOR_SQL:
+        case FLAVOR_FLASH:
+        case FLAVOR_GEARS:
+        case FLAVOR_MSIE:
+            return true;
+        
+        default:
+            return false;
+        
+        }
+    }
+
+    /**
+     *  Performs enhanced type comparison on an object. This is more reliable method
+     *  of type checking a variable than a simple typeof comparison. The reason is that,
+     *  typeof will reduce to the lowest common type. 
+     *
+     *  "typeof []" returns Object, and not Array.
+     *  "typeof {}" returns Object as well.
+     *
+     *  typecheck( [], 'Array' )    :  returns true;
+     *  typecheck( [], 'Object' )   :  returns false;
+     *
+     *  @param type     The variable type to check.
+     *
+     *  @param compare  A string representing the literal type to check.
+     *
+     *  @return True if the variable "type" matches the compare literal.
+     */
+    function typecheck(type, compare)
+    {
+        return !type ? false : type.constructor.toString().match(new RegExp(compare + '\\(\\)', 'i')) !== null; 
+    }
+    
+    /**
+     *  If the provided listener is a valid function, it will be triggered with the provided context
+     *  and parameters.
+     *
+     *  @param listener     The listener being triggered.
+     *  
+     *  @param context      The context to provide to the listener.
+     *
+     *  @param parameters   The parameters to pass to the listener as arguments.
+     *
+     *  @return The response of the notified listener.
+     */
+    function notify(listener, context, parameters)
+    {
+        if (typecheck(listener, 'Function'))
+        {
+            return listener.apply(context || _, typecheck(parameters, 'Array') ? parameters : [parameters]);
+        }
+    }
+    
+    /**
+     *  Load the given script.
+     *
+     *  @param path     The path to the file to include.
+     *
+     *  @param listener The listener to notify when the file finishes loading.
+     */
+    function loadScript(path, listener)
+    {
+        $.ajax(
+        {
+            url: path,
+            complete: listener || $.noop(),
+            type: 'GET',
+            dataType: 'script',
+            cache: false
+        });  
+    }
+    
+    /**
+     *  Checks the type of the value, and returns a value safe to persist in any client-side mechanism.
+     *
+     *  @param value    The value which should be prepared for storage.
+     *
+     *  @return A value safe for storage.
+     */
+    function prepareForStorage(value)
+    {
+        if (value === undefined)
+        {
+            return '';
+        }
+        
+        if (typecheck(value, 'Object') ||
+            typecheck(value, 'Array') ||
+            typecheck(value, 'Function'))
+        {
+            return JSON.stringify(value);
+        }
+        
+        return value;
+    }
+    
+    /**
+     *  Checks the type of the value, and returns a value safe for access in any client-side mechanism.
+     *
+     *  @param value    The value which should be prepared for use.
+     *
+     *  @return A value safe for use.
+     */
+    function prepareForRevival(value)
+    {
+        return RX_JSON.test(value) ? JSON.parse(value) : value;
+    }
+    
+    /**
+     *	Normalize a key before using it, to ensure it's valid.
+     *
+     *  @param key  The key to normalize.
+     *
+     *  @return A normalized key, safe for storage.
+     */
+    function normalizeKey(key)
+    {
+        return key.replace(/^\s+|\s+$/g, "");
+    }
+    
+    /**
+     *  Define a flavored storage engine.
+     *
+     *  @throws EX_COLLISION, EX_INVALID
+     *
+     *  @param flavor       The flavor of engine being defined.
+     *
+     *  @param definition   An object containing the new properties and methods for the engine extension.
+     *
+     *  @param availability A function to invoke which must return a boolean value indicating the
+     *                      availability of the storage flavor on this browser.
+     */
+    function define(flavor, definition, availability)
+    {
+        if (!validFlavor(flavor))
+        {
+            throw EX_INVALID;
+        }
+    
+        if (availability[flavor] !== undefined)
+        {
+            throw EX_COLLISION;
+        }
+        
+        /**
+         *  The logic here has been reworked so unavailable flavors are discarded, so we don't needlessly
+         *  bloat the runtime size of jStore.
+         */
+        if (notify(availability) === true)
+        {
+            _.available[flavor] = true;
+            
+            definition.flavor = flavor;
+            
+            definitions[flavor] = StorageEngine.extend(definition);
+        }
+        else
+        {
+            _.available[flavor] = false;
+            
+            //  Filter the invalid flavor out of the priority list.
+            _.enginePriority = $.map(_.enginePriority, function (engine)
+            {
+                if (engine === flavor)
+                {
+                    return null;
+                }
+                else
+                {
+                    return engine;
+                }
+            });
+        }
+    }
+
+    /**
+     *  Make the jStore library ready.
+     */
+    function makeReady()
+    {
+        if (_.isReady)
+        {
+            return;
+        }
+        
+        if ((waitForFlash && _.isFlashReady) || !waitForFlash)
+        {
+            _.isReady = true;
+            _.trigger('jstore-ready', [engines[active]]);
+        }
+    }
+    
+    /**
+     *  Create a best-fit engine.
+     */
+    function createBestFitEngine()
+    {
+        _.create(_.enginePriority[0], undefined, 'best-fit');
+    }
+    
+    /**
+     *  Get the flash version currently supported in this browser.
+     *
+     *  @return The flash version.
+     */
+    function flashVersion()
+    {
+        // MSIE
+        try
+        {
+            // avoid fp6 minor version lookup issues
+            // see: http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
+            var axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6');
+            
+            try
+            {
+                axo.AllowScriptAccess = 'always';
+            }
+            catch (axo_e)
+            {
+                return '6,0,0';
+            }
+            
+            return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
+        }
+        
+        //  Real browsers
+        catch (e)
+        {
+            try
+            {
+                if (navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin)
+                {
+                    return (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g, ",").match(/^,?(.+),?$/)[1];
+                }
+            }
+            catch (flash_e)
+            {}
+        }
+        
+        return '0,0,0';
+    }
+
+    /**
+     *  Flash Detection functions copied from the jQuery Flash Plugin
+     * 
+     *  Copyright (c) 2006 Luke Lutman (http://jquery.lukelutman.com/plugins/flash)
+     * 
+     *  Dual licensed under the MIT and GPL licenses.
+     *      http://www.opensource.org/licenses/mit-license.php
+     *      http://www.opensource.org/licenses/gpl-license.php 
+     *
+     *  @param version  The version to compare to.
+     *
+     *  @return True if the version is greater than or equal to the required version, false otherwise.
+     */
+    function hasFlashVersion(version)
+    {
+        var playerVersion = flashVersion().match(/\d+/g),
+            requiredVersion = version.match(/\d+/g),
+            index = 0,
+            player, 
+            required;
+            
+        for (; index < 3; index++)
+        {
+            player = parseInt(playerVersion[index], 10);
+            required = parseInt(requiredVersion[index], 10);
+        
+            //  Player version is less than what is required.
+            if (player < required)
+            {
+                return false;
+            }
+            
+            //  Player version is greater than what is required.
+            else if (player > required)
+            {
+                return true;
+            }
+        }
+        
+        //  Player and required version match exactly.
+        return true;
+    }
+
+    //------------------------------
+    //
+    //  Plugin Definition
+    //
+    //------------------------------
+    
+    //------------------------------
+    //  Error Declaration
+    //------------------------------
+    
+    //------------------------------
+    //  Plugin Creation
+    //------------------------------
+    
+    /**
+     *  The jStore object. Manages a collection of StorageEngines for particular "storage flavors", or the types
+     *  of storage solutions available to each browser.
+     *
+     *  2.0 Version Notes:
+     *
+     *      - The user is now responsible for third-party script includes, with the exception of flash.
+     *
+     *      - jStore has been given sole responsibility for testing engine availability.
+     *
+     *      - For the sake of naming conventions, all property names now start with a lowercase, and are camel-cased.
+     *
+     *  The following properties have been changed since the 1.2.x release:
+     *
+     *      - EngineOrder:      For the sake of naming conventions, renamed to enginePriority.
+     *
+     *  The following properties and methods have been removed since the 1.2.x release:
+     *
+     *      - Availability:     jStore's engines would add their availability tests to this object, so jStore could test 
+     *                          them. With the changes to how availability testing works, this property has been removed.
+     *                          A new property, "available" on jStore contains a set of available engines.
+     *
+     *      - Engines:          Formerly contained the definitions of storage engines. This property has been removed, and
+     *                          storage of these definitions has been moved internal to the closure.
+     *     
+     *      - Instances:        Formerly contained instantiated storage engines. This property has been removed, and storage
+     *                          of instantiated engines has been moved internal to the closure.
+     *
+     *      - CurrentEngine:    Formerly contained the active storage engine being used for transacting data through the jStore
+     *                          and/or jQuery objects. This property has been removed, and storage of the current engine has
+     *                          been moved internal to the closure. A new method, "activeEngine" has been added to jQuery to
+     *                          get and set the active engine to use.
+     *
+     *      - defaults:         Formerly used to set the implementation options for jStore. This property has been removed and
+     *                          replaced with a new configuration metho on the jStore object.
+     *
+     *      - delegate:         The delegate class has been removed in favor of a much simpler bind/trigger accessor system, which
+     *                          is accessible contextually through storage engines, or generically through jStore.
+     *      
+     *      + fail:             This registration class bound events on the delegate for jstore-fail events. Instead, use:
+     *                              jStore.bind('jstore-failure', listener);
+     *
+     *      + flashReady:       This registration class bound events on the delegate for flash-ready events. The jstore-ready method
+     *                          now accounts for waiting for flash readyness, if and only if the flash engine is being used. Simply
+     *                          call to jStore.ready().
+     *
+     *      + load:             Replaced with the init() method, which performs the same basic functions as the old load() method. Also,
+     *                          the init function is now domready safe, meaning it wraps itself in a domready listener, so the end user
+     *                          doesn't have to.
+     *
+     *      + FindEngine:       Removed entirely. The functionality provided by this method now implicitly occurs with the new define()
+     *                          system implemented for engine flavors.
+     *
+     *      + setCurrentEngine: Replaced by activeEngine(). Set the current active engine by passing in the JRI.
+     *
+     *      + safeStore:        Replaced by a method internal to this closure, "prepareForStorage".
+     *
+     *      + safeResurrect:    Replaced by a method internal to this closure, "prepareForRevival".
+     *
+     *      + use:              Replaced by "create".
+     */
+    $.extend(_, {
+    
+        //------------------------------
+        //  Properties
+        //------------------------------
+    
+        /**
+         *  The priority order in which engines should be tested for use. The lower their index in the array, the higher
+         *  their priority for use.
+         *
+         *  Be weary when reconfiguring the priority order of engines! jStore will use the first available engine it finds
+         *  based on its priority when autoloading.
+         *
+         *  This array is filtered out as engines are defined, with invalid engines being removed.
+         *
+         *  Signature:
+         *  [FLAVOR_<storageFlavor>, ...]
+         */
+        enginePriority: [FLAVOR_LOCAL, FLAVOR_SQL, FLAVOR_FLASH, FLAVOR_MSIE],
+        
+        /**
+         *  A collection of the availability states of engines, indexed by their flavor.
+         *
+         *  Signature:
+         *  {
+         *      <storageFlavor>: true|false,
+         *
+         *      ...
+         *  }
+         */
+        available: {},
+        
+        /**
+         *  Flag to determine if the jStore library is ready. jStore becomes ready once the dom is ready and all necessary 
+         *  startup procedures required by jStore to function properly are completed.
+         */
+        isReady: false,
+        
+        /**
+         *  With the flash storage engine, we have to jump through a couple of hoops before the flash engine is ready to work.
+         *  This flag tracks whether or not the flash storage is available.
+         */
+        isFlashReady: false,
+        
+        /**
+         *  The available engine flavors.
+         */
+        flavors:
+        {
+            local: FLAVOR_LOCAL,
+            
+            sql: FLAVOR_SQL,
+            
+            flash: FLAVOR_FLASH,
+            
+            gears: FLAVOR_GEARS,
+            
+            msie: FLAVOR_MSIE
+        },
+        
+        //------------------------------
+        //  Constructor
+        //------------------------------
+        
+        /**
+         *  Constructor.
+         *
+         *  @throws EX_INVALID
+         *
+         *  @param project          The name of the jStore project. Used to generate a JRI for the engine we create.
+         *
+         *  @param configuration    Optionally, an object containing configuration options for this implementation.
+         *
+         *  @param flavor           Optionally, the flavor of storage to use. If not provided, jStore will pick the
+         *                          best flavor, based on the current browser.
+         *
+         *  @return jStore
+         */
+        init: function (project, configuration, flavor)
+        {   
+            //  Extend our plugin configurations
+            $.extend(configurations, {project: project}, configuration);
+            
+            $(function ()
+            {
+                //  If JSON parsing isn't defined in this browser, include it.
+                if (window.JSON === undefined)
+                {
+                    loadScript(configurations.json);
+                }
+            
+                //  If we have an explicit flavor to use, use it.
+                if (flavor !== undefined)
+                {
+                    _.create(flavor, project, 'default');
+                }
+                
+                //  Otherwise, attempt to create a best-fit engine.
+                else
+                {
+                    createBestFitEngine();
+                }
+            });
+        
+            return _;
+        },
+    
+        //------------------------------
+        //  Methods
+        //------------------------------
+    
+        /**
+         *  Create an instance of a flavored engine.
+         *
+         *  @throws EX_INVALID, EX_UNAVAILABLE, EX_DUPLICATE
+         *
+         *  @param flavor       The flavor to create the engine with.
+         *
+         *  @param project      The project identifier for this instance.
+         *
+         *  @param identifier   Some arbitrary identifier for this project instance of the engine.
+         *
+         *  @return The created instance.
+         */
+        create: function (flavor, project, identifier)
+        {
+            project = project || configurations.project || location.hostname.replace(/\./g, '-') || 'unknown';
+            
+            if (!validFlavor(flavor))
+            {
+                throw EX_INVALID;
+            }
+            
+            if (definitions[flavor] === undefined)
+            {
+                throw EX_UNAVAILABLE;            
+            }
+            
+            var jri = (identifier !== undefined ? identifier + '.' : '') + project + '.' + flavor,
+                engine;
+
+            if (engines[jri] !== undefined)
+            {
+                throw EX_DUPLICATE;
+            }
+            
+            //  Create our engine instance.
+            engine = engines[jri] = new definitions[flavor](project, jri);
+            
+            //  Set up a listener for our jstore-engine-ready event.
+            engine.ready(function ()
+            {
+                _.trigger('jstore-engine-ready', [engine]);
+            });
+            
+            if (flavor === FLAVOR_FLASH && !_.isFlashReady)
+            {
+                if (active === undefined)
+                {
+                    waitForFlash = true;
+                }
+                
+                //  Define a window-accessible function for flash to call via ExternalInterface
+                window.jstore_ready = function ()
+                {
+                    _.isFlashReady = true;
+                    _.trigger('flash-ready');
+                    
+                    if (active === undefined)
+                    {
+                        makeReady();
+                    }
+                    
+                    //  Remove the callback from the window scope, as it is no longer necessary
+                    window.flash_ready = undefined;
+                };
+                
+                window.jstore_error = function (message)
+                {
+                    _.trigger('jstore-error', ['JSTORE_FLASH_EXCEPTION', null, message]);
+                };
+                
+                $('<iframe style="height:1px;width:1px;position:absolute;left:0;top:0;margin-left:-100px;" id="jStoreFlashFrame" src="' + 
+                    configurations.flash + '"></iframe>').appendTo('body');   
+            }
+            else if (active === undefined)
+            {
+                active = jri;
+                makeReady();
+            }
+            
+            return engine;
+        },
+        
+        /**
+         *  Fetch an engine by it's JRI.
+         *
+         *  @param jri  The JRI of the engine to retrieve.
+         *
+         *  @return The requested engine.
+         */
+        engine: function (jri)
+        {
+            return engines[jri];
+        },
+    
+        /**
+         *  Returns the active storage engine being used. If a value is passed, sets that engine as the active engine.
+         *
+         *  @throws EX_UNKNOWN
+         *
+         *  @param jri  Optionally, the JRI of the engine to make active, if it should be changed.
+         *
+         *  @return The active storage engine.
+         */
+        activeEngine: function (jri)
+        {
+            if (jri !== undefined)
+            {
+                if (engines[jri] === undefined)
+                {
+                    throw EX_UNKNOWN;
+                }
+                else
+                {
+                    active = jri;
+                }
+            }
+            
+            return engines[active];
+        },
+        
+        /**
+         *  Bind an event listener.
+         *
+         *  @param event    The event to bind a listener on.
+         *
+         *  @param listener The listener to notify when the event occurs.
+         *
+         *  @param context  The context of the binding. A string representing the engine flavor
+         *                  binding the event, or undefined to indicate it's a jStore event.
+         *
+         *  @return jStore
+         */
+        bind: function (event, listener, context)
+        {
+            context = context || 'jstore';
+            
+            if (events[context] === undefined)
+            {
+                events[context] = {};
+            }
+            
+            if (events[context][event] === undefined)
+            {
+                events[context][event] = [listener];
+            }
+            else
+            {
+                events[context][event].push(listener);
+            }
+            
+            return _;
+        },
+        
+        /**
+         *  Trigger an event, notifying any bound listeners.
+         *
+         *  @param event        The event to trigger.
+         *
+         *  @param parameters   Any additional parameters to pass to the listeners being notified.
+         *
+         *  @param context      The context of the binding. A string representing the engine flavor
+         *                      binding the event, or undefined to indicate it's a jStore event.
+         *
+         *  @return jStore
+         */
+        trigger: function (event, parameters, context)
+        {
+            context = context || 'jstore';
+            
+            if (events[context] !== undefined)
+            {
+                if (events[context][event] !== undefined)
+                {
+                    $.each(events[context][event], function ()
+                    {
+                        notify(this, _, parameters);
+                    });
+                }
+            }
+            
+            return _;
+        },
+        
+        /**
+         *	Bind a listener to be notified when jStore causes a non-fatal exception.
+         *
+         *  @param listener The listener to notify when a failure occurs.
+         */
+        error: function (listener)
+        {
+            _.bind('jstore-error', listener);
+        },
+        
+        /**
+         *  Bind a listener to be notified when jStore is ready.
+         *
+         *  @param listener The listener to notify when jStore is ready.
+         *
+         *  @return jStore
+         */
+        ready: function (listener)
+        {
+            if (_.isReady)
+            {
+                notify(listener);
+            }
+            else
+            {
+                _.bind('jstore-ready', listener);
+            }
+            
+            return _;
+        },
+        
+        /**
+         *  Bind a listener to be notified when jStore and the default engine are ready.
+         *
+         *  @param listener The listener to notify when jStore and it's default engine are ready.
+         *
+         *  @return jStore
+         */
+        engineReady: function (listener)
+        {
+            if (_.isReady)
+            {
+                notify(listener);
+            }
+            else
+            {
+                _.bind('jstore-engine-ready', listener);
+            }
+            
+            return _;
+        },
+        
+        /**
+         *  A combined getter/setter for the active engine.
+         *
+         *  @param key      The key of the property to get, or set.
+         *
+         *  @param value    If a valid value is provided, sets the engine.
+         *
+         *  @return The requested property value.
+         */
+        store: function (key, value)
+        {   
+            return value === undefined ? _.get(key) : _.set(key, value);
+        },
+        
+        /**
+         *  Remove a property from the active engine.
+         *
+         *  @param key  The key of the property to remove.
+         *
+         *  @return The value of the property before removal.
+         */
+        remove: function (key)
+        {
+            return _.activeEngine().remove(key);
+        },
+        
+        /**
+         *  Get a property from the active engine.
+         *
+         *  @param key  The key of the property to get.
+         *
+         *  @return The value of the property.
+         */
+        get: function (key)
+        {
+            return _.activeEngine().get(key);
+        },
+        
+        /**
+         *  Set a property on the active engine.
+         *
+         *  @param key      The key of the property to set.
+         *
+         *  @param value    The value to set the property to.
+         *
+         *  @return The new value of the property.
+         */
+        set: function (key, value)
+        {
+            return _.activeEngine().set(key, value);
+        }
+    
+    });
+    
+    //------------------------------
+    //  Core Extension
+    //------------------------------
+    
+    //------------------------------
+    //
+    //  Class Definition
+    //
+    //------------------------------
+    
+    /**
+     *  The StorageEngine class is the unified API through which jStore accesses and manipulates
+     *  the various storage flavors available.
+     *
+     *  2.0 Version Notes:
+     *
+     *      - All third-party loading is now the responsibility of the developer.
+     *
+     *      - The delegate class has been removed entirely. Engines have been given "bind" and "trigger" methods
+     *          to interact directly with the delegate like-replacement that has been added to jStore.
+     *
+     *      - Engine availability has been moved out of the engines themselves, and elevated to a jStore
+     *          responsibility.
+     *
+     *  The following methods have changed since the 1.2.x release:
+     *
+     *      - get:          When "get"ting a non-stored property, the get function will now return "undefined"
+     *                      instead of "null". "null" can now be used as a valid property value.
+     *
+     *      - rem:          Renamed to "remove". I always felt dirty about "rem" being vaguely explicit.
+     *
+     *  The following properties have been removed since the 1.2.x release:
+     *
+     *      - autoload:     Part of the third-party loading logic.
+     *
+     *      - hasIncluded:  Part of the third-party loading logic.
+     *  
+     *      - includes:     Part of the third-party loading logic.
+     *
+     *      - isAvailable:  Part of the availability logic elevated to jStore.
+     *
+     *  @throws EX_UNSTABLE
+     */
+    StorageEngine = Class.extend({
+    
+        //------------------------------
+        //  Properties
+        //------------------------------
+    
+        /**
+         *  The project which owns this storage engine.
+         */
+        project: undefined,
+        
+        /**
+         *  The JRI (jStore Resource Identifier) acts as a uuid for this specific instance
+         *  of the storage engine.
+         */
+        jri: undefined,
+        
+        /**
+         *  The flavor of this engine.
+         */
+        flavor: undefined,
+        
+        /**
+         *  The actual database object which data is transacted through.
+         */
+        database: undefined,
+        
+        /**
+         *  A StorageEngine should always respond to fetch requests synchronously. However, some 
+         *  of the storage flavors require callback-based asynchronous access. To get around this, 
+         *  we simlpy require all engines to function off a primary data cache, to allow for 
+         *  synchronous access across all implementations.
+         *
+         *  Signature:
+         *  {
+         *      <propertyKey>: <propertyValue>,
+         *
+         *      ...
+         *  }
+         */
+        data: undefined,
+        
+        /**
+         *  A number of storage engines enforce a size limit as to what they will persist for a given site.
+         *  This limit is not monitored or computed by jStore currently, and this property will merely give
+         *  a static indication of the total size alloted to the engine, as defined by the storage flavor.
+         */
+        limit: undefined,
+        
+        /**
+         *  Each storage flavor has a different process to go through before it's "ready" to transact data. This
+         *  property stores the state of the engine's readyness, and uses it to notify listeners whenever jStore
+         *  is ready to function.
+         */
+        isReady: undefined,
+
+        //------------------------------
+        //  Constructor
+        //------------------------------
+        
+        /**
+         *  Constructor.
+         *
+         *  @param project  The project which instantiated this engine.
+         *
+         *  @param jri      The uuid assigned to this instance by jStore.
+         */
+        init: function (project, jri)
+        {
+            this.project = project;
+            this.jri = jri;
+            this.data = {};
+            this.isReady = false;
+            this.updateCache();
+        },
+        
+        //------------------------------
+        //  Methods
+        //------------------------------
+        
+        /**
+         *  Update the cache.
+         */
+        updateCache: function ()
+        {
+            this.isReady = true;
+            this.trigger('engine-ready', [this]);
+        },
+        
+        /**
+         *  Bind a listener to an event dispatched by this engine.
+         *
+         *  @param event    The event to bind on.
+         *
+         *  @param listener The listener to notify when the event occurs.
+         */
+        bind: function (event, listener)
+        {
+            _.bind(event, listener, this.jri);
+        },
+        
+        /**
+         *  Trigger an event, notifying all bound listeners.
+         *
+         *  @param event        The event to trigger.
+         *
+         *  @param parameters   An optional Array of parameters to pass to the listeners.
+         */
+        trigger: function (event, parameters)
+        {
+            _.trigger(event, parameters, this.jri);
+        },
+        
+        /**
+         *  Bind a listener to the StorageEngine's ready event.
+         *
+         *  @param listener The listener to notify whenever this engine is ready to transact data.
+         */
+        ready: function (listener)
+        {
+            if (this.isReady)
+            {
+                notify(listener, this);
+            }
+            else
+            {
+                this.bind('engine-ready', listener);
+            }
+        },
+        
+        /**
+         *  Get a property from the StorageEngine.
+         *
+         *  @param key  The property key of the data to retrieve.
+         *
+         *  @return The property value, or "undefined" if the property isn't stored.
+         */
+        get: function (key)
+        {
+            this.__interruptAccess();
+            
+            return this.data[key];
+        },
+        
+        /**
+         *  Sets a property in the StorageEngine.
+         *
+         *  @param key      The key of the property.
+         *
+         *  @param value    The value of the property.
+         *
+         *  @return The new value of the property.
+         */
+        set: function (key, value)
+        {
+            this.__interruptAccess();
+            
+            key = normalizeKey(key);
+            
+            try
+            {
+                this.__set(key, value);
+            }
+            catch (e)
+            {
+                _.trigger('jstore-error', ['JSTORE_STORAGE_FAILURE', this.jri, e]);
+            }
+            
+            this.data[key] = value;
+            
+            return value;
+        },
+        
+        /**
+         *  Removes a property from the StorageEngine.
+         *
+         *  @param key  The property key of the data to remove.
+         *
+         *  @return The value of the property, before it was removed.
+         */
+        remove: function (key)
+        {
+            this.__interruptAccess();
+            
+            key = normalizeKey(key);
+            
+            try
+            {
+                this.__remove(key);
+            }
+            catch (e)
+            {
+                _.trigger('jstore-error', ['JSTORE_REMOVE_FAILURE', this.jri, e]);
+            }
+            
+            var buffer = this.data[key];
+            
+            this.data[key] = undefined;
+            
+            return buffer;
+        },
+        
+        //------------------------------
+        //  Internal Methods
+        //------------------------------
+        
+        /**
+         *  Ensures the engine is in a stable state for transacting data.
+         *
+         *  @throws EX_UNSTABLE
+         */
+        __interruptAccess: function ()
+        {
+            if (!this.isReady)
+            {
+                throw EX_UNSTABLE;
+            }
+        },
+        
+        /**
+         *  Sets a property in the StorageEngine. This method should be overloaded to provide actual
+         *  storage flavor integration.
+         *
+         *  @param key      The key of the property.
+         *
+         *  @param value    The value of the property.
+         *
+         *  @return The new value of the property.
+         */
+        __set: function (key, value)
+        {
+            return;
+        },
+        
+        /**
+         *  Removes a property from the StorageEngine. This method should be overloaded to provide actual
+         *  storage flavor integration.
+         *
+         *  @param key  The property key of the data to remove.
+         *
+         *  @return The value of the property, before it was removed.
+         */
+        __remove: function (key)
+        {
+            return;
+        }
+        
+    });
+        
+    //------------------------------
+    //
+    //  jQuery Hooks
+    //
+    //------------------------------
+    
+    $.extend($.fn, {
+    
+        //------------------------------
+        //  Methods
+        //------------------------------
+    
+        /**
+         *  A combined getter/setter for the active engine.
+         *
+         *  @param key      The key of the property to get, or set.
+         *
+         *  @param value    If a valid value is provided, sets the engine.
+         *
+         *  @return jQuery
+         */
+        store: function (key, value)
+        {   
+            if (value === undefined)
+            {
+                _.get(key);
+            }
+            else
+            {
+                _.set(key, value);
+            }
+            
+            return this;
+        },
+        
+        /**
+         *  Remove a property from the active engine.
+         *
+         *  @param key  The key of the property to remove.
+         *
+         *  @return jQuery
+         */
+        removeStore: function (key)
+        {
+            _.activeEngine().remove(key);
+            
+            return this;
+        },
+        
+        /**
+         *  Get a property from the active engine.
+         *
+         *  @param key  The key of the property to get.
+         *
+         *  @return The value of the property.
+         */
+        getStore: function (key)
+        {
+            return _.activeEngine().get(key);
+        },
+        
+        /**
+         *  Set a property on the active engine.
+         *
+         *  @param key      The key of the property to set.
+         *
+         *  @param value    The value to set the property to.
+         *
+         *  @return jQuery
+         */
+        setStore: function (key, value)
+        {
+            _.activeEngine().set(key, value);
+            
+            return this;
+        }
+        
+    });
+    
+    //------------------------------
+    //
+    //  Event Bindings
+    //
+    //------------------------------
+    
+    //------------------------------
+    //
+    //  Startup Code
+    //
+    //------------------------------
+    
+    //------------------------------
+    //  Expose jStore through jQuery
+    //------------------------------
+    
+    window.jStore = $.jStore = _;
+    
+    //------------------------------
+    //
+    //  Engine Definitions
+    //
+    //------------------------------
+
+    //------------------------------
+    //  Local
+    //------------------------------
+    
+    define(FLAVOR_LOCAL, 
+    {
+        //------------------------------
+        //  Properties
+        //------------------------------
+        
+        limit: parseInt(5e5, 16),
+        
+        //------------------------------
+        //  Constructor
+        //------------------------------
+    
+        init: function (project, name)
+        {   
+            this.database = window.globalStorage === undefined ? window.localStorage : window.globalStorage[location.hostname];
+            
+            this._super(project, name);
+        },
+        
+        //------------------------------
+        //  Methods
+        //------------------------------
+        
+        updateCache: function ()
+        {
+            var key, value;
+        
+            for (key in this.database)
+            {
+                var has_key = false;
+                if (this.database.hasOwnProperty) {
+                    if (this.database.hasOwnProperty(key)) {
+                        has_key = true;
+                    }
+                } else { // IE 8
+                    if (this.database.getItem(key) !== null) {
+                        has_key = true;
+                    }
+                }
+                        
+                if (has_key) {
+                    value = this.database.getItem(key);
+            
+                    //  Gecko's getItem returns {value: 'the value'}, WebKit returns 'the value'
+                    this.data[key] = prepareForRevival(value && value.value ? value.value : value);
+                }
+            }
+            
+            this._super();
+        },
+        
+        //------------------------------
+        //  Internal methods
+        //------------------------------
+        
+        __set: function (key, value)
+        {
+            this.database.setItem(key, prepareForStorage(value));
+        },
+        
+        __remove: function (key)
+        {
+            this.database.removeItem(key);
+        }
+    },
+    
+    function ()
+    {
+        return window.localStorage !== undefined || window.globalStorage !== undefined;
+    });
+    
+    //------------------------------
+    //  SQL
+    //------------------------------
+    
+    define(FLAVOR_SQL, 
+    {
+        //------------------------------
+        //  Properties
+        //------------------------------
+        
+        limit: parseInt(32e3, 16),
+        
+        //------------------------------
+        //  Constructor
+        //------------------------------
+    
+        init: function (project, name)
+        {   
+            this.database = window.openDatabase('jstore-' + project, '1.0', project, this.limit);
+
+            if (!this.database)
+            {
+                throw 'JSTORE_SQL_NO_DB';
+            }
+            
+            this.database.transaction(function (database)
+            {
+                database.executeSql('CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)');
+            });
+            
+            this._super(project, name);
+        },
+        
+        //------------------------------
+        //  Methods
+        //------------------------------
+        
+        updateCache: function ()
+        {
+            var self = this,
+                _super = this._super;
+        
+            this.database.transaction(function (database)
+            {
+                database.executeSql('SELECT k,v FROM jstore', [], function (database, result)
+                {
+                    var rows = result.rows,
+                        index = 0,
+                        row;
+                        
+                    for (; index < rows.length; ++index)
+                    {
+                        row = rows.item(index);
+                        self.data[row.k] = prepareForRevival(row.v);
+                    }
+                    
+                    _super.apply(self);
+                });
+            });
+        },
+        
+        //------------------------------
+        //  Internal methods
+        //------------------------------
+        
+        __set: function (key, value)
+        {
+            this.database.transaction(function (database)
+            {
+                database.executeSql('INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)', [key, prepareForStorage(value)]);
+            });
+        },
+        
+        __remove: function (key)
+        {
+            this.database.transaction(function (database)
+            {
+                database.executeSql('DELETE FROM jstore WHERE k = ?', [key]);
+            });
+        }
+    }, 
+    
+    function ()
+    {
+        return window.openDatabase !== undefined;
+    });
+    
+    //------------------------------
+    //  Flash
+    //------------------------------
+    
+    define(FLAVOR_FLASH, 
+    {
+        //------------------------------
+        //  Properties
+        //------------------------------
+        
+        limit: -1,
+        
+        //------------------------------
+        //  Constructor
+        //------------------------------
+    
+        init: function (project, name)
+        {   
+            var self = this;
+        
+            _.bind('flash-ready', function ()
+            {
+                self.__flashReadyListener();
+            });
+            
+            this._super(project, name);
+        },
+        
+        //------------------------------
+        //  Methods
+        //------------------------------
+        
+        updateCache: function (enable)
+        {
+            /**
+             *  The default call to updateCache passes no variable, so we can short circuit the
+             *  ready state until we explictly call this after flash ready.
+             */
+            if (enable === true)
+            {
+                var key, 
+                    dataset = this.database.jstore_get_all();
+            
+                for (key in dataset)
+                {
+                    if (dataset.hasOwnProperty(key))
+                    {   
+                        this.data[key] = prepareForRevival(this.database.jstore_get(key));
+                    }
+                }
+            
+                this._super();
+            }
+        },
+        
+        //------------------------------
+        //  Internal methods
+        //------------------------------
+        
+        __set: function (key, value)
+        {
+            if (!this.database.jstore_set(key, prepareForStorage(value)))
+            {
+                _.trigger('jstore-error', ['JSTORE_STORAGE_FAILURE', this.jri, 'Flash Exception']);
+            }
+        },
+        
+        __remove: function (key)
+        {
+            this.database.jstore_remove(key);
+        },
+        
+        /**
+         *  Triggered whenever flash is ready.
+         */
+        __flashReadyListener: function ()
+        {
+            var iFrame = $('#jStoreFlashFrame')[0],
+                frameDocument;
+            
+            //  MSIE
+            if (iFrame.Document !== undefined && typecheck(iFrame.Document.jStoreFlash.jstore_get, 'Function'))
+            {
+                this.database = iFrame.Document.jStoreFlash;
+            }
+            
+            //  Real Browsers
+            else if (iFrame.contentWindow && iFrame.contentWindow.document)
+            {
+                frameDocument = $(iFrame.contentWindow.document);
+                
+                //  Webkit
+                if (typecheck($('object', frameDocument)[0].jstore_get, 'Function'))
+                {
+                    this.database = $('object', frameDocument)[0];
+                }
+                
+                //  Gecko
+                else if (typecheck($('embed', frameDocument)[0].jstore_get, 'Function'))
+                {
+                    this.database = $('embed', frameDocument)[0];
+                }
+            }
+            
+            if (this.database === undefined)
+            {
+                throw 'JSTORE_FLASH_REFERENCE_ISSUE';
+            }
+            else
+            {
+                this.updateCache(true);
+            }
+        }
+    }, 
+    
+    function ()
+    {
+        return hasFlashVersion('9.0.0');
+    });
+    
+    //------------------------------
+    //  Gears
+    //------------------------------
+    
+    define(FLAVOR_GEARS, 
+    {
+        //------------------------------
+        //  Properties
+        //------------------------------
+        
+        limit: -1,
+        
+        //------------------------------
+        //  Constructor
+        //------------------------------
+    
+        init: function (project, name)
+        {   
+            this.database = google.gears.factory.create('beta.database');
+            this.database.open('jstore-' + project);
+            this.database.execute('CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)');
+            
+            this._super(project, name);
+        },
+        
+        //------------------------------
+        //  Methods
+        //------------------------------
+        
+        updateCache: function ()
+        {
+            var result = this.database.execute('SELECT k,v FROM jstore');
+            
+            while (result.isValidRow())
+            {
+                this.data[result.field(0)] = prepareForRevival(result.field(1));
+                result.next();
+            }
+            
+            result.close();
+            
+            this._super();
+        },
+        
+        //------------------------------
+        //  Internal methods
+        //------------------------------
+        
+        __set: function (key, value)
+        {
+            this.database.execute('BEGIN');
+            this.database.execute('INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)', [key, prepareForStorage(value)]);
+            this.database.execute('COMMIT');
+        },
+        
+        __remove: function (key)
+        {
+            this.database.execute('BEGIN');
+            this.database.execute('DELETE FROM jstore WHERE k = ?', [key]);
+            this.database.execute('COMMIT');
+        }
+    }, 
+    
+    function ()
+    {
+        return window.google !== undefined && window.google.gears !== undefined;
+    });
+    
+    //------------------------------
+    //  MSIE
+    //------------------------------
+        
+    define(FLAVOR_MSIE, 
+    {
+        //------------------------------
+        //  Properties
+        //------------------------------
+        
+        limit: parseInt(1e4, 16),
+        
+        //------------------------------
+        //  Constructor
+        //------------------------------
+    
+        init: function (project, name)
+        {   
+            this.database = $('<div style="display:none;behavior:url(\'#default#userData\')" id="jstore-' + project + '"></div>')
+                .appendTo(document.body).get(0);
+            
+            this._super(project, name);
+        },
+        
+        //------------------------------
+        //  Methods
+        //------------------------------
+        
+        updateCache: function ()
+        {
+            this.database.load(this.project);
+            
+            var node = document.getElementById('jstore-' + this.project),
+                xmlDoc = node.XMLDocument,
+                root,
+                index = 0;
+                
+            if (xmlDoc && xmlDoc.documentElement && xmlDoc.documentElement.attributes)
+            {
+                root = xmlDoc.documentElement;
+                
+                for (; index < root.attributes.length; ++index)
+                {
+                    this.data[root.attributes.item(index).nodeName] = prepareForRevival(root.attributes.item(index).nodeValue);
+                }  
+            }
+            
+            this._super();
+        },
+        
+        //------------------------------
+        //  Internal methods
+        //------------------------------
+        
+        __set: function (key, value)
+        {
+            this.database.setAttribute(key, prepareForStorage(value));
+            this.database.save(this.project);
+        },
+        
+        __remove: function (key)
+        {
+            this.database.removeAttribute(key);
+            this.database.save(this.project);
+        }
+    }, 
+    
+    function ()
+    {
+        return window.ActiveXObject !== undefined;
+    });
+    
+}(jQuery, window));
diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/json2.js
--- a/static/scripts/json2.js	Fri Apr 09 13:02:15 2010 -0400
+++ b/static/scripts/json2.js	Fri Apr 09 18:09:54 2010 -0400
@@ -1,6 +1,6 @@
 /*
     http://www.JSON.org/json2.js
-    2009-06-29
+    2010-03-20
 
     Public Domain.
 
@@ -8,6 +8,14 @@
 
     See http://www.JSON.org/js.html
 
+
+    This code should be minified before deployment.
+    See http://javascript.crockford.com/jsmin.html
+
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+    NOT CONTROL.
+
+
     This file creates a global JSON object containing two methods: stringify
     and parse.
 
@@ -33,7 +41,7 @@
             value represented by the name/value pair that should be serialized,
             or undefined if nothing should be serialized. The toJSON method
             will be passed the key associated with the value, and this will be
-            bound to the object holding the key.
+            bound to the value
 
             For example, this would serialize Dates as ISO strings.
 
@@ -136,15 +144,9 @@
 
     This is a reference implementation. You are free to copy, modify, or
     redistribute.
-
-    This code should be minified before deployment.
-    See http://javascript.crockford.com/jsmin.html
-
-    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
-    NOT CONTROL.
 */
 
-/*jslint evil: true */
+/*jslint evil: true, strict: false */
 
 /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
     call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
@@ -153,10 +155,13 @@
     test, toJSON, toString, valueOf
 */
 
+
 // Create a JSON object only if one does not already exist. We create the
 // methods in a closure to avoid creating global variables.
 
-var JSON = JSON || {};
+if (!this.JSON) {
+    this.JSON = {};
+}
 
 (function () {
 
@@ -428,6 +433,7 @@
 // Unicode characters with escape sequences. JavaScript handles many characters
 // incorrectly, either silently deleting them, or treating them as line endings.
 
+            text = String(text);
             cx.lastIndex = 0;
             if (cx.test(text)) {
                 text = text.replace(cx, function (a) {
diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/packed/class.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/static/scripts/packed/class.js	Fri Apr 09 18:09:54 2010 -0400
@@ -0,0 +1,7 @@
+/*
+ *  Class definition
+ *
+ *  Copyright (c) 2008 John Resig (http://ejohn.org/blog/simple-javascript-inheritance/)
+ *  Inspired by base2 and Prototype
+ */
+"use strict";(function(){var a=false,b=/xyz/.test(function(){xyz})?/\b_super\b/:/.*/;this.Class=function(){};Class.extend=function(g){var f=this.prototype;a=true;var e=new this();a=false;for(var d in g){e[d]=(typeof g[d]==="function"&&typeof f[d]==="function"&&b.test(g[d])?(function(h,i){return function(){var k=this._super;this._super=f[h];var j=i.apply(this,arguments);this._super=k;return j}}(d,g[d])):g[d])}function c(){if(!a&&this.init){this.init.apply(this,arguments)}}c.prototype=e;c.constructor=c;c.extend=arguments.callee;return c}}());
\ No newline at end of file
diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/packed/galaxy.base.js
--- a/static/scripts/packed/galaxy.base.js	Fri Apr 09 13:02:15 2010 -0400
+++ b/static/scripts/packed/galaxy.base.js	Fri Apr 09 18:09:54 2010 -0400
@@ -1,1 +1,1 @@
-$(document).ready(function(){replace_big_select_inputs()});$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function ensure_popup_helper(){if($("#popup-helper").length===0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}function make_popupmen!
 u(c,b){ensure_popup_helper();var a=$("<ul id='"+c.attr("id")+"-menu'></ul>");$.each(b,function(f,e){if(e){$("<li/>").html(f).click(e).appendTo(a)}else{$("<li class='head'/>").html(f).appendTo(a)}});var d=$("<div class='popmenu-wrapper'>");d.append(a).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(c,d)}function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}else{if(e=="_top"){g=window.top}}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.addClass("popup").show()})}function array_length(b){if(b.length){return b.length}var c=0;for(var a in b){c++}return c}function replace_big_select_inputs(){$("select[name=dbkey]").each(function(){var a=$(this);if(a!
 .find("option").length<20){return}var b=a.attr("value");var c=$("<inpu
t type='text' class='text-and-autocomplete-select'></input>");c.attr("size",40);c.attr("name",a.attr("name"));c.click(function(){var g=$(this).attr("value");$(this).attr("value","Loading...");$(this).showAllInCache();$(this).attr("value",g);$(this).select()});var f=[];var e={};a.children("option").each(function(){var h=$(this).text();var g=$(this).attr("value");if(g=="?"){return}f.push(h);e[h]=g;e[g]=g;if(g==b){c.attr("value",h)}});if(c.attr("value")==""){c.attr("value","Click to Search or Select")}var d={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:1000,minChars:0,hideForLessThanMinChars:false};c.autocomplete(f,d);a.replaceWith(c);c.parents("form").submit(function(){var h=c.attr("value");var g=e[h];if(g!==null&&g!==undefined){c.attr("value",g)}else{if(b!=""){c.attr("value",b)}else{c.attr("value","?")}}})})}function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).live("click",function(){if($("#renaming-activ!
 e").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text(k)}else{j=$("<input type='text'></input>").attr({value:k,size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){l.text(o);if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}$(document).ready(function(){$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tipsy){$(".tooltip").tipsy({gravity:"s"})}make_popup_menus()});
\ No newline at end of file
+$(document).ready(function(){replace_big_select_inputs()});$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};function ensure_popup_helper(){if($("#popup-helper").length===0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}function make_popupmen!
 u(c,b){ensure_popup_helper();var a=$("<ul id='"+c.attr("id")+"-menu'></ul>");$.each(b,function(f,e){if(e){$("<li/>").html(f).click(e).appendTo(a)}else{$("<li class='head'/>").html(f).appendTo(a)}});var d=$("<div class='popmenu-wrapper'>");d.append(a).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(c,d)}function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}else{if(e=="_top"){g=window.top}}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.addClass("popup").show()})}function array_length(b){if(b.length){return b.length}var c=0;for(var a in b){c++}return c}function replace_big_select_inputs(){$("select[name=dbkey]").each(function(){var a=$(this);if(a!
 .find("option").length<20){return}var b=a.attr("value");var c=$("<inpu
t type='text' class='text-and-autocomplete-select'></input>");c.attr("size",40);c.attr("name",a.attr("name"));c.click(function(){var g=$(this).attr("value");$(this).attr("value","Loading...");$(this).showAllInCache();$(this).attr("value",g);$(this).select()});var f=[];var e={};a.children("option").each(function(){var h=$(this).text();var g=$(this).attr("value");if(g=="?"){return}f.push(h);e[h]=g;e[g]=g;if(g==b){c.attr("value",h)}});if(c.attr("value")==""){c.attr("value","Click to Search or Select")}var d={selectFirst:false,autoFill:false,mustMatch:false,matchContains:true,max:1000,minChars:0,hideForLessThanMinChars:false};c.autocomplete(f,d);a.replaceWith(c);c.parents("form").submit(function(){var h=c.attr("value");var g=e[h];if(g!==null&&g!==undefined){c.attr("value",g)}else{if(b!=""){c.attr("value",b)}else{c.attr("value","?")}}})})}function async_save_text(d,f,e,a,c,h,i,g,b){if(c===undefined){c=30}if(i===undefined){i=4}$("#"+d).live("click",function(){if($("#renaming-activ!
 e").length>0){return}var l=$("#"+f),k=l.text(),j;if(h){j=$("<textarea></textarea>").attr({rows:i,cols:c}).text(k)}else{j=$("<input type='text'></input>").attr({value:k,size:c})}j.attr("id","renaming-active");j.blur(function(){$(this).remove();l.show();if(b){b(j)}});j.keyup(function(n){if(n.keyCode===27){$(this).trigger("blur")}else{if(n.keyCode===13){var m={};m[a]=$(this).val();$(this).trigger("blur");$.ajax({url:e,data:m,error:function(){alert("Text editing for elt "+f+" failed")},success:function(o){l.text(o);if(b){b(j)}}})}}});if(g){g(j)}l.hide();j.insertAfter(l);j.focus();j.select();return})}function init_history_items(c,a){var b=function(){try{var d=$.jStore.store("history_expand_state");if(d){for(var f in d){$("#"+f+" div.historyItemBody").show()}}}catch(e){$.jStore.remove("history_expand_state")}if($.browser.mozilla){$("div.historyItemBody").each(function(){if(!$(this).is(":visible")){$(this).find("pre.peek").css("overflow","hidden")}})}c.each(function(){var i=this.i!
 d;var g=$(this).children("div.historyItemBody");var h=g.find("pre.peek
");$(this).children(".historyItemTitleBar").find(".historyItemTitle").wrap("<a href='#'></a>").click(function(){if(g.is(":visible")){if($.browser.mozilla){h.css("overflow","hidden")}g.slideUp("fast");if(!a){var j=$.jStore.store("history_expand_state");if(j){delete j[i];$.jStore.store("history_expand_state",j)}}}else{g.slideDown("fast",function(){if($.browser.mozilla){h.css("overflow","auto")}});if(!a){var j=$.jStore.store("history_expand_state");if(j===undefined){j={}}j[i]=true;$.jStore.store("history_expand_state",j)}}return false})});$("#top-links > a.toggle").click(function(){var g=$.jStore.store("history_expand_state");if(g===undefined){g={}}$("div.historyItemBody:visible").each(function(){if($.browser.mozilla){$(this).find("pre.peek").css("overflow","hidden")}$(this).slideUp("fast");if(g){delete g[$(this).parent().attr("id")]}});$.jStore.store("history_expand_state",g)}).show()};if(a){b()}else{$.jStore.init("galaxy");$.jStore.engineReady(function(){b()})}}$(document).re!
 ady(function(){$("a[confirm]").click(function(){return confirm($(this).attr("confirm"))});if($.fn.tipsy){$(".tooltip").tipsy({gravity:"s"})}make_popup_menus()});
\ No newline at end of file
diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/packed/jquery.jstore-all.js
--- a/static/scripts/packed/jquery.jstore-all.js	Fri Apr 09 13:02:15 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-(function(){var a=false,b=/xyz/.test(function(){xyz})?/\b_super\b/:/.*/;this.Class=function(){};Class.extend=function(g){var f=this.prototype;a=true;var e=new this();a=false;for(var d in g){e[d]=typeof g[d]=="function"&&typeof f[d]=="function"&&b.test(g[d])?(function(h,i){return function(){var k=this._super;this._super=f[h];var j=i.apply(this,arguments);this._super=k;return j}})(d,g[d]):g[d]}function c(){if(!a&&this.init){this.init.apply(this,arguments)}}c.prototype=e;c.constructor=c;c.extend=arguments.callee;return c}})();(function(a){this.jStoreDelegate=Class.extend({init:function(b){this.parent=b;this.callbacks={}},bind:function(b,c){if(!a.isFunction(c)){return this}if(!this.callbacks[b]){this.callbacks[b]=[]}this.callbacks[b].push(c);return this},trigger:function(){var d=this.parent,c=[].slice.call(arguments),e=c.shift(),b=this.callbacks[e];if(!b){return false}a.each(b,function(){this.apply(d,c)});return this}})})(jQuery);(function(a){a.jStore={};a.extend(a.jStore,{Engi!
 neOrder:[],Availability:{},Engines:{},Instances:{},CurrentEngine:null,defaults:{project:null,engine:null,autoload:true,flash:"jStore.Flash.html"},isReady:false,isFlashReady:false,delegate:new jStoreDelegate(a.jStore).bind("jStore-ready",function(b){a.jStore.isReady=true;if(a.jStore.defaults.autoload){b.connect()}}).bind("flash-ready",function(){a.jStore.isFlashReady=true})});a.jStore.ready=function(b){if(a.jStore.isReady){b.apply(a.jStore,[a.jStore.CurrentEngine])}else{a.jStore.delegate.bind("jStore-ready",b)}};a.jStore.fail=function(b){a.jStore.delegate.bind("jStore-failure",b)};a.jStore.flashReady=function(b){if(a.jStore.isFlashReady){b.apply(a.jStore,[a.jStore.CurrentEngine])}else{a.jStore.delegate.bind("flash-ready",b)}};a.jStore.use=function(d,g,c){g=g||a.jStore.defaults.project||location.hostname.replace(/\./g,"-")||"unknown";var f=a.jStore.Engines[d.toLowerCase()]||null,b=(c?c+".":"")+g+"."+d;if(!f){throw"JSTORE_ENGINE_UNDEFINED"}f=new f(g,b);if(a.jStore.Instances[b]!
 ){throw"JSTORE_JRI_CONFLICT"}if(f.isAvailable()){a.jStore.Instances[b]
=f;if(!a.jStore.CurrentEngine){a.jStore.CurrentEngine=f}a.jStore.delegate.trigger("jStore-ready",f)}else{if(!f.autoload){throw"JSTORE_ENGINE_UNAVILABLE"}else{f.included(function(){if(this.isAvailable()){a.jStore.Instances[b]=this;if(!a.jStore.CurrentEngine){a.jStore.CurrentEngine=this}a.jStore.delegate.trigger("jStore-ready",this)}else{a.jStore.delegate.trigger("jStore-failure",this)}}).include()}}};a.jStore.setCurrentEngine=function(b){if(!a.jStore.Instances.length){return a.jStore.FindEngine()}if(!b&&a.jStore.Instances.length>=1){a.jStore.delegate.trigger("jStore-ready",a.jStore.Instances[0]);return a.jStore.CurrentEngine=a.jStore.Instances[0]}if(b&&a.jStore.Instances[b]){a.jStore.delegate.trigger("jStore-ready",a.jStore.Instances[b]);return a.jStore.CurrentEngine=a.jStore.Instances[b]}throw"JSTORE_JRI_NO_MATCH"};a.jStore.FindEngine=function(){a.each(a.jStore.EngineOrder,function(b){if(a.jStore.Availability[this]()){a.jStore.use(this,a.jStore.defaults.project,"default");re!
 turn false}})};a.jStore.store=function(b,c){if(!a.jStore.CurrentEngine){return false}if(!c){return a.jStore.CurrentEngine.get(b)}return a.jStore.CurrentEngine.set(b,c)};a.jStore.remove=function(b){if(!a.jStore.CurrentEngine){return false}return a.jStore.CurrentEngine.rem(b)};a.fn.store=function(c,d){if(!a.jStore.CurrentEngine){return this}var b=a.jStore.store(c,d);return !d?b:this};a.fn.removeStore=function(b){a.jStore.remove(b);return this};a.jStore.load=function(){if(a.jStore.defaults.engine){return a.jStore.use(a.jStore.defaults.engine,a.jStore.defaults.project,"default")}try{a.jStore.FindEngine()}catch(b){}}})(jQuery);(function(a){this.StorageEngine=Class.extend({init:function(c,b){this.project=c;this.jri=b;this.data={};this.limit=-1;this.includes=[];this.delegate=new jStoreDelegate(this).bind("engine-ready",function(){this.isReady=true}).bind("engine-included",function(){this.hasIncluded=true});this.autoload=false;this.isReady=false;this.hasIncluded=false},include:func!
 tion(){var b=this,d=this.includes.length,c=0;a.each(this.includes,func
tion(){a.ajax({type:"get",url:this,dataType:"script",cache:true,success:function(){c++;if(c==d){b.delegate.trigger("engine-included")}}})})},isAvailable:function(){return false},ready:function(b){if(this.isReady){b.apply(this)}else{this.delegate.bind("engine-ready",b)}return this},included:function(b){if(this.hasIncluded){b.apply(this)}else{this.delegate.bind("engine-included",b)}return this},get:function(b){return this.data[b]||null},set:function(b,c){this.data[b]=c;return c},rem:function(b){var c=this.data[b];this.data[b]=null;return c}})})(jQuery);(function(c){var b=c.jStore.Availability.session=function(){return !!window.sessionStorage},a=c.jStore.Availability.local=function(){return !!(window.localStorage||window.globalStorage)};this.jStoreDom=StorageEngine.extend({init:function(e,d){this._super(e,d);this.type="DOM";this.limit=5*1024*1024},connect:function(){this.delegate.trigger("engine-ready")},get:function(e){var d=this.db.getItem(e);return d&&d.value?d.value:d},set:!
 function(d,e){this.db.setItem(d,e);return e},rem:function(e){var d=this.get(e);this.db.removeItem(e);return d}});this.jStoreLocal=jStoreDom.extend({connect:function(){this.db=!window.globalStorage?window.localStorage:window.globalStorage[location.hostname];this._super()},isAvailable:a});this.jStoreSession=jStoreDom.extend({connect:function(){this.db=sessionStorage;this._super()},isAvailable:b});c.jStore.Engines.local=jStoreLocal;c.jStore.Engines.session=jStoreSession;c.jStore.EngineOrder[1]="local"})(jQuery);(function(b){var a=b.jStore.Availability.flash=function(){return !!(b.jStore.hasFlash("8.0.0"))};this.jStoreFlash=StorageEngine.extend({init:function(e,d){this._super(e,d);this.type="Flash";var c=this;b.jStore.flashReady(function(){c.flashReady()})},connect:function(){var c="jstore-flash-embed-"+this.project;b(document.body).append('<iframe style="height:1px;width:1px;position:absolute;left:0;top:0;margin-left:-100px;" id="jStoreFlashFrame" src="'+b.jStore.defaults.flas!
 h+'"></iframe>')},flashReady:function(f){var c=b("#jStoreFlashFrame")[
0];if(c.Document&&b.isFunction(c.Document.jStoreFlash.f_get_cookie)){this.db=c.Document.jStoreFlash}else{if(c.contentWindow&&c.contentWindow.document){var d=c.contentWindow.document;if(b.isFunction(b("object",b(d))[0].f_get_cookie)){this.db=b("object",b(d))[0]}else{if(b.isFunction(b("embed",b(d))[0].f_get_cookie)){this.db=b("embed",b(d))[0]}}}}if(this.db){this.delegate.trigger("engine-ready")}},isAvailable:a,get:function(d){var c=this.db.f_get_cookie(d);return c=="null"?null:c},set:function(c,d){this.db.f_set_cookie(c,d);return d},rem:function(c){var d=this.get(c);this.db.f_delete_cookie(c);return d}});b.jStore.Engines.flash=jStoreFlash;b.jStore.EngineOrder[2]="flash";b.jStore.hasFlash=function(c){var e=b.jStore.flashVersion().match(/\d+/g),f=c.match(/\d+/g);for(var d=0;d<3;d++){e[d]=parseInt(e[d]||0);f[d]=parseInt(f[d]||0);if(e[d]<f[d]){return false}if(e[d]>f[d]){return true}}return true};b.jStore.flashVersion=function(){try{try{var c=new ActiveXObject("ShockwaveFlash.Shock!
 waveFlash.6");try{c.AllowScriptAccess="always"}catch(d){return"6,0,0"}}catch(d){}return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version").replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}catch(d){try{if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){return(navigator.plugins["Shockwave Flash 2.0"]||navigator.plugins["Shockwave Flash"]).description.replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}}catch(d){}}return"0,0,0"}})(jQuery);function flash_ready(){$.jStore.delegate.trigger("flash-ready")}(function(b){var a=b.jStore.Availability.gears=function(){return !!(window.google&&window.google.gears)};this.jStoreGears=StorageEngine.extend({init:function(d,c){this._super(d,c);this.type="Google Gears";this.includes.push("http://code.google.com/apis/gears/gears_init.js");this.autoload=true},connect:function(){var c=this.db=google.gears.factory.create("beta.database");c.open("jstore-"+this.project);c.execute("CREATE TABLE IF NOT EXISTS jstore (k TEX!
 T UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)");this.updateCache()},
updateCache:function(){var c=this.db.execute("SELECT k,v FROM jstore");while(c.isValidRow()){this.data[c.field(0)]=c.field(1);c.next()}c.close();this.delegate.trigger("engine-ready")},isAvailable:a,set:function(d,e){var c=this.db;c.execute("BEGIN");c.execute("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[d,e]);c.execute("COMMIT");return this._super(d,e)},rem:function(d){var c=this.db;c.execute("BEGIN");c.execute("DELETE FROM jstore WHERE k = ?",[d]);c.execute("COMMIT");return this._super(d)}});b.jStore.Engines.gears=jStoreGears;b.jStore.EngineOrder[3]="gears"})(jQuery);(function(b){var a=b.jStore.Availability.html5=function(){return !!window.openDatabase};this.jStoreHtml5=StorageEngine.extend({init:function(d,c){this._super(d,c);this.type="HTML5";this.limit=1024*200},connect:function(){var c=this.db=openDatabase("jstore-"+this.project,"1.0",this.project,this.limit);if(!c){throw"JSTORE_ENGINE_HTML5_NODB"}c.transaction(function(d){d.executeSql("CREATE TABLE IF NOT EXISTS!
  jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)")});this.updateCache()},updateCache:function(){var c=this;this.db.transaction(function(d){d.executeSql("SELECT k,v FROM jstore",[],function(f,e){var h=e.rows,g=0,j;for(;g<h.length;++g){j=h.item(g);c.data[j.k]=j.v}c.delegate.trigger("engine-ready")})})},isAvailable:a,set:function(c,d){this.db.transaction(function(e){e.executeSql("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[c,d])});return this._super(c,d)},rem:function(c){this.db.transaction(function(d){d.executeSql("DELETE FROM jstore WHERE k = ?",[c])});return this._super(c)}});b.jStore.Engines.html5=jStoreHtml5;b.jStore.EngineOrder[0]="html5"})(jQuery);(function(b){var a=b.jStore.Availability.ie=function(){return !!window.ActiveXObject};this.jStoreIE=StorageEngine.extend({init:function(d,c){this._super(d,c);this.type="IE";this.limit=64*1024},connect:function(){this.db=b('<div style="display:none;behavior:url(\'#default#userData\')" id="jstore-'+this.proj!
 ect+'"></div>').appendTo(document.body).get(0);this.delegate.trigger("
engine-ready")},isAvailable:a,get:function(c){this.db.load(this.project);return this.db.getAttribute(c)},set:function(c,d){this.db.setAttribute(c,d);this.db.save(this.project);return d},rem:function(c){var d=this.get(c);this.db.removeAttribute(c);this.db.save(this.project);return d}});b.jStore.Engines.ie=jStoreIE;b.jStore.EngineOrder[4]="ie"})(jQuery);
\ No newline at end of file
diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/packed/jquery.jstore.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/static/scripts/packed/jquery.jstore.js	Fri Apr 09 18:09:54 2010 -0400
@@ -0,0 +1,17 @@
+/*
+ *  jStore 2.0 - Persistent Client Side Storage
+ *
+ *  Copyright (c) 2010 Eric Garside (http://eric.garside.name/)
+ *  Dual licensed under:
+ *      MIT: http://www.opensource.org/licenses/mit-license.php
+ *      GPLv3: http://www.opensource.org/licenses/gpl-3.0.html
+ *
+ *  ---------------------------
+ *
+ *  jStore Flash Storage Component
+ *
+ *  Copyright (c) 2006 Jeff Lerman (jeff at blip.tv)
+ *  Licensed under the Creative Commons Attribution 3.0 United States License:
+ *      http://creativecommons.org/licenses/by/3.0/us
+ */
+"use strict";(function(i,n){var h="JSTORE_ENGINE_UNSTABLE",t="JSTORE_UNKNOWN_ENGINE_REQUESTED",r="JSTORE_ENGINE_NAMESPACE_COLLISION",j="JSTORE_RESOURCE_NAMESPACE_COLLISION",m="JSTORE_ENGINE_UNAVAILABLE",o="JSTORE_INVALID_FLAVOR",f=(function(){try{return new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$')}catch(I){return(/^(true|false|null|\[.*\]|\{.*\}|".*"|\d+|\d+\.\d+)$/)}}()),b="jstore-html5-local",y="jstore-html5-sql",F="jstore-flash",G="jstore-google-gears",A="jstore-msie",u,E={},D={},C={},c=false,d={},q={project:undefined,flash:"jStore.Flash.html",json:"browser.json.js"},l;function z(I){switch(I){case b:case y:case F:case G:case A:return true;default:return false}}function g(I,J){return !I?false:I.constructor.toString().match(new RegExp(J+"\\(\\)","i"))!==null}function s(K,I,J){if(g(K,"Function")){return K.apply(I||E,g(J,"Array")?J:[J])}}function p(J,I){i.ajax({url:J,complete:I||i.noop(),type:"GET",dataType:"script",cache:false})}fun!
 ction x(I){if(I===undefined){return""}if(g(I,"Object")||g(I,"Array")||g(I,"Function")){return JSON.stringify(I)}return I}function k(I){return f.test(I)?JSON.parse(I):I}function w(I){return I.replace(/^\s+|\s+$/g,"")}function e(I,J,K){if(!z(I)){throw o}if(K[I]!==undefined){throw r}if(s(K)===true){E.available[I]=true;J.flavor=I;D[I]=u.extend(J)}else{E.available[I]=false;E.enginePriority=i.map(E.enginePriority,function(L){if(L===I){return null}else{return L}})}}function v(){if(E.isReady){return}if((c&&E.isFlashReady)||!c){E.isReady=true;E.trigger("jstore-ready",[C[l]])}}function a(){E.create(E.enginePriority[0],undefined,"best-fit")}function H(){try{var J=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");try{J.AllowScriptAccess="always"}catch(L){return"6,0,0"}return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version").replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}catch(K){try{if(navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){return(na!
 vigator.plugins["Shockwave Flash 2.0"]||navigator.plugins["Shockwave F
lash"]).description.replace(/\D+/g,",").match(/^,?(.+),?$/)[1]}}catch(I){}}return"0,0,0"}function B(I){var N=H().match(/\d+/g),L=I.match(/\d+/g),J=0,K,M;for(;J<3;J++){K=parseInt(N[J],10);M=parseInt(L[J],10);if(K<M){return false}else{if(K>M){return true}}}return true}i.extend(E,{enginePriority:[b,y,F,A],available:{},isReady:false,isFlashReady:false,flavors:{local:b,sql:y,flash:F,gears:G,msie:A},init:function(J,K,I){i.extend(q,{project:J},K);i(function(){if(n.JSON===undefined){p(q.json)}if(I!==undefined){E.create(I,J,"default")}else{a()}});return E},create:function(I,M,J){M=M||q.project||location.hostname.replace(/\./g,"-")||"unknown";if(!z(I)){throw o}if(D[I]===undefined){throw m}var L=(J!==undefined?J+".":"")+M+"."+I,K;if(C[L]!==undefined){throw j}K=C[L]=new D[I](M,L);K.ready(function(){E.trigger("jstore-engine-ready",[K])});if(I===F&&!E.isFlashReady){if(l===undefined){c=true}n.jstore_ready=function(){E.isFlashReady=true;E.trigger("flash-ready");if(l===undefined){v()}n.flash!
 _ready=undefined};n.jstore_error=function(N){E.trigger("jstore-error",["JSTORE_FLASH_EXCEPTION",null,N])};i('<iframe style="height:1px;width:1px;position:absolute;left:0;top:0;margin-left:-100px;" id="jStoreFlashFrame" src="'+q.flash+'"></iframe>').appendTo("body")}else{if(l===undefined){l=L;v()}}return K},engine:function(I){return C[I]},activeEngine:function(I){if(I!==undefined){if(C[I]===undefined){throw t}else{l=I}}return C[l]},bind:function(J,K,I){I=I||"jstore";if(d[I]===undefined){d[I]={}}if(d[I][J]===undefined){d[I][J]=[K]}else{d[I][J].push(K)}return E},trigger:function(K,J,I){I=I||"jstore";if(d[I]!==undefined){if(d[I][K]!==undefined){i.each(d[I][K],function(){s(this,E,J)})}}return E},error:function(I){E.bind("jstore-error",I)},ready:function(I){if(E.isReady){s(I)}else{E.bind("jstore-ready",I)}return E},engineReady:function(I){if(E.isReady){s(I)}else{E.bind("jstore-engine-ready",I)}return E},store:function(I,J){return J===undefined?E.get(I):E.set(I,J)},remove:function!
 (I){return E.activeEngine().remove(I)},get:function(I){return E.active
Engine().get(I)},set:function(I,J){return E.activeEngine().set(I,J)}});u=Class.extend({project:undefined,jri:undefined,flavor:undefined,database:undefined,data:undefined,limit:undefined,isReady:undefined,init:function(J,I){this.project=J;this.jri=I;this.data={};this.isReady=false;this.updateCache()},updateCache:function(){this.isReady=true;this.trigger("engine-ready",[this])},bind:function(I,J){E.bind(I,J,this.jri)},trigger:function(J,I){E.trigger(J,I,this.jri)},ready:function(I){if(this.isReady){s(I,this)}else{this.bind("engine-ready",I)}},get:function(I){this.__interruptAccess();return this.data[I]},set:function(I,J){this.__interruptAccess();I=w(I);try{this.__set(I,J)}catch(K){E.trigger("jstore-error",["JSTORE_STORAGE_FAILURE",this.jri,K])}this.data[I]=J;return J},remove:function(J){this.__interruptAccess();J=w(J);try{this.__remove(J)}catch(K){E.trigger("jstore-error",["JSTORE_REMOVE_FAILURE",this.jri,K])}var I=this.data[J];this.data[J]=undefined;return I},__interruptAcces!
 s:function(){if(!this.isReady){throw h}},__set:function(I,J){return},__remove:function(I){return}});i.extend(i.fn,{store:function(I,J){if(J===undefined){E.get(I)}else{E.set(I,J)}return this},removeStore:function(I){E.activeEngine().remove(I);return this},getStore:function(I){return E.activeEngine().get(I)},setStore:function(I,J){E.activeEngine().set(I,J);return this}});n.jStore=i.jStore=E;e(b,{limit:parseInt(500000,16),init:function(J,I){this.database=n.globalStorage===undefined?n.localStorage:n.globalStorage[location.hostname];this._super(J,I)},updateCache:function(){var J,K;for(J in this.database){var I=false;if(this.database.hasOwnProperty){if(this.database.hasOwnProperty(J)){I=true}}else{if(this.database.getItem(J)!==null){I=true}}if(I){K=this.database.getItem(J);this.data[J]=k(K&&K.value?K.value:K)}}this._super()},__set:function(I,J){this.database.setItem(I,x(J))},__remove:function(I){this.database.removeItem(I)}},function(){return n.localStorage!==undefined||n.globalS!
 torage!==undefined});e(y,{limit:parseInt(32000,16),init:function(J,I){
this.database=n.openDatabase("jstore-"+J,"1.0",J,this.limit);if(!this.database){throw"JSTORE_SQL_NO_DB"}this.database.transaction(function(K){K.executeSql("CREATE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v TEXT NOT NULL)")});this._super(J,I)},updateCache:function(){var I=this,J=this._super;this.database.transaction(function(K){K.executeSql("SELECT k,v FROM jstore",[],function(O,L){var N=L.rows,M=0,P;for(;M<N.length;++M){P=N.item(M);I.data[P.k]=k(P.v)}J.apply(I)})})},__set:function(I,J){this.database.transaction(function(K){K.executeSql("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[I,x(J)])})},__remove:function(I){this.database.transaction(function(J){J.executeSql("DELETE FROM jstore WHERE k = ?",[I])})}},function(){return n.openDatabase!==undefined});e(F,{limit:-1,init:function(K,J){var I=this;E.bind("flash-ready",function(){I.__flashReadyListener()});this._super(K,J)},updateCache:function(I){if(I===true){var J,K=this.database.jstore_get_all();f!
 or(J in K){if(K.hasOwnProperty(J)){this.data[J]=k(this.database.jstore_get(J))}}this._super()}},__set:function(I,J){if(!this.database.jstore_set(I,x(J))){E.trigger("jstore-error",["JSTORE_STORAGE_FAILURE",this.jri,"Flash Exception"])}},__remove:function(I){this.database.jstore_remove(I)},__flashReadyListener:function(){var I=i("#jStoreFlashFrame")[0],J;if(I.Document!==undefined&&g(I.Document.jStoreFlash.jstore_get,"Function")){this.database=I.Document.jStoreFlash}else{if(I.contentWindow&&I.contentWindow.document){J=i(I.contentWindow.document);if(g(i("object",J)[0].jstore_get,"Function")){this.database=i("object",J)[0]}else{if(g(i("embed",J)[0].jstore_get,"Function")){this.database=i("embed",J)[0]}}}}if(this.database===undefined){throw"JSTORE_FLASH_REFERENCE_ISSUE"}else{this.updateCache(true)}}},function(){return B("9.0.0")});e(G,{limit:-1,init:function(J,I){this.database=google.gears.factory.create("beta.database");this.database.open("jstore-"+J);this.database.execute("CREA!
 TE TABLE IF NOT EXISTS jstore (k TEXT UNIQUE NOT NULL PRIMARY KEY, v T
EXT NOT NULL)");this._super(J,I)},updateCache:function(){var I=this.database.execute("SELECT k,v FROM jstore");while(I.isValidRow()){this.data[I.field(0)]=k(I.field(1));I.next()}I.close();this._super()},__set:function(I,J){this.database.execute("BEGIN");this.database.execute("INSERT OR REPLACE INTO jstore(k, v) VALUES (?, ?)",[I,x(J)]);this.database.execute("COMMIT")},__remove:function(I){this.database.execute("BEGIN");this.database.execute("DELETE FROM jstore WHERE k = ?",[I]);this.database.execute("COMMIT")}},function(){return n.google!==undefined&&n.google.gears!==undefined});e(A,{limit:parseInt(10000,16),init:function(J,I){this.database=i('<div style="display:none;behavior:url(\'#default#userData\')" id="jstore-'+J+'"></div>').appendTo(document.body).get(0);this._super(J,I)},updateCache:function(){this.database.load(this.project);var K=document.getElementById("jstore-"+this.project),L=K.XMLDocument,I,J=0;if(L&&L.documentElement&&L.documentElement.attributes){I=L.document!
 Element;for(;J<I.attributes.length;++J){this.data[I.attributes.item(J).nodeName]=k(I.attributes.item(J).nodeValue)}}this._super()},__set:function(I,J){this.database.setAttribute(I,x(J));this.database.save(this.project)},__remove:function(I){this.database.removeAttribute(I);this.database.save(this.project)}},function(){return n.ActiveXObject!==undefined})}(jQuery,window));
\ No newline at end of file
diff -r a9402fc7ce1b -r 5536d57237a3 static/scripts/packed/json2.js
--- a/static/scripts/packed/json2.js	Fri Apr 09 13:02:15 2010 -0400
+++ b/static/scripts/packed/json2.js	Fri Apr 09 18:09:54 2010 -0400
@@ -1,1 +1,1 @@
-var JSON=JSON||{};(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0!
 ).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=st!
 r(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.
length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test!
 (text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());
\ No newline at end of file
+if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.ch!
 arCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(valu!
 e,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}
v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-!
 4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());
\ No newline at end of file
diff -r a9402fc7ce1b -r 5536d57237a3 templates/display_base.mako
--- a/templates/display_base.mako	Fri Apr 09 13:02:15 2010 -0400
+++ b/templates/display_base.mako	Fri Apr 09 18:09:54 2010 -0400
@@ -32,29 +32,25 @@
 
 <%def name="javascripts()">
     ${parent.javascripts()}
-    ${h.js( "jquery", "jquery.tipsy", "galaxy.base", "json2", "jquery.autocomplete", "jquery.jstore-all", "autocomplete_tagging" )}
+    ${h.js( "jquery", "jquery.tipsy", "galaxy.base", "json2", "class", "jquery.jstore", "jquery.autocomplete", "autocomplete_tagging" )}
 
     <script type="text/javascript">
-        //
+        
         // Handle click on community tag.
-        //
-        function community_tag_click(tag_name, tag_value) 
-        {
+        function community_tag_click(tag_name, tag_value) {
             <% controller_name = get_controller_name( item ) %>
             var href = '${h.url_for ( controller='/' + controller_name , action='list_published')}';
             href = href + "?f-tags=" + tag_name;
-            if (tag_value != undefined && tag_value != "")
+            if (tag_value != undefined && tag_value != "") {
                 href = href + ":" + tag_value;
+            }
             self.location = href;
         }
         
-        $(document).ready( function() 
-        {
+        $(function() {
             // Set links to Galaxy screencasts to open in overlay.
-            $(this).find("a[href^='http://screencast.g2.bx.psu.edu/']").each( function() 
-            {
-                $(this).click( function() 
-                {
+            $(this).find("a[href^='http://screencast.g2.bx.psu.edu/']").each( function() {
+                $(this).click( function() {
                     var href = $(this).attr('href');
                     show_in_overlay(
                         {
@@ -67,7 +63,8 @@
                     return false;
                 });
             });
-        
+            // Init history boxes
+            init_history_items( $("div.historyItemWrapper") );
         });    
     </script>
 </%def>
@@ -76,14 +73,12 @@
     ${parent.stylesheets()}
     ${h.css( "autocomplete_tagging", "embed_item" )}
     <style type="text/css">
-        .page-body
-        {
+        .page-body {
             padding: 10px;
             ## float: left;
             ## width: 65%;
         }
-        .page-meta
-        {
+        .page-meta {
             float: right;
             width: 27%;
             padding: 0.5em;
diff -r a9402fc7ce1b -r 5536d57237a3 templates/history/display.mako
--- a/templates/history/display.mako	Fri Apr 09 13:02:15 2010 -0400
+++ b/templates/history/display.mako	Fri Apr 09 18:09:54 2010 -0400
@@ -1,207 +1,14 @@
 <%inherit file="/display_base.mako"/>
 <%namespace file="/root/history_common.mako" import="render_dataset" />
 
+## Set vars so that there's no need to change the code below.
+<% 
+    history = published_item 
+    datasets = published_item_data
+%>
+
 <%def name="javascripts()">
     ${parent.javascripts()}
-    ${h.js( "jquery.jstore-all" )}
-    
-    ## Set vars so that there's no need to change the code below.
-    <% 
-        history = published_item 
-        datasets = published_item_data
-    %> 
-    
-    <script type="text/javascript">
-    $(function() {
-        // Load jStore for local storage
-        $.extend(jQuery.jStore.defaults, { project: 'galaxy', flash: '/static/jStore.Flash.html' })
-        $.jStore.load(); // Auto-select best storage


More information about the galaxy-dev mailing list