	/* Config
	--------------------------------------------------------*/
	var success_auto_hide_delay  = 3000;
	var global_transition        = 'expo:out';

	/* Utility Functions
	--------------------------------------------------------*/
	// Used to kill the go-to-top effect of clicking # links
	return_false = function () {
		// Fire any explicitly-defined onclick routines
		eval (this.get ('onclick'));
		return false;
	};

	/* Tweak some MooTools objects
	--------------------------------------------------------*/
	SAB_Request = new Class ({
		Extends: Request.HTML,
		initialize: function (options) {
			// Custom events
			this.addEvent ('onStatusSuccess', $pick (options.onStatusSuccess, function () {}));
			this.addEvent ('onStatusError', $pick (options.onError, function () {}));
			this.addEvent ('onStatusConfirm', $pick (options.onConfirm, function () {}));
			this.addEvent ('onDrawWindow', $pick (options.onDrawWindow, function () {}));

			// Tweak the 'url' property
			if (window.location.toString ().indexOf ('/buy') >= 0 && options.url.indexOf ('/buy') < 0) {
				options.url = '/buy' + options.url;
			}

			// Tweak default events
			this.addEvents ({
				onRequest: function () {
					show_loading_box ();
				},
				onComplete: function (responseTree, responseElements, responseHTML, responseJavaScript) {
					// Hide the loading box
					hide_loading_box ();

					// Some error checking
					if (!responseHTML) {
						this.fireEvent ('onFailure');
						return;
					}

					// JSON object?
					if (responseHTML.replace (/^\s+/ig, '').indexOf ('{') === 0)
					{
						// Turn it into an object
						result_obj = JSON.decode (responseHTML);

						// Auto hide prompts?
						var prompt_options = {};
						if (options.autoHidePrompts) {
							prompt_options = {
								'auto_hide_delay': success_auto_hide_delay
							}
						}

						switch (result_obj.status)
						{
							case 'success':
								shade_viewport (0);

								if (result_obj.url) {
									window.location = result_obj.url.toString ().replace (/\#/g, '');
								} else if (result_obj.message) {
									draw_prompt ('success', result_obj.message, prompt_options);
								}

								this.fireEvent ('onStatusSuccess', result_obj);
								break;

							case 'error':
								if (result_obj.message) {
									draw_prompt ('error', result_obj.message);
								}
								this.fireEvent ('onStatusError', result_obj);
								break;

							case 'confirm':
								draw_prompt ('confirm', result_obj.message, result_obj.options);
								this.fireEvent ('onStatusConfirm', result_obj);
								break;
						}
					}

					// HTML? Draw it into a faux window
					else
					{
						hide_loading_box ('See below...');

						// Draw the window
						var faux_window = draw_window (responseHTML);

						// Parse the HTML with standard sniffing functions
						parse_html (faux_window, this.options.button_options);

						// Fire the DrawWindow event
						this.fireEvent ('onDrawWindow', faux_window);
					}
				},
				onFailure: function (instance) {
					shade_viewport (0);
					hide_loading_box ();
					draw_prompt ('error', 'There was an error in making your request. Please try again. If the problem persists, please let us know!');
				}
			});

			this.parent (options);
		}
	});

	/* Faux Window Drawing
	--------------------------------------------------------*/
	var draw_window = function (html) {
		// Shade the viewport
		shade_viewport (0.7);

		// Get and stuff the faux window element
		var faux_window = $('faux_window');
		faux_window.set ('html', html);

		// Position it for display
		var faux_window_size = faux_window.getScrollSize ();
		faux_window.setStyles ({
			'margin-left': faux_window_size.x / 2 * -1,
			'margin-top': window.getScroll ().y + (faux_window_size.y / 2 * -1),
			'opacity': 1
		});

		// Set proper size of the H1
		faux_window.getElement ('h1').setStyle ('width', faux_window_size.x);

		// Enable the cancel button
		var cancel_button = faux_window.getElement ('a.cancel');
		if (cancel_button)
		{
			cancel_button.addEvent ('click', function () {
				rollup (faux_window);
				shade_viewport.pass (0).delay (750);
			}).onclick = return_false;
		}

		// Roll it Out
		rollout.pass (faux_window).delay (750);

		return faux_window;
	}

	/* Edition Picker
	--------------------------------------------------------*/
	// The edition picking onClick event handler for pick/add buttons
	pick_edition = function (pick_data) {
		var element = this;

		// This data gets thrown around more than once, so we'll store it here
		if ($type (pick_data) != 'object')
		{
			var pick_data = {
				'family_id': element.get ('href').match (/\#([0-9]+)/)[1],
				'action': element.hasClass ('pick') ? 'pick' : 'add',
				'service': element.getParent ('li').get ('class').match (/wish|rent|download|physically_purchase|digitally_purchase/)[0]
			};

			// Other arguments can be passed after the book_id;
			// IE: href="#123456_abridged
			var switches = element.get ('href').replace (/[^\#]*\#[0-9]+/, '').match (/_[^_]+/g);
			if (switches) {
				switches.each (function (element, index) {
					$extend (pick_data, JSON.decode ('{ ' + element.substr (1) + ': true }'));
				});
			}
		}

		// Send a flag when we're on the book details page
		if ($('editions') && $('editions').getElements ('.accordion_handle').length > 1) {
			pick_data.book_details_page = true;
		}

		// Make the request
		new SAB_Request ({
			url: '/edition_picker.php',
			method: 'get',
			data: pick_data,
			onRequest: function () {
				// Rollup the edition picker, if it's there
				var faux_window = $('faux_window');
				if (faux_window.getStyle ('height').toInt () > 0) {
					rollup (faux_window);
				}
			},
			autoHidePrompts: true,
			onStatusError: function (result_obj) {
				// Unfade viewport!
				shade_viewport (0);

				// Call custom event
				if (element.options && element.options.onStatusError) {
					element.options.onStatusError (result_obj, element);
				}
			},
			onStatusSuccess: function (result_obj) {
				// Any buttons that might try to perform the same action in the same
				// service need to be changed to the past tense (rent -> rented)
				// and turned into actual links that take them to the response's URL
				$$('.action_menu .' + result_obj.service +', .action_buttons .' + result_obj.service).each (function (element, index) {
					var a_obj = element.getElement ('a');
					var href_str = a_obj.get ('href');
					var family_or_book_id = parseInt (href_str.substr (href_str.lastIndexOf ('#') + 1));
					if (family_or_book_id != '' && ((result_obj.family_id && result_obj.family_id.indexOf (family_or_book_id) != -1) || (result_obj.book_id && result_obj.book_id.indexOf (family_or_book_id) != -1)))
					{
						// Switch the button class to "past tense" by adding "-ed".
						// IE: rent -> rented
						// Smart enough for: purchase -> purchased
						// New: Now smart enough for: rent rent_again -> rented
						element.set ('class', element.get ('class').replace (/\b(wish|rent|download|physically_purchase|digitally_purchase)\b/, '$1ed').replace ('eed', 'ed'));

						// No more clicky
						a_obj.removeEvents ('click');

						// Change the button's label, and turn it into a link
						if (result_obj.button_url && result_obj.label)
						{
							a_obj
								.removeClass ('pick')
								.removeClass ('add')
								.set ('href', result_obj.button_url)
								.set ('html', result_obj.label)
								.set ('title', result_obj.label)
								.onclick = null;
						}
					}
				});

				// If wish list addition was success, update the counter
				if (result_obj.service == 'wish') {
					var _ = $$('#user_nav_wishlist var');
					_.set ('html', parseInt (_.get ('html')) + 1);
				}

				// If buying, increase the cart counter
				if (result_obj.service == 'digitally_purchase' || result_obj.service == 'physically_purchase') {
					var _ = $$('#main_nav_cart var');
					_.set ('html', parseInt (_.get ('html')) + 1);
				}

				// CoreMetrics
				switch (result_obj.service) {
					// Rent
					case 'rent':
						cmCreateConversionEventTag ('Added book to rental shelf. FamilyID: ' + result_obj.family_id + ' BookID: ' + result_obj.book_id, '2');
						break;

					// Download
					case 'download':
						cmCreateConversionEventTag ('Used download credit. FamilyID: ' + result_obj.family_id + ' BookID: ' + result_obj.book_id, '2');
						break;

					// Wish List
					case 'wish':
						cmCreateConversionEventTag ('Added book to wish list. FamilyID: ' + result_obj.family_id + ' BookID: ' + result_obj.book_id, '2');
						break;
				}

				// Call custom event
				if (element.options && element.options.onStatusSuccess) {
					element.options.onStatusSuccess (result_obj, element);
				}
			},
			onStatusConfirm: function (result_obj) {
				var data = {
					'family_id': result_obj.family_id,
					'action': result_obj.action,
					'service': result_obj.service
				};

				draw_prompt ('confirm', result_obj.message, {
					'buttons': [
						{
							'label': 'Yes, and view my library',
							'handler': function () {
								pick_edition ($merge (data, {
									'confirmed': 'yes, library'
								}));
							}
						},
						{
							'label': 'Yes',
							'handler': function () {
								pick_edition ($merge (data, {
									'confirmed': 'yes'
								}));
							}
						},
						{
							'label': 'No',
							'handler': function () {
								// Unfade the viewport
								shade_viewport (0);

								// Hide the window
								rollup ($('faux_window'));
							}
						}
					]
				});

				// Call custom event
				if (element.options && element.options.onStatusConfirm) {
					element.options.onStatusConfirm (result_obj, element);
				}
			},
			onDrawWindow: function (faux_window) {
				// Adjust the position of the tables
				var starting_amount = $('IE') ? 20 : 1;

				// Line things up on load (cover image needs to load before we can really do this properly)
				faux_window.getElement ('.cover img').onload = function () {
					// Get heights
					var cover_height = faux_window.getElement ('.cover').getSize ().y.toInt ();
					var h2_height = faux_window.getElement ('h2').getSize ().y.toInt ();
					var h3_height = faux_window.getElement ('h3').getSize ().y.toInt ();

					// Find delta
					var delta = cover_height - h2_height - h3_height;

					// Subtract arbitrary browser difference
					delta -= 12;

					faux_window.getElement ('h3').setStyle ('border-bottom', delta + 'px solid white');
				};

				// Call custom event
				if (element.options && element.options.onDrawWindow) {
					element.options.onDrawWindow (faux_window, element);
				}
			}
		}).send ();
	};

	/* Review Writer
	--------------------------------------------------------*/
	var write_review = function () {
		var element = this;
		new SAB_Request ({
			url: '/rate_and_review_form.php',
			method: 'get',
			data: {
				'family_id': element.get ('href').substr (element.get ('href').lastIndexOf ('#') + 1)
			},
			onDrawWindow: function (faux_window) {
				// Review Toggling
				if ($('review_toggler'))
				{
					$('review_toggler').addEvent ('click', function () {
						faux_window.setStyle ('height', '');
						var review_toggler = this;
						var submit_button = faux_window.getElement ('tfoot input');
						var form_obj = faux_window.getElement ('form.ajax');
						autoroll (form_obj.getElement ('.nested_table_container div'), {
							'onRollOut': function (element) {
								review_toggler.set ('text', 'Cancel Review');
								submit_button.set ('value', 'Submit Rating & Review');
							},
							'onRollUp': function (element) {
								review_toggler.set ('text', 'Write Review');
								submit_button.set ('value', 'Submit Rating');
							},
							'onComplete': function (element) {
								var faux_window_size = faux_window.getScrollSize ();
								faux_window.tween ('margin-top', window.getScroll ().y + (faux_window_size.y / 2 * -1));
							}
						});
					});
				}
			}
		}).send ();
	};

	/* HTML-Parsing Routine
	--------------------------------------------------------*/
	var highlight_error_fields, clear_error_fields;
	var parse_html = function (parent_element, options) {
		/* Unique Links for Coremetrics
		--------------------------------------------------------*/
		// Compile a list of links
		var links = [], duplicate_links = [];
		parent_element.getElements ('a').each (function (element, index) {
			_href = element.get ('href');

			if (_href)
			{
				// Index the array on href to keep track of duplicates
				if (typeof links[_href] == 'undefined')
				{
					links[_href] = [];
				}
				else
				{
					duplicate_links.push (_href);
				}

				links[_href].push (element);
			}
		});

		// Adds a var=value to ANY link's query string (or adds the query string if necessary)
		add_query_string_argument = function (_href, var_name, var_value) {
			// Do NOTHING to internal links; we can't track them anyway
			// And mailto: links
			var actual_href = _href.replace (window.location.toString ().replace (/\#.*$/, ''), '');
			if (actual_href.indexOf ('mailto') >= 0 || actual_href.indexOf ('#') === 0)
			{
				return _href;
			}

			// Build the query string
			query_string = '?' + var_name + '=' + var_value + '&';

			// Keep the #blah for later, but delete it for now
			hashy_bit = (_href.indexOf ('#') >= 0) ? _href.match (/\#.*$/)[0] : '';
			_href = _href.replace (/\#.*$/, '');

			return _href.replace (/\?|$/, query_string) + hashy_bit;
		};

		// Go through duplicate links and tag them
		duplicate_links.each (function (_href) {
			links[_href].each (function (element, index) {
				element.set ('href', add_query_string_argument (_href, 'link_num', index + 1));
			});
		});

		/* Cover Tootlips
		--------------------------------------------------------*/
		// Attach events to covers
		parent_element.getElements ('.cover').each (function (element, index) {
			element.addEvent ('mouseover', describeCover);
			element.addEvent ('mouseout', undescribeCover);
		});

		/* Edition-Picking and Review-Writing Buttons
		--------------------------------------------------------*/
		// Select all .rent, .download, and .wish buttons
		parent_element.getElements ('.action_buttons, .action_menu, .item_actions, .write_review').each (function (element, index) {
			// Review Writer
			if (element.hasClass ('write_review') && element.getElement ('a')) {
				element.getElement ('a').addEvent ('click', write_review).onclick = return_false;
			}

			// Edition Picker
			else
			{
				element.getElements ('.rent, .download, .wish, .physically_purchase, .digitally_purchase').each (function (element, index) {
					var a_obj = element.getElement ('a.add, a.pick');
					if (a_obj)
					{
						a_obj.addEvent ('click', pick_edition).onclick = return_false;
					}
				});
			}
		});

		/* AJAX Forms
		--------------------------------------------------------*/
		// Remove all errors from a form
		clear_error_fields = function (form) {
			// Un-error everything
			form.getElements ('.error, .error_corrected').each (function (element, index) {
				element.removeClass ('error').removeClass ('error_corrected');
			});
		};

		// Used to highlight erroneous fields; intelligently decides which objects to
		// apply the 'error' classes to, and handles focus on correction and stuff.
		highlight_error_fields = function (fields) {
			clear_error_fields ($(fields[0]).getParent ('form'));

			// Add errors where they ought to be
			for (var i = 0; i < fields.length; i++)
			{
				target_obj = $(fields[i]);

				// By default, highlight the parent row
				highlight_target = 'tr';

				// If the field is contained inside a label, hightlight the parent cell
				if (target_obj.getParent ('label'))
				{
					highlight_target = 'td';
				}

				// Likewise, if there is a label sharing the same parent, highlight the cell
				// but make sure that label points to the field in question!
				adjacent_label = target_obj.getParent ().getElement ('label');
				if (adjacent_label && adjacent_label.get ('for') == fields[i])
				{
					highlight_target = 'td';
				}

				target_obj.highlighted_obj = target_obj.getParent (highlight_target);

				target_obj.highlighted_obj.addClass ('error');

				target_obj.addEvent ('focus', function () {
					if (this.highlighted_obj.hasClass ('error'))
					{
						this.highlighted_obj.removeClass ('error');
						this.highlighted_obj.addClass ('error_corrected');
					}
				});
			}
		};

		parent_element.getElements ('form.ajax').each (function (form_obj, index) {
			form_obj.getElements ('input[type="submit"]').each (function (old_button, index) {
				button = new Element ('input', {
					'type': 'button',
					'value': old_button.get ('value'),
					'class': old_button.get ('class'),
					'id': old_button.get ('id')
				});
				button.replaces (old_button);
				button.addEvent ('click', function () {
					new SAB_Request ({
						'url': form_obj.get ('action'),
						'method': form_obj.get ('method'),
						'data': form_obj,
						'onStatusSuccess': function (result_obj) {
							// Hide the faux window
							rollup ($('faux_window'));

							// Call custom event
							if (form_obj.options && form_obj.options.onStatusSuccess) {
								form_obj.options.onStatusSuccess (result_obj);
							}
						},
						'onStatusError': function (result_obj) {
							// Highlight all errored fields
							highlight_error_fields (result_obj.highlight);

							// Call custom event
							if (form_obj.options && form_obj.options.onStatusError) {
								form_obj.options.onStatusError (result_obj);
							}
						}
					}).send ();
				}).onclick = return_false;
			});
		});

		/* Embedded Prompts
		--------------------------------------------------------*/
		parent_element.getElements ('div.success, div.error, div.warning, div.alert').each (function (element, index) {
			// Faux window
			if (element.hasClass ('alert'))
			{
				draw_window ('<div class="faux_window_content" id="alert_prompt">' + element.get ('html') + '<a href="#" class="cancel button">Close [x]</a></div>');
			}

			// Prompt
			else
			{
				draw_prompt (element.get ('class'), element.get ('html'));
			}

			// Destroooooy it!
			element.destroy ();
		});


		/* Accordions
		--------------------------------------------------------*/
		parent_element.getElements ('.accordion').each (function (element, index) {
			// Get all handles and elements that're children of
			handles = element.getElements ('.accordion_handle');
			elements = element.getElements ('.accordion_element');

			// Filter out any handles and elements that're children of
			// a nested accordion inside this one
			var nested_elements = element.getElements ('.accordion .accordion_handle, .accordion .accordion_element');

			// Go through our handles and elements and remove them if
			// they exist inside our nested_elements collection
			var nested_check = function (item, index) {
				var nested_index = nested_elements.indexOf (item);
				if (nested_index !== -1)
				{
					// Remove it from the collection to speed up future searches
					nested_elements.splice (nested_index, 1);
					return false;
				}
				return true;
			};
			handles = handles.filter (nested_check);
			elements = elements.filter (nested_check);

			// Default objects
			var options = {
				transition: global_transition,
				duration: 750,
				opacity: false,
				alwaysHide: false,
				show: 0,
				onActive: function (toggler, element) {
					toggler.addClass ('accordion_open');
					toggler.setProperty ('title', '');
				},
				onBackground: function (toggler, element) {
					toggler.removeClass ('accordion_open');
					toggler.setProperty ('title', 'Click to Expand');
				}
			};

			// Explicity told not to show anything?
			if (element.hasClass ('fully_closed'))
			{
				options.show = -1;
			}

			/* Hierarchical tree behviours (Also an accordion)
			--------------------------------------------------------*/
			if (element.hasClass ('hierarchical'))
			{
				options.show = -1;
				options.alwaysHide = true;
				options.onActive = function (toggler, element) {
					toggler.addClass ('accordion_open');
					toggler.setProperty ('title', 'Click to Collapse');

					// Nested accordions are weird...
					var toggler_parent = toggler.getParent ('.accordion_element');
					if (toggler_parent)
					{
						(function () {
							toggler_parent.setStyle ('height', '');
						}).delay (options.duration);
					}
				}
			}

			// Determine which element to show by looking for the 'active' class
			// on EITHER the handle or the element... There should be an equal number
			// of both, so we just iterate one list and simultaneoulsy check the other
			var _ = false;
			elements.each (function (sub_element, index) {
				if (!_ && (sub_element.hasClass ('active') || handles[index].hasClass ('active'))) {
					options.show = index;
					_ = true;
				}
			});

			new Accordion (handles, elements, options);
		});

		// Because some accordions are nested
		parent_element.getElements ('.hierarchical .accordion_handle').each (function (element, index) {
			element.addEvent ('click', function () {
				var parent_element = this.getParent ('.accordion_element');
				parent_element.setStyle ('height', '');
			});
		});

		/* IE Handholding
		--------------------------------------------------------*/
		// IE doesn't obey/understand td { white-space: nowrap; }
		if ($('IE'))
		{
			parent_element.getElements ('form table.data tbody th').each (function (element, index) {
				element.set ('html', '<span>' + element.get ('html') + '</span>');
			});
		}

		if ($('IE6'))
		{
			// Faking :hover
			var hoverable_objects = new Array ();
			hoverable_objects.push ('.hierarchical .accordion_handle');
			hoverable_objects.push ('.cover');
			hoverable_objects.push ('.rollout_trigger');
			hoverable_objects.push ('#queue tbody tr');
			hoverable_objects.push ('#download_library tbody tr');
			hoverable_objects.push ('#wish_list tbody tr');

			parent_element.getElements (hoverable_objects.join (',')).each (function (element, index) {
				element.addEvents ({
					'mouseover': function () {
						this.addClass ('hover');
					},
					'mouseout': function () {
						this.removeClass ('hover');
					}
				});
			});
		}
	};

	/* Prompts
	--------------------------------------------------------*/
	var draw_prompt = function (type, message, options) {
		// Hide any existing prompts
		$$('.prompt').each (function (element, index) {
			// Only hide prompts of the same type, or loading.
			if (element.hasClass ('loading_prompt') || element.hasClass (type + '_prompt')) {
				hide_prompt.run ([], element);
			}
		});

		// Options
		options = $pick (options, {});

		// Create the prompt box itself
		var box = new Element ('div', {
			'class': type + '_prompt prompt',
			'styles': {
				'position': 'absolute',
				'left': 0,
				'top': -1000,
				'width': window.getSize ().x,
				'z-index': 10000000
			},
			'html': '<div class="message_content">' + message + '</div>'
		}).set ('tween', {
			'transition': global_transition,
			'duration': 500
		});

		// Optional auto-hide
		if ($defined (options.auto_hide_delay))
		{
			box.get ('tween').addEvent ('onComplete', function () {
				box.auto_hide_timer = hide_prompt.pass ([], box).delay (options.auto_hide_delay);
			});
		}

		// Create a title bar
		var title_bar = new Element ('h1', {
			'html': '<div class="title_content">' + type.capitalize () + '</div>'
		});

		// Create a close button
		var close_button = new Element ('a', {
			'class': 'button',
			'href': '#',
			'text': 'Close [x]',
			'events': {
				'click': hide_prompt.pass ([], box)
			}
		})
		close_button.onclick = return_false;

		// Build the entire prompt box
		close_button.inject (title_bar.getElement ('.title_content'));
		title_bar.inject (box);

		// Inject at the top of <body>, but after all other prompts.
		box.inject (document.body.getLast ('.prompt') || document.body, document.body.getLast ('.prompt') ? 'after': 'top');

		// Optional buttons
		if ($defined (options.buttons))
		{
			// Remove the close button; the action buttons MUST be used
			close_button.destroy ();

			// Insert a button container
			box.getElement ('.message_content').set ('html', box.getElement ('.message_content').get ('html') + '<div class="buttons"></div>');

			// Populate the button container
			var button_container = box.getElement ('.buttons');
			options.buttons.each (function (element, index) {
				new Element ('a', {
					'class': 'button',
					'text': element.label,
					'events': {
						'click': function () {
							// Clicking any button will close the prompt
							hide_prompt.run ([], box);

							// Run the button's defined handler, if it has one
							if ($defined (element.handler)) {
								element.handler ();
							}
						}
					}
				}).inject (button_container).onclick = return_false;
			});
		}

		// To animate the reveal, we need to align the prompt_container's
		// bottom edge with the top of the viewport, and then tween it down
		// so its top edge aligns with the top of the viewport. Easy stuff.
		var top_position = window.getScroll ().y - box.getSize ().y;
		box.tween ('top', top_position, top_position + box.getSize ().y);
	};

	var hide_prompt = function () {
		// Get the prompt box
		var prompt_box = this;

		// Clear any lingering auto_hiders
		prompt_box.auto_hide_timer = $clear (prompt_box.auto_hide_timer);

		// Destroy the box when animation is done
		prompt_box.get ('tween').removeEvents ('onComplete');
		prompt_box.get ('tween').addEvent ('onComplete', function () {
			prompt_box.destroy ();
		});

		// Tween the prompt from its current 'top' property to just outside the viewport
		prompt_box.tween ('top', window.getScroll ().y - prompt_box.getSize ().y);
	};

	/* AJAX Loading
	--------------------------------------------------------*/
	var show_loading_box = function () {
		draw_prompt ('loading', 'Your request is being processed. Please wait...');
	};

	var hide_loading_box = function (message) {
		var prompt_box = document.body.getLast ('.loading_prompt');

		// The box may not exist if many are fired in succession, as prompts are
		// automatically hidden when another one is called, and it's possible
		// that the prompt is hidden while the request is still running.
		if (prompt_box)
		{
			// Set the box's text to 'success'
			prompt_box.getElement ('.message_content.').set ('html', $type (message) == 'string' ? message : 'Done!');

			// Hide the box automatically after 1 second
			prompt_box.auto_hide_timer = hide_prompt.pass ([], prompt_box).delay (2000);
		}
	};

	/* Viewport Shading
	--------------------------------------------------------*/
	var shade_viewport = function (level) {
		// Get the shader
		var viewport_shader = $('viewport_shader');

		// Get window size
		var window_size = window.getSize ();

		// Get and shade viewport
		viewport_shader.level = level;
		viewport_shader.setStyles ({
			'top': window.getScroll ().y,
			//'bottom': 0 - window.getScroll ().y,
			'width': window_size.x,
			'height': window_size.y
		}).set ('opacity', level);
		//}).tween ('opacity', level);
		//}).tween ('height', level > 0 ? window_size.y : 0);

		// Hide <select> for IE6, because it's LAME
		if ($chk($('IE6'))) {
			$$('select').each (function (element, index) {
				element.setStyle ('visibility', level > 0 ? 'hidden' : '');
			});
		}
	};

	/* Position fixers
	--------------------------------------------------------*/
	var correct_positions = function () {
		// Viewport shader
		var viewport_shader = $('viewport_shader');
		shade_viewport (viewport_shader.level);

		// Faux window
		var faux_window = $('faux_window');
		var faux_window_size = faux_window.getScrollSize ();
		faux_window.setStyles ({
			'margin-left': faux_window_size.x / 2 * -1,
			'margin-top': window.getScroll ().y + (faux_window_size.y / 2 * -1),
			'opacity': 1
		});

		// Prompts
		$$('.prompt').each (function (element, index) {
			element.setStyles ({
				'top': window.getScroll ().y,
				'width': window.getSize ().x
			});
		});
	};

	/* Cover Tooltips
	--------------------------------------------------------*/
	var describeCover = function () {
		var cover_tooltip = $('cover_tooltip');

		var details_obj = this.getElement ('.cover_details');

		// No details in this cover? Then we're done.
		if (!details_obj)
		{
			return false;
		}

		// Show it
		cover_tooltip
			.adopt (details_obj.clone ())
			.setStyles ({
				'display': 'block'
			});

		// Get coordinates of this a tag
		coords = this.getCoordinates ();

		// Position it now that we can read its  height and so on
		cover_tooltip.setStyles ({
			'top': coords.top - cover_tooltip.getSize ().y + 4,
			'left': coords.left + (coords.width / 2) - (cover_tooltip.getSize ().x / 2)
		});
	}

	var undescribeCover = function () {
		if ($('cover_tooltip').getStyle ('display') == 'block')
		{
			$('cover_tooltip')
				.setStyle ('display', 'none')
				.getElement ('.cover_details').destroy ();
		}
	}

	/* Rollouts
	--------------------------------------------------------*/
	// For rolling an object up or down (animated)
	var rollout = function (target, options) {
		// Set default options
		options = $pick (options, {});
		options.open         = $pick (options.open, true);
		options.animate      = $pick (options.animate, true);
		options.transition   = $pick (options.transition, global_transition);
		options.duration     = $pick (options.duration, 750);
		options.heightTweak  = $pick (options.heightTweak, 0);
		options.onPreRollOut = $pick (options.onPreRollOut, function () {});
		options.onPreRollUp  = $pick (options.onPreRollUp, function () {});
		options.onRollOut    = $pick (options.onRollOut, function () {});
		options.onRollUp     = $pick (options.onRollUp, function () {});
		options.onComplete   = $pick (options.onComplete, function () {});

		// Set overflow
		target.setStyle ('overflow', 'hidden');

		// Animating?
		if (options.animate)
		{
			target.set ('tween', {
				'transition': options.transition,
				'duration': options.duration,
				'onComplete': options.open ? function () { options.onRollOut (target); options.onComplete (target); } : function () { options.onRollUp (target); options.onComplete (target); }
			});
		}

		// We're opening the target
		if (options.open === true)
		{
			options.onPreRollOut (target);

			// Size it up to that height; animate if that's what we're told
			if (options.animate) {
				target.tween ('height', target.scrollHeight + options.heightTweak);
			}
			else
			{
				target.setStyle ('height', target.scrollHeight + options.heightTweak);

				// Fire the onRollOut event
				options.onRollOut (target);
			}
		}

		// We're closing the target
		else if (options.open === false)
		{
			options.onPreRollUp (target);

			// Set height to 0
			if (options.animate) {
				target.tween ('height', 0);
			}
			else
			{
				target.setStyle ('height', 0);

				// Fire the onRollUp event
				options.onRollUp (target);
			}
		}
	};

	var rollup = function (target, options) {
		options = $pick (options, {});
		options.open = false;
		rollout (target, options);
	};

	var autoroll = function (target, options) {
		options = $pick (options, {});
		options.open = (target.getStyle ('height').toInt () > 0) ? false : true;
		rollout (target, options);
	};

	/* Form Field Disabling
	--------------------------------------------------------*/
	// Disable/enable all form elements within an element
	var enable_inputs_in = function (id, enabled) {
		if ($type (enabled) !== 'boolean') {
			enabled = true;
		}

		$(id)
			.getElements ('input, textarea, select')
			.each (function (element, index) {
				element.set ('disabled', enabled ? '' : 'disabled');
			});
	};

	var disable_inputs_in = function (id) {
		enable_inputs_in (id, false);
	}

	/* IE Handholding
	--------------------------------------------------------*/
	// Fix stamp PNGs in IE6
	var fix_stamps_in_IE6 = function () {
		if ($('IE6'))
		{
			$$('.stamp, .stamp a').each (function (element, index) {
				element.removeProperty ('style');
				var bg = element.currentStyle.backgroundImage;
				if (bg && bg.match (/\.png/i) != null)
	  			{
	  				var mypng = bg.substring (5, bg.length - 2);
	  				element.style.zoom = '1.0';
	  				element.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + mypng + "', sizingMethod='crop')";
	  				element.style.backgroundImage = "url('/assets/images/x.gif')";
	  			}
			});
		}
	}

	// Fix tabs for IE6
	var fix_tabs_in_IE6 = function () {
		if ($('IE6'))
		{
			$$('#tab_list .tab').each (function (element, index) {
				element.removeProperty ('style');
				_ = element.hasClass ('accordion_open') ? 'ie6.tab.on.png' : 'ie6.tab.off.png';
				element.style.zoom = '1.0';
				element.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/widgets/tabs/" + _ + "', sizingMethod='crop')";
				element.style.backgroundImage = "url('/assets/images/x.gif')";
			});
		}
	}

	/* Log In
	--------------------------------------------------------*/
	var log_in = function () {
		new SAB_Request ({
			'url': '/log_in_handler.php',
			'method': 'get'
		}).send ();

		return false;
	};

	/* Things to do onDomReady
	--------------------------------------------------------*/
	var init_events = new Array ();
	var tabbed_interface = null
	var load_tab;
	init_events.push (function () {
		/* Log In Button
		--------------------------------------------------------*/
		$$('#user_nav_login a').addEvent ('click', log_in);

		/* IE Handholding
		--------------------------------------------------------*/
		// IE doesn't have its <body> extended properly. This fixes it.
		// We need to do this first. Before anything. Or ELSE! Ooooh...
		document.getElement ('body');

		// Fix stamps
		fix_stamps_in_IE6 ();

		/* Cover Tooltip
		--------------------------------------------------------*/
		var cover_tooltip = new Element ('div', {
			id: 'cover_tooltip'
		});
		var arrow = new Element ('div', {
			id: 'cover_tooltip_arrow'
		});
		cover_tooltip.adopt (arrow);
		document.body.adopt (cover_tooltip);

		/* Viewport Shader
		--------------------------------------------------------*/
		// Fader
		var viewport_shader = new Element ('div', {
			'id': 'viewport_shader',
			'styles': {
				'position': 'absolute',
				'z-index': 15000,
				'opacity': 0
			}
		}).set ('tween', {
			'duration': 250
		}).inject (document.body, 'top');
		viewport_shader.level = 0;

		/* Faux Window
		--------------------------------------------------------*/
		var faux_window = new Element ('div', {
			'id': 'faux_window',
			'styles': {
				'position': 'absolute',
				'left': '50%',
				'top': '50%',
				'z-index': 100000,
				'height': 0,
				'overflow': 'hidden',
				'opacity': 0
			}
		}).inject (document.body, 'top');

		/* Learn More Sub Menu
		--------------------------------------------------------*/
		if ($('learn_more_sub'))
		{
			// Function hide learn more subs
			var hide_learn_more_sub = function () {
				$$('#main_nav_learnmore a').removeClass ('hover');
				$('learn_more_sub').setStyle ('display', 'none');
			};

			// Anything that ISN'T the learn more button should hide the learn more sub
			$$('#main_nav > li').each (function (element, index) {
				if (element.id != 'main_nav_learnmore') {
					element.getElement ('a').addEvent ('mouseover', hide_learn_more_sub);
				}
			});

			var sub_hide_timeout = null;

			// Extract the sub menu and make it a direct child of <body>
			$('learn_more_sub').inject (document.body, 'top');

			// Disable the button itself
			$$('#main_nav_learnmore a').onclick = return_false;

			// Add events
			$('main_nav_learnmore').addEvents ({
				'mouseover': function () {
					this.getElement ('a').addClass ('hover');
					$('learn_more_sub').setStyles ({
						'display': 'block',
						'left': $('main_nav_learnmore').getPosition ().x - 1
					});
					sub_hide_timeout = $clear (sub_hide_timeout);
				},
				'mouseout': function () {
					sub_hide_timeout = hide_learn_more_sub.delay (1000);
				}
			});
			$$('#learn_more_sub a').each (function (element, index) {
				element.addEvents ({
					'mouseover': function () {
						sub_hide_timeout = $clear (sub_hide_timeout);
					},
					'mouseout': function () {
						sub_hide_timeout = hide_learn_more_sub.delay (1000);
					}
				});
			});
		}

		/* Search Bar Behaviour
		--------------------------------------------------------*/
		if ($('quick_search'))
		{
			var quick_search_focused = false;
			$('quick_search').addEvents ({
				'focus': function () {
					if (this.value == 'Find Books')
					{
						this.value = '';
						this.addClass ('active');
					}
					quick_search_focused = true;
				},
				'blur': function () {
					if (this.value == '')
					{
						this.value = 'Find Books';
						this.removeClass ('active');
					}
					quick_search_focused = false;
				},
				'mouseover': function () {
					this.addClass ('active');
				},
				'mouseout': function () {
					if (!quick_search_focused && this.value == 'Find Books') {
						this.removeClass ('active');
					}
				}
			});
			$('quick_search').fireEvent ('mouseover');
			$('quick_search').fireEvent ('mouseout');
		}

		/* Tabbed Interface
		--------------------------------------------------------*/
		if ($('tabbed_interface'))
		{
			tabs = $('tab_list').getElements ('.tab');

			// Disable the anchors
			var active_tab = 0;
			tabs.each (function (element, index) {
				element.getElement ('a').onclick = return_false;

				// Active tab?
				if (element.hasClass ('active')) {
					active_tab = index;
				}
			});

			var tab_contents = $('tabbed_interface').getElements ('.tab_content');
			tab_contents.each (function (element, index) {
				new Element ('div', {
					'class': 'clearer',
					'html': '&nbsp;'
				}).inject (element, 'bottom');
			});

			// Create the accordion
			var tabbed_interface = new Accordion (tabs, tab_contents, {
				display: active_tab,
				transition: global_transition,
				duration: 750,
				opacity: false,
				alwaysHide: false,
				onActive: function (toggler, element) {
					element.setStyle ('display', 'block');
					toggler.addClass ('accordion_open');
					toggler.setProperty ('title', '');
					fix_tabs_in_IE6 ();
					active_tab = element;
				},
				onBackground: function (toggler, element) {
					toggler.removeClass ('accordion_open');
					toggler.setProperty ('title', 'Click to Open');
					element.setStyle ('display', 'none');
					fix_tabs_in_IE6 ();
				},
				onComplete: function () {
					active_tab.setStyle ('height', '');
				}
			});

			// For loading a specific tab
			// Enter either the 0-based index, or the first few letters of its label
			// IE: load_tab (0); load_tab ('Account Hist');
			load_tab = function (tab_indicator) {
				switch ($type (tab_indicator))
				{
					// Just load the tab by its index (0-based)
					case 'number':
						tabbed_interface.display (tab_indicator);
						return false;

					// Use the string to match the tab's text
					case 'string':
						tabs.each (function (element, index) {
							if (element.getElement ('a').getText ().match (new RegExp ('^' + tab_indicator + '.*$', 'gi')))
							{
								tabbed_interface.display (index);
								return false;
							}
						});
				}

				return false;
			};

			/* Auto-Loading Tabs
			--------------------------------------------------------*/
			var auto_loading_tab = window.location.toString ().indexOf ('#load_tab_');
			if (auto_loading_tab >= 0)
			{
				// #load_tab_3 is really #load_tab_2
				load_tab (window.location.toString ().charAt (auto_loading_tab + 10).toInt () - 1);
			}
		}

		/* HTML Parsing
		--------------------------------------------------------*/
		parse_html (document);
	});

	/* Delayed DOMReady Event Firing
	--------------------------------------------------------*/
	window.addEvent ('domready', function () {
		(function () {
			init_events.each (function (func, index) {
				func ();
			});
		}).delay (100);
	});

	/* OnLoad
	--------------------------------------------------------*/
	window.addEvent ('load', function () {
		/* Cover List Baseline Alignment
		--------------------------------------------------------*/
		$$('.cover_list').each (function (element, index) {
			var _ = [];
			var max_height = 0;

			// Calculate the maximum number of covers per row
			cover_right_margin = element.getElement ('.cover').getStyle ('margin-right').toInt ();
			covers_per_row = Math.floor ((element.getSize ().x + cover_right_margin) / (79 + cover_right_margin));

			element.getElements ('.cover').each (function (element, index) {
				// Get coords of current and next element
				element.coords = element.getCoordinates ();

				// Store the maximum height of all elements in a row
				max_height = Math.max (element.coords.height, max_height);

				// Add the element to the collection
				_.push (element);

				// Look ahead to the next element
				var next_element = element.getNext ();
				if (next_element) {
					next_element.coords = next_element.getCoordinates ();
				}

				// End of a row or end overall?
				if ((index > 0 && (index + 1) % covers_per_row === 0) || !next_element)
				{
					// Remove right margin on last element (for IE's sake...)
					element.setStyle ('margin-right', 0);

					// Align the elements in our collection (the 'row')
					_.each (function (element, index) {
						element.setStyle ('margin-top', max_height - element.coords.height);
					});

					// Reset
					_ = [];
					max_height = 0;
				}
			});
		});

		/* OnResize = FIX STUFF (delay)
		--------------------------------------------------------*/
		(function () {
			window.addEvent ('resize', correct_positions);
			window.addEvent ('scroll', correct_positions);
		}).delay (750);
	});