﻿/*
Copyright (C) 2011 Tony Germaneri

main.js version 0.1.1

This file is part of rendition.

rendition is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

rendition is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with rendition.  If not, see <http://www.gnu.org/licenses/>.
 */

/// <summary>
/// This is a reference/example of how to use Rendition.dll as a front end e-commerce site.
/// This file contains methods and properties that impement AJAX/JSON path /responder.html to rendition.dll
/// If your AJAX/JSON responder.html is not the URL /responder.html it will be nessessary to modify this file.
/// This file exclusivly uses JQuery 1.4.2 to execute all AJAX and animation procedures and is required.
/// </summary>
window.responderURL = "responder.html";

/* these are the default colors for the validation method later in the file */
window.pulseColor1 = 'lightblue';
window.pulseColor2 = 'white';

/* This is a list of easing methods for easy reference:
jswing, def, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, easeInQuart
easeOutQuart, easeInOutQuart, easeInQuint, easeOutQuint, easeInOutQuint, easeInSine, easeOutSine
easeInOutSine, easeInExpo, easeOutExpo, easeInOutExpo, easeInCirc, easeOutCirc, easeInOutCirc
easeInElastic, easeOutElastic, easeInOutElastic, easeInBack, easeOutBack, easeInOutBack, easeInBounce
easeOutBounce, easeInOutBounce
*/
/* these are the deafult easing methods for the validation method later in this file */
window.easeOut = "linear";
window.easeIn = "linear";

/* these are the default validation patterns for the given input type */
/* for fields that can be left blank, but probably shouldn't be */
window.askLeaveBlank = '.*monogram.*';
/* for fields that cannot be left blank */
window.cannotBeBlank = '(^billTo[^2]*$)|(^shipTo[^2]*$)|(^card.*$)|(^exp.*$)|(^nameOnCard$)|(^secNumber$)';
/* for fields that can be left blank but look a lot like fields that cannot be left blank */
window.cannotBeBlankExceptions = '(^.*SpecialInstructions$)';
/* fields that cannot be left the default value */
window.cannotBeDefault = '(^gender.*$)|(^hair.*$)|(^skin.*$)';
/* array of values the above fields cannot be set to */
window.defaultValues = ["-Select-","Select"];

/* adds a discount code to the cart and executes args.callbackProcedure
accepts one argument dictionary {
	discountCode: <the discount code as a string> 
	callbackProcedure: <procedure to run when this method completes successfully. signature: (JSONResponse e) >
}
*/
function setDiscountCode(args) {
	var instance = {};
	$.ajax({
		type: "POST",
		url: window.responderURL,
		data: 'method1=' + encodeURIComponent(JSON.stringify([
			'setDiscountCode',
			[
				args.discountCode
			]
		])),
		processData: false,
		dataType: "json",
		success:function(e){
			e = e.method1;
			if(e.error!=undefined){
				alert(e.desc);
				return;/* error accessing method */
			}
			e = e.setDiscountCode;
			if(e.error!=0){
				alert(e.desc);
				return;/* method returns an error */
			}
			if(args.callbackProcedure!=undefined){
				args.callbackProcedure.apply(this,[e]);
			}
		}
	});
}
/* removes an item to the wish list session property 
accepts one argument dictionary {
	button: <DOM button,changes button message and disables/enables button>,
	returnMessage: <String, the message that appeears on the button when the method completes successfully>,
	callbackProcedure: <procedure to run when this method completes successfully. sig: (JSONResponse e) >
}
*/
function removeFromWishlist(args) {
	if(args.button!=undefined){
		args.button.disabled = true;
		args.button.innerHTML = 'Removing Items...';
	}
	$.ajax({
		type: "POST",
		url: window.responderURL,
		data: 'method1=' + encodeURIComponent(JSON.stringify([
			'removeFromWishlist',
			[
				args.itemNumber
			]
		])),
		processData: false,
		dataType: "json",
		success:function(e){
			e = e.method1;
			if(e.error!=undefined){
				alert(e.desc);
				args.button.disabled = false;
				return;/* error accessing method */
			}
			e = e.removeFromWishlist;
			if(e.error!=0){
				alert(e.desc);
				args.button.disabled = false;
				return;/* method returns an error */
			}
			if(args.callbackProcedure!=undefined){
				args.callbackProcedure.apply(this,[e]);
			}
			args.button.innerHTML = args.returnMessage||'Item Removed';
		}
	});
}

/* adds an item to the wish list session property 
accepts one argument dictionary {
	button: <DOM button,changes button message and disables/enables button>,
	returnMessage: <String, the message that appeears on the button when the method completes successfully>,
	callbackProcedure: <procedure to run when this method completes successfully. sig: (JSONResponse e) >
}
*/
function addToWishList(args) {
	var instance = {};
	if(args.button!=undefined){
		args.button.disabled = true;
		instance.buttonHTML = args.button.innerHTML;
		args.button.innerHTML = 'Adding Item...';
	}
	instance.restoreButton = function(){
		if(args.button!=undefined){
			args.button.innerHTML = instance.buttonHTML = instance.buttonHTML;
			args.button.disabled = false;
		}
	}
	$.ajax({
		type: "POST",
		url: window.responderURL,
		data: 'method1=' + encodeURIComponent(JSON.stringify([
			'addToWishlist',
			[
				args.itemNumber
			]
		])),
		processData: false,
		dataType: "json",
		success:function(e){
			e = e.method1;
			if(e.error!=undefined){
				alert(e.desc);
				instance.restoreButton();
				return;/* error accessing method */
			}
			e = e.addToWishlist;
			if(e.error!=0){
				alert(e.desc);
				instance.restoreButton();
				return;/* method returns an error */
			}
			if(args.callbackProcedure!=undefined){
				args.callbackProcedure.apply(this,[e]);
			}
			args.button.innerHTML = args.returnMessage||'Item In Wishlist';
		}
	});
}
/* 
produces a dialog (DIV) that contains default buttons and fields nessessary to email a friend
information abou this item using the emailAFriend event handler in rendition.dll.
accepts one argument dictionary {
	marginTop:<top margin of the absolutly position div from the top of the window default: 50>
	width:<width of the dialog default: 600>
	height:<height of the dialog default: 315>
	previewWidth:<width of the preview of the message default: 800>
	previewHeight:<height of the preview of the message default: 450>
	animationTimer:<time for the animation to complete default: 'fast' (JQuery, 'fast','slow',100 etc)
	animationEasing:<easing method of the animation default: 'linear' (JQuery easing methods)
	emailSentMessage:<message to display to the user after the email has been sent default: 'EMAIL SENT!'>
	callbackMessageDelay:<how long to delay before removing the message in ms default: 3000 (3 seconds) >
}
*/
function emailAFriend(args) {
	if(window.user.userId==-1||window.user==undefined){
		new logon({
			callbackProcedure:function(){
				emailAFriend(args);
			}
		});
		return;
	}
	var instance = {};
	if(args==undefined){
		args = {};
	}
	instance.margin = {
		top:args.marginTop||50
	}
	instance.rect = {
		width:args.width||600,
		height:args.height||315
	}
	instance.previewMargin = {
		top:args.previewMarginTop||10
	}
	instance.previewRect = {
		width:args.previewWidth||800,
		height:args.previewHeight||450
	}
	instance.animationTimer = args.animationTimer||'fast';
	instance.animationEasing = args.animationEasing||'linear';
	instance.resize = function () {
		var p = {
			t:document.documentElement.scrollTop,
			l:document.documentElement.scrollLeft,
			h:document.documentElement.clientHeight,
			w:document.documentElement.clientWidth
		}
		instance.modalBackground.style.height = p.h + 'px';
		instance.modalBackground.style.width = p.w + 'px';
		instance.modalBackground.style.top = p.t + 'px';
		instance.modalBackground.style.left = p.l + 'px';
		instance.email.style.top = instance.finalTop() + 'px';
		instance.email.style.left = (document.documentElement.clientWidth / 2 - (instance.rect.width / 2)) + 'px';
	}
	instance.init = function () {

		instance.email = document.createElement('div');
		instance.modalBackground = document.createElement('div');
		
		instance.finalLeft = (document.documentElement.clientWidth / 2) - (instance.rect.width / 2);
		instance.finalTop = function(){return document.documentElement.scrollTop + instance.margin.top};
		instance.email.style.top = instance.finalTop();
		instance.email.style.left = (document.documentElement.clientWidth / 2 - (instance.rect.width / 2)) + 'px';
		instance.modalBackground.style.background = 'url(/img/25PctAlphaBlackDot.png)';
		instance.modalBackground.style.position = 'absolute';
		instance.modalBackground.style.zIndex = '9996';
		instance.email.className = 'replyWindow emailAFriendWindow';
		instance.email.style.zIndex = '9997';
		instance.email.style.position = 'absolute';
		appendEvent('resize', window.document, instance.resize, false);
		appendEvent('scroll', window.document, instance.resize , false);
		instance.email.style.width = 10 + 'px';
		instance.email.style.height = 10 + 'px';
		instance.resize();
		
		instance.formTable = document.createElement('table');
		instance.formTable.className = 'blogReply emailAFriend';
		instance.formTable.style.width = '100%';
		instance.formTable.style.marginTop = '10px';

		instance.friendsEmail = document.createElement('input');
		instance.message = document.createElement('textarea');
		instance.cancelButton = document.createElement('button');
		instance.postButton = document.createElement('button');

		instance.friendsEmail.style.width = '350px';

		instance.cancelButton.onclick = instance.close;
		instance.postButton.onclick = instance.submit;

		instance.cancelButton.style.margin = '4px';
		instance.postButton.style.margin = '4px';

		instance.cancelButton.innerHTML = 'Cancel';
		instance.postButton.innerHTML = 'Post';

		var t = instance.formTable;
		var r4 = t.insertRow(0);
		var r3 = t.insertRow(0);
		var r2 = t.insertRow(0);
		var r1 = t.insertRow(0);
		var r4c1 = r4.insertCell(0);
		r4c1.setAttribute('colspan','2');
		var r3c1 = r3.insertCell(0);
		r3c1.setAttribute('colspan','2');
		var r2c1 = r2.insertCell(0);
		r2c1.setAttribute('colspan','2');
		var r1c2 = r1.insertCell(0);
		var r1c1 = r1.insertCell(0);

		r1c1.style.textAlign = 'right';
		r1c2.style.fontWeight = 'bold';
		r2c1.style.textAlign = 'center';
		r1c1.appendChild(document.createTextNode('Friend\'s Email Address'));
		r1c2.appendChild(instance.friendsEmail);
		r2c1.appendChild(document.createTextNode('Message To Include'));
		r3c1.appendChild(instance.message);
		r2c1.style.padding = '0 0 0 16px';
		r2c1.style.textAlign = 'left';
		r3c1.style.padding = '4px';
		r3c1.style.textAlign = 'right';
		r4c1.style.padding = '4px';
		r4c1.style.textAlign = 'right';
		instance.message.style.width = '550px';
		instance.message.style.height = '200px';
		
		r4c1.appendChild(instance.cancelButton);
		r4c1.appendChild(instance.postButton);

		document.body.appendChild(instance.modalBackground);
		document.body.appendChild(instance.email);

		instance.email.appendChild(instance.formTable);

		$(instance.email).animate({ width: instance.rect.width, left: instance.finalLeft }, instance.animationTimer, instance.animationEasing, function () {
			$(instance.email).animate({ height: instance.rect.height  }, instance.animationTimer, instance.animationEasing, function(){
				instance.friendsEmail.focus();
				instance.friendsEmail.select();
			});
		});

		return instance;
	}
	instance.close = function (e) {
		instance.dispose();
	}
	instance.formStruct = function(){
		return {
			message:instance.message.value,
			subject:instance.friendsEmail.value
		}
	}
	instance.submit = function (button) {
		instance.postButton.disabled = true;
		$.ajax({
			type: "POST",
			url: window.responderURL,
			data: 'method1=' + encodeURIComponent(JSON.stringify(instance.getEmailMethod())),
			processData: false,
			dataType: "json",
			success:instance.submitCallback
		});
	}
	instance.submitCallback = function(e){
		e = e.method1;
		if(e.error!=undefined){
			alert(e.desc);
			instance.postButton.disabled = false;
			return;/* error accessing method */
		}
		e = e.emailAFriend;
		if(e.error!=0){
			alert(e.desc);
			instance.postButton.disabled = false;
			return;/* method returns an error */
		}
		instance.postButton.innerHTML = args.emailSentMessage || 'EMAIL SENT!';
		setTimeout(instance.dispose, args.callbackMessageDelay || 3000);/*close the window 3 seconds after post callback */
	}
	instance.dispose = function(){
		instance.postButton.disabled = false;
		document.body.removeChild(instance.modalBackground);
		document.body.removeChild(instance.email);
	}
	instance.getEmailMethod = function(){
		return [
			'emailAFriend',
			[
				args.itemNumber,
				instance.message.value,
				instance.friendsEmail.value
			]
		]
	}
	return instance.init();
}
/* search button click event */
function searchClick(value){
	window.location = '/list.aspx?search=' + value;
}
/* search button keypress event (on enter submit search) */
function searchKeyPress(e, value){	
	if(e.keyCode==13){
		window.location = '/list.aspx?search=' + value;
	}
}
/* 
BILL TO OVERWRITES SHIP TO
copies the information the checkout form from one set of DOM inputs to another */
function copyShipTo(){
	var g = function(i){return document.getElementById(i);};
	g('shipToFirstName').value = g('billToFirstName').value;
	g('shipToLastName').value = g('billToLastName').value;
	g('shipToAddress1').value = g('billToAddress1').value;
	g('shipToAddress2').value = g('billToAddress2').value;
	g('shipToCity').value = g('billToCity').value;
	g('shipToState').value = g('billToState').value;	
	g('shipToCountry').value = g('billToCountry').value;
	g('shipToHomePhone').value = g('billToHomePhone').value;
	g('shipToWorkPhone').value = g('billToWorkPhone').value;
	g('shipToZip').value = g('billToZip').value;
}
/* 
SHIP TO OVERWRITES BILL TO
copies the information the checkout form from one set of DOM inputs to another */
function copyBillTo(){
	var g = function(i){return document.getElementById(i);};
	g('billToFirstName').value = g('shipToFirstName').value;
	g('billToLastName').value = g('shipToLastName').value;
	g('billToAddress1').value = g('shipToAddress1').value;
	g('billToAddress2').value = g('shipToAddress2').value;
	g('billToCity').value = g('shipToCity').value;
	g('billToState').value = g('shipToState').value;
	g('billToCountry').value = g('shipToCountry').value;
	g('billToHomePhone').value = g('shipToHomePhone').value;
	g('billToWorkPhone').value = g('shipToWorkPhone').value;
	g('billToZip').value = g('shipToZip').value;
}
/* Creates a drop down menu for multiple calendar entries to be displayed without mucking up the calendar */
function calendarEntries(o,a){
	var m = document.createElement('div');
	m.className = 'calendarDetail';
	var t = document.createElement('table');
	var h = a.length;
	for(var x=0;h>x;x++){
		var r = t.insertRow(0);
		var c = r.insertCell(0);
		c.className = 'calendarDetailCell';
		c.innerHTML = '<a href="/reply.aspx?entryId='+a[x][0]+'">'+a[x][2]+'</a>';
		c = r.insertCell(0);
		c.className = 'calendarDetailCell';
		c.innerHTML = '<a href="/reply.aspx?entryId='+a[x][0]+'">'+a[x][1]+'</a>';
	}
	var r = t.insertRow(0);
	c = r.insertCell(0);
	c.className = 'calendarDetailHeader';
	c.innerHTML = 'Date';
	c = r.insertCell(0);
	c.className = 'calendarDetailHeader';
	c.innerHTML = 'Subject';
	m.appendChild(t);
	new openMenu(m, o, {});
}
/* Recalculates the cart based on the inputs in a form.
using rendition.dll -> commerce.recalculate to recalculate.
accepts one argument dictionary {
	form:<the DOMElement that contains the inputs that makeup the checkout form
}
 */
function recalculateCart(args) {
	var inputs = getInputs(args.form);
	inputs.billToEmail = "";
	inputs.billToComments = "";
	inputs.billToEmailAds = false;
	inputs.billToCompany = "";
	inputs.shipToEmail = "";
	inputs.shipToComments = "";
	inputs.shipToEmailAds = false;
	inputs.shipToCompany = "";
	inputs.billToSendShipmentUpdates = false;
	inputs.billToSpecialInstructions = "";
	inputs.billToRateId = -1;
	if(args.form==undefined){return;}
	$.ajax({
		type: "POST",
		url: window.responderURL,
		data: 'method1=["recalculate",[' + JSON.stringify(inputs) + ']]',
		processData: false,
		dataType: "json",
		success: completeRecalculate
	});

};
/* callback procedure for recalculateCart */
function completeRecalculate(e) {
	if(e.method1.error!=undefined){
		alert(e.method1.desc);
		return;
	}
	if(e.method1.recalculate.error!=0){
		alert(e.method1.recalculate.desc);
		return;
	}
	e = e.method1.recalculate;
	for(var x=0;e.addresses.length>x;x++){
		a = undefined;
		var a = document.getElementById(encodeXMLId(e.addresses[x].id));
		if(a){
			var r = e.addresses[x].rates;
			while(a.options.length>0){
				a.remove(a.options[0]);
			}
			for(var y=0;r.length>y;y++){
				if((r[y].id!=-1)||r.length==1){
					var opt = document.createElement('option');
					opt.value = r[y].id;
					opt.text = r[y].name + ' $' + r[y].estShippingCost.toFixed(2);
					a.add(opt,null);
					if(e.addresses[x].rate!=null){
						if(e.addresses[x].rate.id==r[y].id){
							opt.selected = "selected";
						}
					}
				}
			}
		}
	}
	$('#subTotal').html('$' + e.subTotal.toFixed(2));
	$('#discountTotal').html('$' + e.discountTotal.toFixed(2));
	$('#taxTotal').html('$' + e.taxTotal.toFixed(2));
	$('#estShipTotal').html('$' + e.estShipTotal.toFixed(2));
	$('#grandTotal').html('$' + e.grandTotal.toFixed(2));
}
/* creates a gallery dialog (DIV) that displays a list of gallery images
based on the Id of a single image in the gallery.
This function is also called by the galleryRotator function.
accepts one argument dictionary {
	pageAlign:<where to align the page buttons default:{x: 'right', y: 'bottom'}>
	animationTimer:<time for the animation to complete default: 'fast' (JQuery, 'fast','slow',100 etc)
	animationEasing:<easing method of the animation default: 'linear' (JQuery easing methods)
	img:<the gallery image that belongs to the gallery, image must contain attribute galleryId="galleryId">
	galleryId:<the galleryId (instead of passing the img key)>
	pageText:<text that appears on each button.  the string <page> will be replaced with the page number.>
	pageClass:<the CSS class the page buttons use default:'galleryPages'>
	alwaysShowPages:<boolean - if the pages are shown even when the mouse isn't hovering default:false>
	previousText:<what text to display on the 'previous' button default:'&lArr;'>
	nextText:<what text to display on the 'next' button default:'&rArr;'>
	closeText:<what text to display on the 'close' button default:'Close'>
	nextClass:<the CSS class the 'next' button uses default: 'galleryNext'>
	closeClass:<the CSS class the 'close' button uses default: 'galleryClose'>
	previousClass:<the CSS class the 'previous' button uses default: 'galleryPrevious'>
	frameClass:<the CSS class the gallery DIV uses default:'frame gallery'>
	URL:<override the default responder URL default:'responder.html'>
	pageActiveClass:<the CSS class the 'active page' uses default:'galleryActivePage'>
	frameAnimate:<procedure to use to animate images changing. Signature: (frame, oldImage, newImage), Default: gallery.defaultAnimate >
	rect:<rectange used for the height and width of the background div.
}
 */
function gallery(args){
	if (args == undefined) { args = {}; };
	var instance = {};
	instance.rect = {
		height:600,
		width:900
	}
	if(args.rect!=undefined){
		instance.rect = args.rect;
	}
	instance.margin = {
		top: 20
	}
	instance.pageMargin = 5;
	instance.pageAlign = args.pageAlign || { x: 'right', y: 'bottom' };
	instance.index = 0;
	instance.images = [];
	instance.navigation = {
		pages : []
	}
	instance.defaultAnimateInterval = args.interval || 'fast';
	instance.animationEasing = args.animationEasing||'linear';
	instance.initCallback = function(e){
		instance.images = [];
		instance.imagePaths = [];
		if(args.img){
			var originalId = args.img.getAttribute('imageId');
		}
		if(originalId!=undefined){
			for(var x=0;e.length>x;x++){
				if(e[x].locationType=='f'){/* full size image */
					if(e[x].id==originalId){
						instance.index = instance.imagePaths.length;
					}
					instance.imagePaths.push(e[x].url);
				}
			}
		}else if(args.galleryId!=undefined){
			e = e.method1.getGallery.gallery.images;
			for(var x=0;e.length>x;x++){
				instance.imagePaths.push(e[x].full);
			}
		}
		
		var h = instance.imagePaths.length;
		for (var x = 0; h > x; x++) {
			var pageText = (x + 1);
			if (args.pageText != undefined) {
				pageText = args.pageText.replace('<page>', (x + 1));
			}
			var page = document.createElement('button');
			page.style.cursor = 'pointer';
			page.onmousedown = function (e) {
				e.preventDefault();
				return false;
			}
			page.className = args.pageClass || 'galleryPages';
			var showPages = args.alwaysShowPages == undefined ? false : args.alwaysShowPages;
			if (showPages) {
				page.style.visibility = 'hidden';
			}
			page.index = parseInt(x);
			page.style.position = 'absolute';
			page.onclick = function () {
				if (this.index == instance.index) { return; };
				instance.index = this.index;
				$(instance.oldImage).stop(true, true);
				$(instance.currentImage).stop(true, true);
				instance.loadImage(this.index);
				$(instance.oldImage).stop(true, true);
				$(instance.currentImage).stop(true, true);
			}
			page.innerHTML = pageText;
			
			if(instance.imagePaths.length>1){
				instance.frame.appendChild(page);
			}
			
			instance.navigation.pages.push(page);
			var i = new Image();
			i.setAttribute('path',instance.imagePaths[x]);
			i.loaded = false;
			appendEvent('load', i, function () {
				this.loaded = true;
				this.frameAnimate();
			}, false);
			i.frameAnimate = function () {
				instance.frameAnimate(instance.oldImage, instance.currentImage);
			}
			i.image = instance.images[x];
			i.index = x;
			instance.images.push(i);
		}
		if(instance.imagePaths.length>1){
			instance.frame.appendChild(instance.navigation.previous);
			instance.frame.appendChild(instance.navigation.next);
		}
		instance.frame.style.height = '10px';
		instance.frame.style.width = '10px';
		instance.frame.style.textAlign = 'left';/* must remain left for button positioning to work */
		instance.navigation.previous.innerHTML = args.previousText != undefined ? args.previousText : '&lArr;';
		instance.navigation.next.innerHTML = args.nextText != undefined ? args.nextText : '&rArr;';
		instance.closeButton.innerHTML = args.closeText != undefined ? args.closeText : 'Close';
		instance.closeButton.onclick = instance.dispose;
		instance.frame.appendChild(instance.closeButton);
		document.body.appendChild(instance.frame);
		document.body.appendChild(instance.modalBackground);
		
		$(instance.frame).animate({ width: instance.rect.width, left: instance.finalLeft }, instance.defaultAnimateInterval, instance.animationEasing, function () {
			$(instance.frame).animate({ height: instance.rect.height  }, instance.defaultAnimateInterval, instance.animationEasing, function(){
				instance.loadImage(instance.index);
				instance.positionButtons();
			});
		});
	}
	instance.positionButtons = function () {
		var h = instance.navigation.pages.length;
		var x = 0;
		var y = 0;
		var pH = instance.navigation.pages[0].offsetHeight;
		var pW = instance.navigation.pages[0].offsetWidth;
		var totalW = (instance.navigation.pages.length * (pW + instance.pageMargin));
		var rx = 0;
		var pbH = instance.navigation.previous.offsetHeight;
		var pbW = instance.navigation.previous.offsetWidth;
		var nbH = instance.navigation.next.offsetHeight;
		var nbW = instance.navigation.next.offsetWidth;

		instance.closeButton.style.marginLeft = ( instance.rect.width - instance.pageMargin - instance.closeButton.offsetWidth ) + 'px';

		instance.navigation.previous.style.marginTop = (parseInt(instance.rect.height / 2) + parseInt(pbH / 2) - pbH) + 'px';
		instance.navigation.previous.style.marginLeft = instance.pageMargin + 'px';

		instance.navigation.next.style.marginTop = (parseInt(instance.rect.height / 2) + parseInt(nbH / 2) - nbH ) + 'px';
		instance.navigation.next.style.marginLeft = ((instance.rect.width - instance.pageMargin) - nbW) + 'px';

		for (var x = h - 1; -1 < x; x--) {
			var p = instance.navigation.pages[x];
			if (instance.pageAlign.x == 'top') {
				p.style.marginTop = instance.pageMargin + 'px';
			} else {
				p.style.marginTop = (instance.rect.height - instance.pageMargin - pH) + 'px';
			}
			if (instance.pageAlign.x == 'right') {
				p.style.marginLeft = (totalW - rx) + 'px';
			} else {
				p.style.marginLeft = (instance.pageMargin + rx) + 'px';
			}
			rx += instance.pageMargin + pW;
		}
	}
	instance.resize = function () {
		var p = {
			t:document.documentElement.scrollTop,
			l:document.documentElement.scrollLeft,
			h:document.documentElement.clientHeight,
			w:document.documentElement.clientWidth
		}
		instance.modalBackground.style.height = p.h + 'px';
		instance.modalBackground.style.width = p.w + 'px';
		instance.modalBackground.style.top = p.t + 'px';
		instance.modalBackground.style.left = p.l + 'px';
		instance.frame.style.top = instance.finalTop() + 'px';
		instance.frame.style.left = (document.documentElement.clientWidth / 2 - (instance.rect.width / 2)) + 'px';
	}
	instance.finalTop = function(){return document.documentElement.scrollTop + instance.margin.top};
	instance.init = function(){
		instance.frame = document.createElement('div');
		instance.frame.style.position = 'absolute';
		instance.frame.style.zIndex = '9997';
		instance.closeButton = document.createElement('button');
		instance.navigation.previous = document.createElement('button');
		instance.navigation.next = document.createElement('button');
		instance.modalBackground = document.createElement('div');
		instance.modalBackground.style.background = 'url(/img/25PctAlphaBlackDot.png)';
		instance.modalBackground.style.position = 'absolute';
		instance.modalBackground.style.zIndex = '9996';
		instance.modalBackground.onclick = instance.dispose;
		
		instance.navigation.previous.onclick = function (e) {
			$(instance.oldImage).stop(true, true);
			$(instance.currentImage).stop(true, true);
			instance.index = instance.index == 0 ? instance.images.length - 1 : instance.index - 1;
			instance.loadImage(instance.index);
			$(instance.oldImage).stop(true, true);
			$(instance.currentImage).stop(true, true);
			e.preventDefault();
			return false;
		}

		instance.navigation.next.onclick = function (e) {
			$(instance.oldImage).stop(true, true);
			$(instance.currentImage).stop(true, true);
			instance.index = instance.index == instance.images.length - 1 ? 0 : instance.index + 1;
			instance.loadImage(instance.index);
			$(instance.oldImage).stop(true, true);
			$(instance.currentImage).stop(true, true);
			e.preventDefault();
			return false;
		}

		instance.navigation.next.className = args.nextClass || 'galleryNext';
		instance.navigation.next.style.position = 'absolute';
		instance.closeButton.className = args.closeClass || 'galleryClose';
		instance.closeButton.style.position = 'absolute';
		instance.navigation.previous.className = args.previousClass || 'galleryPrevious';
		instance.navigation.previous.style.position = 'absolute';
		instance.frame.className = args.frameClass || 'frame gallery';
		appendEvent('resize', window, instance.resize, false);
		appendEvent('scroll', window.document, instance.resize , false);
		instance.resize();
		instance.finalLeft = (document.documentElement.clientWidth / 2) - (instance.rect.width / 2);
		if(args.galleryId!=undefined){
			var request = [
				'getGallery',
				[args.galleryId]
			]
			args.data = 'method1=' + encodeURIComponent(JSON.stringify(request));
		}
		$.ajax({
			type: "POST",
			url: args.URL||window.responderURL,
			data: args.data,
			processData: false,
			dataType: "json",
			success: instance.initCallback
		});
	}
	instance.dispose = function(){
		if(instance.frame.parentNode==document.body){document.body.removeChild(instance.frame);};
		if(instance.modalBackground.parentNode==document.body){document.body.removeChild(instance.modalBackground)};
		removeEvent('resize', window, instance.resize, false);
		removeEvent('scroll', window.document, instance.resize , false);
		instance.frame = undefined;
		instance.frame = instance.modalBackground;
		instance = undefined;
	}
	instance.loadImage = function (imageIndex) {
		var h = instance.navigation.pages.length;
		for (var x = 0; h > x; x++) {
			instance.navigation.pages[x].className = args.pageClass || 'galleryPages';
			instance.navigation.pages[x].style.position = 'absolute';
		}
		instance.navigation.pages[imageIndex].className = args.pageActiveClass || 'galleryActivePage';
		instance.oldImage = instance.currentImage;
		instance.currentImage = instance.images[imageIndex];

		if (instance.currentImage == undefined) {
			instance.currentImage = instance.images[0];
		}
		
		if (instance.currentImage.loaded) {
			instance.currentImage.frameAnimate();
		} else {
			instance.currentImage.src = instance.currentImage.getAttribute('path');
		}
	}
	instance.frameAnimate = function (oldImage, newImage) {
		var callback = function () {
			var h = instance.frame.childNodes.length;
			for (var x = 0; h > x; x++) {
				if (instance.frame.childNodes[x] == oldImage) {
					instance.frame.removeChild(oldImage);
				}
			}
			callbackProcedure.call();
		}
		if (typeof args.frameAnimate == 'function') {
			args.frameAnimate.apply(instance, [instance.frame, oldImage, newImage]);
		} else {
			instance.defaultAnimate(instance.frame, oldImage, newImage);
		}
	}
	instance.defaultAnimate = function (frame, oldImage, newImage) {
		/* 
		the old image starts as the only element in the frame
		your job, if you choose to replace this default function,
		is to get the new image in the frame and remove the old image
		and do it in a stylish way - then call the callback procedure
		using call or apply
		*/
		
		newImage.style.position = 'absolute';
		newImage.style.opacity = 0;
		newImage.style.left = ((frame.offsetWidth/2)-(newImage.width/2))+'px';
		newImage.style.top = '20px';
		frame.appendChild(newImage);
		/* if you fade all the way out JQuery likes to be "helpfull" and remove the node */
		$(oldImage).animate({ opacity: .01 }, instance.defaultAnimateInterval);
		$(newImage).animate({ opacity: 1 }, instance.defaultAnimateInterval);
	}


	instance.init();
}
/* creates a gallery dialog (DIV) that displays a list of gallery images
based on the Id of a single image in the gallery.
This function is also called by the galleryRotator function.
accepts DHTML image element, argument dictionary {
	pageAlign:<where to align the page buttons default:{x: 'right', y: 'bottom'}>
	interval:<time in ms to wait between images default:1000 (1 second)>
	defaultAnimateInterval:<how long it takes for animations to occur default: 2000 (2 seconds)>
	pauseText:<text to display on the play/pause button when it is paused default: "||">
	transportPlayClass:<the class the 'play/pause' button uses while playing: 'galleryPlay'>
	transportClass:< the class the 'play/pause' button uses while not playing default:"galleryPlay">
	playText:<text to display on the play/pause button when it is playing default: "&rang;">
	nextClass:<the CSS class the 'next' button uses default: 'galleryNext'>
	previousClass:<the CSS class the 'previous' button uses default: 'galleryPrevious'>
	frameClass:<the CSS the frame DIV uses default: 'frameClass'>
	pageClass:<the CSS class the page buttons use default:'galleryPages'>
	pageActiveClass:<the CSS class the 'active page' uses default:'galleryActivePage'>
	alwaysShowPages:<boolean - if the pages are shown even when the mouse isn't hovering default:false>
	frameAnimate:<procedure to use to animate images changing. Signature: (frame, oldImage, newImage), Default: gallery.defaultAnimate >
} */
function galleryRotator(image, args) {
	/* identifiy the gallery */
	var id = image.getAttribute('galleryId');
	if (id == undefined) { return; };
	if (args == undefined) { args = {}; };
	var instance = {};
	instance.pageMargin = 5;
	instance.pageAlign = args.pageAlign || { x: 'right', y: 'bottom' };
	instance.index = 0;
	instance.images = [];
	instance.navigation = {
		pages : []
	}
	instance.initalImage = image;
	instance.interval = args.interval || 1000;
	instance.defaultAnimateInterval = args.interval || 2000;
	instance.transportPlay = args.playTransport || true;
	instance.frameMouseover = function (e) {
		instance.transportPlay = false;
		$(instance.oldImage).stop(true, true);
		$(instance.currentImage).stop(true, true);
		instance.showTransport();
		instance.navigation.transport.innerHTML = args.pauseText != undefined ? args.pauseText : '||';
		clearTimeout(instance.timer);
		instance.timer = undefined;
		e.cancelBubble = true;
	}
	instance.frameMouseout = function (e) {
		instance.transportPlay = true;
		$(instance.oldImage).stop(true, true);
		$(instance.currentImage).stop(true, true);
		instance.hideTransport();
		if (instance.timer != undefined) {
			clearTimeout(instance.timer);
		}
		instance.timer = setTimeout(instance.elapsed, instance.interval);
		e.cancelBubble = true;
	}
	instance.initCallback = function (e) {
		if (e.method1.error != undefined) { return; };
		if (e.method1.getGallery.error != 0) { return; };
		instance.gallery = e.method1.getGallery.gallery;
		/* create a div that will lay on top of the image */
		instance.height = instance.initalImage.offsetHeight;
		instance.width = instance.initalImage.offsetWidth;
		instance.frame = document.createElement('div');
		instance.navigation.previous = document.createElement('button');
		instance.navigation.next = document.createElement('button');
		instance.navigation.transport = document.createElement('button');
		instance.navigation.previous.ondblclick = function (e) {
			e.preventDefault();
			return false;
		}
		instance.navigation.next.ondblclick = function (e) {
			e.preventDefault();
			return false;
		}
		instance.navigation.previous.onclick = function (e) {
			instance.transportPlay = true;
			$(instance.oldImage).stop(true, true);
			$(instance.currentImage).stop(true, true);
			instance.index = instance.index == 0 ? instance.images.length - 1 : instance.index - 1;
			instance.loadImage(instance.index);
			instance.transportPlay = false;
			$(instance.oldImage).stop(true, true);
			$(instance.currentImage).stop(true, true);
			e.preventDefault();
			return false;
		}
		instance.navigation.next.onclick = function (e) {
			instance.transportPlay = true;
			$(instance.oldImage).stop(true, true);
			$(instance.currentImage).stop(true, true);
			instance.index = instance.index == instance.images.length - 1 ? 0 : instance.index + 1;
			instance.loadImage(instance.index);
			instance.transportPlay = false;
			$(instance.oldImage).stop(true, true);
			$(instance.currentImage).stop(true, true);
			e.preventDefault();
			return false;
		}
		instance.navigation.transport.onclick = function () {
			instance.transportPlay = !instance.transportPlay;
			if (instance.transportPlay) {
				removeEvent('mouseover', instance.frame, instance.frameMouseover, true);
				appendEvent('mouseover', instance.frame, function (e) {
					appendEvent('mouseover', instance.frame, instance.frameMouseover, true);
					removeEvent('mouseover', instance.frame, arguments.callee, true);
					e.cancelBubble = true;
					e.preventDefault();
					return false;
				}, true);
				instance.navigation.transport.className = args.transportPlayClass || 'galleryPlay';
				instance.navigation.transport.innerHTML = args.playText != undefined ? args.playText : '&rang;';
				instance.hideTransport();
				if (instance.timer != undefined) {
					clearTimeout(instance.timer);
				}
				instance.timer = setTimeout(instance.elapsed, instance.interval);
			} else {
				instance.navigation.transport.className = args.transportPauseClass || 'galleryPause';
				instance.navigation.transport.innerHTML = args.pauseText != undefined ? args.pauseText : '||';
			}
		}
		instance.navigation.next.className = args.nextClass || 'galleryNext';
		instance.navigation.next.style.position = 'absolute';
		instance.navigation.next.style.visibility = 'hidden';
		instance.navigation.previous.className = args.previousClass || 'galleryPrevious';
		instance.navigation.previous.style.position = 'absolute';
		instance.navigation.previous.style.visibility = 'hidden';
		instance.navigation.transport.className = args.transportClass || 'galleryPlay';
		instance.navigation.transport.style.position = 'absolute';
		instance.navigation.transport.style.visibility = 'hidden';
		instance.frame.className = args.frameClass || 'frame';
		if (instance.initalImage.style.position == 'absolute' || instance.initalImage.style.position == 'relative') {
			instance.frame.style.top = instance.initalImage.style.top;
			instance.frame.style.left = instance.initalImage.style.left;
		}
		instance.frame.style.display = instance.initalImage.style.display || 'inline-block';
		instance.frame.style.position = instance.initalImage.style.position || 'inherit';
		instance.frame.style.margin = instance.initalImage.style.margin || '0';
		instance.frame.style.border = instance.initalImage.style.border || 'none';
		instance.frame.style.height = instance.initalImage.offsetHeight + 'px';
		instance.frame.style.width = instance.initalImage.offsetWidth + 'px';
		instance.frame.style.overflow = 'none';
		appendEvent('mouseover', instance.frame, instance.frameMouseover, true);
		appendEvent('mouseout', instance.frame, instance.frameMouseout, true);
		instance.initalImage.parentNode.insertBefore(instance.frame, instance.initalImage);
		instance.initalImage.style.position = 'absolute';
		var h = instance.gallery.images.length;
		for (var x = 0; h > x; x++) {
			var pageText = (x + 1);
			if (args.pageText != undefined) {
				pageText = args.pageText.replace('<page>', (x + 1));
			}
			var page = document.createElement('button');
			page.style.cursor = 'pointer';
			page.onmousedown = function (e) {
				e.preventDefault();
				return false;
			}
			if (x == 0) {
				page.className = args.pageActiveClass || 'galleryActivePage';
			} else {
				page.className = args.pageClass || 'galleryPages';
			}
			var showPages = args.alwaysShowPages == undefined ? false : args.alwaysShowPages;
			if (showPages) {
				page.style.visibility = 'hidden';
			}
			page.index = parseInt(x);
			page.style.position = 'absolute';
			page.onclick = function () {
				if (this.index == instance.index) { return; };
				instance.index = this.index;
				$(instance.oldImage).stop(true, true);
				$(instance.currentImage).stop(true, true);
				instance.transportPlay = true;
				instance.loadImage(this.index);
				$(instance.oldImage).stop(true, true);
				$(instance.currentImage).stop(true, true);
				instance.transportPlay = false;
			}
			page.innerHTML = pageText;
			instance.navigation.transport.innerHTML = args.playText != undefined ? args.playText : '||';
			instance.navigation.previous.innerHTML = args.previousText != undefined ? args.previousText : '&lArr;';
			instance.navigation.next.innerHTML = args.nextText != undefined ? args.nextText : '&rArr;';
			instance.frame.appendChild(page);
			instance.frame.appendChild(instance.navigation.previous);
			instance.frame.appendChild(instance.navigation.next);
			instance.frame.appendChild(instance.navigation.transport);
			instance.navigation.pages.push(page);
			if (x == 0) {
				var i = instance.initalImage;
				instance.currentImage = i;
				i.loaded = true;
			} else {
				var i = new Image();
				i.loaded = false;
			}
			appendEvent('load', i, function () {
				this.loaded = true;
				this.frameAnimate();
			}, false);
			i.frameAnimate = function () {
				instance.frameAnimate(instance.oldImage, instance.currentImage, function () {
					if (instance.timer != undefined) {
						clearTimeout(instance.timer);
						instance.timer = undefined;
					}
					instance.timer = setTimeout(instance.elapsed, instance.interval);
				});
			}
			i.gallery = instance.gallery;
			i.image = instance.gallery.images[x];
			i.onclick = function(){
				new gallery({galleryId:this.gallery.id,rect:args.rect});
			}
			i.index = x;
			instance.images.push(i);
		}
		var showPages = args.alwaysShowPages == undefined ? false : args.alwaysShowPages;
		if (!showPages) {
			var h = instance.navigation.pages.length;
			for (var x = 0; h > x; x++) {
				instance.navigation.pages[x].style.visibility = 'hidden';
			}
		}
		instance.frame.appendChild(instance.initalImage);
		instance.positionButtons();
		instance.timer = setTimeout(instance.elapsed, instance.interval);
	}
	instance.showTransport = function () {
		instance.navigation.next.style.visibility = 'visible';
		instance.navigation.previous.style.visibility = 'visible';
		instance.navigation.transport.style.visibility = 'visible';
		var showPages = args.alwaysShowPages == undefined ? false : args.alwaysShowPages;
		if (!showPages) {
			var h = instance.navigation.pages.length;
			for (var x = 0; h > x; x++) {
				instance.navigation.pages[x].style.visibility = 'visible';
			}
		}
	};
	instance.hideTransport = function () {
		instance.navigation.next.style.visibility = 'hidden';
		instance.navigation.previous.style.visibility = 'hidden';
		instance.navigation.transport.style.visibility = 'hidden';
		var showPages = args.alwaysShowPages == undefined ? false : args.alwaysShowPages;
		if (!showPages) {
			var h = instance.navigation.pages.length;
			for (var x = 0; h > x; x++) {
				instance.navigation.pages[x].style.visibility = 'hidden';
			}
		}
	};
	instance.positionButtons = function () {
		var h = instance.navigation.pages.length;
		var x = 0;
		var y = 0;
		var pH = instance.navigation.pages[0].offsetHeight;
		var pW = instance.navigation.pages[0].offsetWidth;
		var totalW = (instance.navigation.pages.length * (pW + instance.pageMargin));
		var rx = 0;
		var pbH = instance.navigation.previous.offsetHeight;
		var pbW = instance.navigation.previous.offsetWidth;
		var nbH = instance.navigation.next.offsetHeight;
		var nbW = instance.navigation.next.offsetWidth;
		var tbW = instance.navigation.transport.offsetWidth;
		var tbH = instance.navigation.transport.offsetHeight;
		instance.navigation.previous.style.marginTop = (parseInt(instance.height / 2) + parseInt(pbH / 2) - pbH) + 'px';
		instance.navigation.previous.style.marginLeft = instance.pageMargin + 'px';

		instance.navigation.next.style.marginTop = (parseInt(instance.height / 2) + parseInt(nbH / 2) - nbH ) + 'px';
		instance.navigation.next.style.marginLeft = ((instance.width - instance.pageMargin) - nbW) + 'px';

		instance.navigation.transport.style.marginTop = (parseInt(instance.height / 2) + parseInt(tbH / 2) - tbH) + 'px';
		instance.navigation.transport.style.marginLeft = ((tbW / 2) + (instance.width/2) - tbW) + 'px';

		for (var x = h - 1; -1 < x; x--) {
			var p = instance.navigation.pages[x];
			if (instance.pageAlign.x == 'top') {
				p.style.marginTop = instance.pageMargin + 'px';
			} else {
				p.style.marginTop = (instance.height - instance.pageMargin - pH) + 'px';
			}
			if (instance.pageAlign.x == 'right') {
				p.style.marginLeft = (totalW - rx) + 'px';
			} else {
				p.style.marginLeft = (instance.pageMargin + rx) + 'px';
			}
			rx += instance.pageMargin + pW;
		}
	}
	instance.init = function () {
		/* fetch all the other images via an ajax request */
		var request = [
			'getGallery',
			[id]
		]
		$.ajax({
			type: "POST",
			url: window.responderURL,
			data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
			processData: false,
			dataType: "json",
			success: instance.initCallback
		});
		
	}
	instance.elapsed = function () {
		if (!instance.transportPlay) { return };
		/* time has passed so load another image */
		instance.index = instance.currentImage.index + 1;
		if (instance.index == instance.gallery.images.length) {
			instance.index = 0;
		}
		instance.loadImage(instance.index);
	}
	instance.loadImage = function (imageIndex) {
		if (!instance.transportPlay) { return };
		var h = instance.navigation.pages.length;
		for (var x = 0; h > x; x++) {
			instance.navigation.pages[x].className = args.pageClass || 'galleryPages';
			instance.navigation.pages[x].style.position = 'absolute';
		}
		instance.navigation.pages[imageIndex].className = args.pageActiveClass || 'galleryActivePage';
		instance.oldImage = instance.currentImage;
		instance.currentImage = instance.images[imageIndex];
		if (instance.currentImage == undefined) {
			instance.currentImage = instance.images[0];
		}
		var srcs = instance.currentImage.image;
		if (instance.currentImage.loaded) {
			instance.currentImage.frameAnimate();
		} else {
			instance.currentImage.src = srcs.rotator;
		}
	}
	instance.frameAnimate = function (oldImage, newImage, callbackProcedure) {
		var callback = function () {
			var h = instance.frame.childNodes.length;
			for (var x = 0; h > x; x++) {
				if (instance.frame.childNodes[x] == oldImage) {
					instance.frame.removeChild(oldImage);
				}
			}
			callbackProcedure.call();
		}
		if (typeof args.frameAnimate == 'function') {
			args.frameAnimate.apply(instance, [instance.frame, oldImage, newImage, callback]);
		} else {
			instance.defaultAnimate(instance.frame, oldImage, newImage, callback);
		}
	}
	instance.defaultAnimate = function (frame, oldImage, newImage, callbackProcedure) {
		/* 
		the old image starts as the only element in the frame
		your job, if you choose to replace this default function,
		is to get the new image in the frame and remove the old image
		and do it in a stylish way - then call the callback procedure
		using call or apply
		*/
		newImage.style.position = 'absolute';
		newImage.style.opacity = 0;
		frame.appendChild(newImage);
		/* if you fade all the way out JQuery likes to be "helpfull" and remove the node */
		$(oldImage).animate({ opacity: .01 }, instance.defaultAnimateInterval);
		$(newImage).animate({ opacity: 1 }, instance.defaultAnimateInterval, function () {
			callbackProcedure.call();
		});
	}
	instance.init();
}
/* logs the user off of the system.
using rendition.dll -> site.logoff.
accepts one argument dictionary {
	infoId:<ID of a DHTML element that should contain a link to log back on after logoff success>
	callbackProcedure:<procedure to execute after logoff success>
}
 */
function logoff(args){
	var request = [
		'logoff',
		[{}]
	]
	$.ajax({
		type: "POST",
		url: window.responderURL,
		data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
		processData: false,
		dataType: "json",
		success: function(e){
			window.user = {
				email: '',
				userId: -1
			}
			window.loggedon = false;
			if(args.infoId!=undefined){
				var info = document.getElementById(args.infoId);
				info.innerHTML = '<a onclick="javascript:logon({infoId:\'logonInfo\'});">Logon</a>';
			}
			if(args.callbackProcedure!=undefined){
				callbackProcedure.apply(this,[e]);
			}
			if(window.location.toString().match(/^.*(cart|checkout)*.$/)){
				window.location = '/';
			}
		}
	});
}
/* logs the user onto the system using a dialog (DIV) with fields and buttons nessessary to do so.
The logon procedure organicly contains a method to create accounts.  A create account button is also provided.
using rendition.dll -> site.logon.
Also includes a seperate function to retreive a lost password via rendition.dll lostPassword email event handler.
accepts one argument dictionary {
	marginTop:<how far away the dialog (absolutly position DIV) should be placed from the top of the window default: 50>
	width:<the width of the dialog default:300>
	height:<the height of the dialog default:120>
	animationTimer:<time for the animation to complete default: 'fast' (JQuery, 'fast','slow',100 etc)
	animationEasing:<easing method of the animation default: 'linear' (JQuery easing methods)
	cancelCallbackProcedure:<the procedure to execute if the user clicks the cancel button to close the dialog>
	forgotPasswordMessage:<message that appears in the lost password dialog default: suffice to say there is a default>,
	successColor:<color of the message that appears when logon is successfull default: green (standard DHTML colors)>
	successMessageDelay:<number of ms for the success message to stay before the dialog is closed default: 2500 (2.5 seconds)>
	errorColor:<color of the messaga that displays errors (wrong password etc) default:red>
	infoId:<ID of the DHTML element that should contain a link to logoff once the user is succussfully logged on>
	callbackProcedure:<the procedure to execute once the user is successfully logged on>
}
 */
function logon(args){
	var instance = {};
	if(args==undefined){
		args = {};
	}
	instance.margin = {
		top:args.marginTop||50
	}
	instance.rect = {
		width:args.width||300,
		height:args.height||120
	}
	instance.animationTimer = args.animationTimer||'fast';
	instance.animationEasing = args.animationEasing||'linear';
	instance.logonCancel = function(){
		if(args.cancelCallbackProcedure!=undefined){
			args.cancelCallbackProcedure.apply(this,[instance]);
		}
		instance.close();
	}
	instance.close = function(){
		removeEvent('resize', window, instance.resize, false);
		removeEvent('scroll', window.document, instance.resize , false);
		document.body.removeChild(instance.modalBackground);
		document.body.removeChild(instance.logon);
		instance.modalBackground = undefined;
		instance.logon = undefined;
		instance.password = undefined;
		instance.email = undefined;
		instance = undefined;
	}
	instance.resize = function () {
		var p = {
			t:document.documentElement.scrollTop,
			l:document.documentElement.scrollLeft,
			h:document.documentElement.clientHeight,
			w:document.documentElement.clientWidth
		}
		instance.modalBackground.style.height = p.h + 'px';
		instance.modalBackground.style.width = p.w + 'px';
		instance.modalBackground.style.top = p.t + 'px';
		instance.modalBackground.style.left = p.l + 'px';
		instance.logon.style.top = instance.finalTop() + 'px';
		instance.logon.style.left = (document.documentElement.clientWidth / 2 - (instance.rect.width / 2)) + 'px';
	}
	instance.forgotPassword = function(){
		/* 
			hide the password text and input row, unhide the msg row
			hide the three buttons, unhide button that activates the email thing
			on return display email success/failure then return logon buttons and row
		*/
		instance.h(instance.forgotPasswordLink);
		instance.errormsg.className = '';
		instance.errormsg.color = 'inherit';
		instance.errormsg.innerHTML = args.forgotPasswordMessage||'Enter your email address in the email field above and press \'Send Password Email\' \
		to have your password sent to your email inbox.';
		instance.h(instance.cancelButton);
		instance.h(instance.logonButton);
		instance.h(instance.createAccountButton);
		instance.s(instance.cancelSendEmailButton);
		instance.s(instance.sendEmailButton);
		instance.passwordRow.style.visibility = 'hidden';
		instance.passwordRow.style.display = 'none';
	}
	instance.cancelSendEmail = function(){
		instance.errormsg.innerHTML = '';
		instance.errormsg.className = 'errormsg';
		instance.h(instance.cancelSendEmailButton);
		instance.h(instance.sendEmailButton);
		instance.s(instance.cancelButton);
		instance.s(instance.logonButton);
		instance.s(instance.createAccountButton);
		instance.s(instance.forgotPasswordLink);
		instance.passwordRow.style.visibility = 'visible';
		instance.passwordRow.style.display = 'table-row';
	}
	instance.tryCreateAccount = function(){
		var request = [
			'createAccount',
			[
				{
					email:instance.email.value,
					password:instance.password.value,
					showUserData:true
				}
			]
		]
		$.ajax({
			type: "POST",
			url: window.responderURL,
			data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
			processData: false,
			dataType: "json",
			success: instance.createAccountTryCallback
		});
	}
	instance.tryLogon = function(){
		var request = [
			'logon',
			[
				{
					email:instance.email.value,
					password:instance.password.value,
					showUserData:true
				}
			]
		]
		$.ajax({
			type: "POST",
			url: window.responderURL,
			data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
			processData: false,
			dataType: "json",
			success: instance.logonTryCallback
		});
	}
	instance.emailTry = function(){
		var request = [
			'sendPasswordEmail',
			[
				{
					email:instance.email.value
				}
			]
		]
		$.ajax({
			type: "POST",
			url: window.responderURL,
			data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
			processData: false,
			dataType: "json",
			success: instance.logonTryCallback
		});
	}
	instance.emailTryCallback = function(e){
		if(e.method1.error!=undefined){
			alert('Exception Error:'+e.method1.error+":"+e.method1.desc);
		}
		if(e.method1.logon.error!=0){
			alert('Exception Error:'+e.method1.error+":"+e.method1.desc);
		}else{
			instance.errormsg.style.color = args.successColor||'green';
			instance.errormsg.innerHTML = e.method1.sendPasswordEmail.desc;
			setTimeout(function(){
				instance.close();
			},args.successMessageDelay||2500);
		}
	}
	instance.createAccountTryCallback = function(e){
		if(e.method1.error!=undefined){
			alert('Exception Error:'+e.method1.error+":"+e.method1.desc);
		}
		if(e.method1.createAccount.error!=0){
			instance.errormsg.style.color = args.errorColor||'red';
			instance.errormsg.innerHTML = e.method1.createAccount.desc;
		}else{
			window.user = e.method1.createAccount.user;
			instance.errormsg.style.color = args.successColor||'green';
			instance.errormsg.innerHTML = e.method1.createAccount.desc;
			setTimeout(function(){
				if(args.callbackProcedure!=undefined){
					args.callbackProcedure.apply(this,[]);
				}
				instance.close();
			},args.successMessageDelay||2500);
		}
	}
	instance.logonTryCallback = function(e){
		if(e.method1.error!=undefined){
			alert('Exception Error:'+e.method1.error+":"+e.method1.desc);
		}
		if(e.method1.logon.error!=0){
			instance.errormsg.style.color = args.errorColor||'red';
			instance.errormsg.innerHTML = e.method1.logon.desc;
		}else{
			window.user = e.method1.logon.user;
			instance.errormsg.style.color = args.successColor||'green';
			instance.errormsg.innerHTML = e.method1.logon.desc;
			setTimeout(function(){
				if(args.infoId!=undefined){
					var info = document.getElementById(args.infoId);
					info.innerHTML = '<a onclick="javascript:logoff({infoId:\'logonInfo\'});">Logoff</a>';
				}
				if(args.callbackProcedure!=undefined){
					args.callbackProcedure.apply(this,[]);
				}
				instance.close();
			},args.successMessageDelay||2500);
		}
	}
	instance.submitOnEnter = function(e){
		if(e.keyCode==13){
			instance.tryLogon();
		}
	}
	instance.h = function(b){
		b.style.visibility = 'hidden';
		b.style.display = 'none';
	}
	instance.s = function(b){
		b.style.visibility = 'visible';
		b.style.display = 'inline-block';
	}
	instance.init = function(){
		instance.modalBackground = document.createElement('div');
		instance.logon = document.createElement('div');
		instance.logon.style.position = 'absolute';
		instance.logon.style.zIndex = '9997';
		instance.logon.className = 'logon';
		instance.finalLeft = (document.documentElement.clientWidth / 2) - (instance.rect.width / 2);
		instance.finalTop = function(){return document.documentElement.scrollTop + instance.margin.top};
		instance.logon.style.top = instance.finalTop()+'px';
		instance.logon.style.left = (document.documentElement.clientWidth / 2 - (instance.rect.width / 2)) + 'px';

		instance.logon.style.width = instance.rect.width+'px';
		instance.logon.style.height = '1px';

		instance.modalBackground.style.background = 'url(/img/25PctAlphaBlackDot.png)';
		instance.modalBackground.style.position = 'absolute';
		instance.modalBackground.style.zIndex = '9996';

		appendEvent('resize', window, instance.resize, false);
		appendEvent('scroll', window.document, instance.resize , false);

		instance.resize();

		instance.formTable = document.createElement('table');
		instance.formTable.className = '';
		instance.formTable.style.width = '100%';
		instance.formTable.style.marginTop = '10px';

		instance.email = document.createElement('input');
		if(window.loggedon==true){
			instance.email.value = window.user.email;
		}
		instance.email.style.width = '95%';
		instance.email.onkeypress = instance.submitOnEnter;
		instance.password = document.createElement('input');
		instance.password.style.width = '95%';
		instance.password.onkeypress = instance.submitOnEnter;
		instance.password.type = 'password';
		instance.cancelButton = document.createElement('button');
		instance.logonButton = document.createElement('button');
		instance.createAccountButton = document.createElement('button');
		instance.sendEmailButton = document.createElement('button');
		instance.cancelSendEmailButton = document.createElement('button');
		instance.cancelButton.style.margin = '4px';
		instance.logonButton.style.margin = '4px';
		instance.createAccountButton.style.margin = '4px';
		instance.sendEmailButton.style.margin = '4px';
		instance.cancelSendEmailButton.style.margin = '4px';
		instance.cancelButton.onclick = instance.logonCancel;
		instance.logonButton.onclick = instance.tryLogon;
		instance.createAccountButton.onclick = instance.tryCreateAccount;
		instance.cancelSendEmailButton.onclick = instance.cancelSendEmail;
		instance.cancelButton.innerHTML = 'Cancel';
		instance.logonButton.innerHTML = 'Logon';
		instance.createAccountButton.innerHTML = 'Create New Account';
		instance.cancelSendEmailButton.innerHTML = 'Cancel';
		instance.sendEmailButton.innerHTML = 'Send Password Email';
		instance.forgotPasswordLink = document.createElement('a');
		instance.forgotPasswordLink.className = 'forgotPasswordLink';
		instance.forgotPasswordLink.style.cursor = 'pointer';
		instance.forgotPasswordLink.onclick = instance.forgotPassword;
		instance.forgotPasswordLink.innerHTML = 'Forgot your password?';

		instance.errormsg = document.createElement('span');
		instance.errormsg.className = 'errormsg';

		var t = instance.formTable;
		var r3 = t.insertRow(0);
		var r2 = t.insertRow(0);
		var r1 = t.insertRow(0);
		var r3c1 = r3.insertCell(0);
		r3c1.setAttribute('colspan','2');
		var r2c2 = r2.insertCell(0);
		var r2c1 = r2.insertCell(0);
		var r1c2 = r1.insertCell(0);
		var r1c1 = r1.insertCell(0);

		r1c1.style.textAlign = 'right';
		r1c2.style.fontWeight = 'bold';
		r2c1.style.textAlign = 'right';
		r2c2.style.fontWeight = 'bold';
		r1c1.appendChild(document.createTextNode('Email'));
		r1c2.appendChild(instance.email);
		r2c1.appendChild(document.createTextNode('Password'));
		r2c2.appendChild(instance.password);
		r3c1.style.padding = '4px';
		r3c1.style.textAlign = 'right';

		instance.passwordRow = r2;

		instance.h(instance.cancelSendEmailButton);
		instance.h(instance.sendEmailButton);

		r3c1.appendChild(instance.createAccountButton);
		r3c1.appendChild(instance.cancelButton);
		r3c1.appendChild(instance.logonButton);
		r3c1.appendChild(instance.sendEmailButton);
		r3c1.appendChild(instance.cancelSendEmailButton);
		
		r3c1.appendChild(document.createElement('br'));
		r3c1.appendChild(instance.forgotPasswordLink);
		r3c1.appendChild(instance.errormsg);

		document.body.appendChild(instance.modalBackground);
		document.body.appendChild(instance.logon);
		instance.logon.appendChild(t);

		$(instance.logon).animate({ width: instance.rect.width, left: instance.finalLeft }, instance.animationTimer, instance.animationEasing, function () {
			$(instance.logon).animate({ height: instance.rect.height  }, instance.animationTimer, instance.animationEasing, function(){
				instance.email.focus();
				instance.email.select();
			});
		});
		return instance;
	}
	return instance.init();
}
/* 
produces a dialog (DIV) that contains default buttons and fields nessessary reply to a blog entry

accepts DHTML button(reply button), argument dictionary {
	marginTop:<top margin of the absolutly position div from the top of the window default: 50>
	width:<width of the dialog default: 600>
	height:<height of the dialog default: 435>
	previewMarginTop:<size of the margin of the absolutly position div preview default: 10>
	previewWidth:<width of the preview of the message default: 800>
	previewHeight:<height of the preview of the message default: 450>
	animationTimer:<time for the animation to complete default: 'fast' (JQuery, 'fast','slow',100 etc)
	animationEasing:<easing method of the animation default: 'linear' (JQuery easing methods)
	parentId:<reloads this DHTML object with a fresh list of replies to this blog>
}
*/
function reply(button,args) {
	if(window.user.userId==-1||window.user==undefined){
		new logon({
			callbackProcedure:function(){
				reply(button,args);
			}
		});
		return;
	}
	var instance = {};
	if(args==undefined){
		args = {};
	}
	instance.margin = {
		top:args.marginTop||50
	}
	instance.rect = {
		width:args.width||600,
		height:args.height||435
	}
	instance.previewMargin = {
		top:args.previewMarginTop||10
	}
	instance.previewRect = {
		width:args.previewWidth||800,
		height:args.previewHeight||450
	}
	instance.animationTimer = args.animationTimer||'fast';
	instance.animationEasing = args.animationEasing||'linear';
	instance.resize = function () {
		var p = {
			t:document.documentElement.scrollTop,
			l:document.documentElement.scrollLeft,
			h:document.documentElement.clientHeight,
			w:document.documentElement.clientWidth
		}
		instance.modalBackground.style.height = p.h + 'px';
		instance.modalBackground.style.width = p.w + 'px';
		instance.modalBackground.style.top = p.t + 'px';
		instance.modalBackground.style.left = p.l + 'px';
		instance.reply.style.top = instance.finalTop() + 'px';
		instance.preview.style.top = instance.finalPreviewTop() + 'px';
		instance.reply.style.left = (document.documentElement.clientWidth / 2 - (instance.rect.width / 2)) + 'px';
		instance.preview.style.left = (document.documentElement.clientWidth / 2 - (instance.previewRect.width / 2)) + 'px';
	}
	instance.init = function () {

		instance.reply = document.createElement('div');
		instance.modalBackground = document.createElement('div');
		instance.preview = document.createElement('div');
		instance.preview.className = 'replyWindow previewWindow';
		instance.preview.style.zIndex = '9998';
		instance.preview.style.position = 'absolute';
		
		instance.finalLeft = (document.documentElement.clientWidth / 2) - (instance.rect.width / 2);
		instance.finalPreviewLeft = (document.documentElement.clientWidth / 2) - (instance.previewRect.width / 2);
		+ document.documentElement.scrollLeft + instance.margin.left;
		instance.finalTop = function(){return document.documentElement.scrollTop + instance.margin.top};
		instance.finalPreviewTop = function(){return document.documentElement.scrollTop + instance.previewMargin.top};
		instance.reply.style.top = instance.finalTop();
		instance.reply.style.left = (document.documentElement.clientWidth / 2 - (instance.rect.width / 2)) + 'px';
		instance.preview.style.top = instance.finalPreviewTop();
		instance.preview.style.left = (document.documentElement.clientWidth / 2 - (instance.previewRect.width / 2)) + 'px';
		instance.modalBackground.style.background = 'url(/img/25PctAlphaBlackDot.png)';
		instance.modalBackground.style.position = 'absolute';
		instance.modalBackground.style.zIndex = '9996';
		instance.reply.className = 'replyWindow';
		instance.reply.style.zIndex = '9997';
		instance.reply.style.position = 'absolute';
		appendEvent('resize', window.document, instance.resize, false);
		appendEvent('scroll', window.document, instance.resize , false);
		instance.reply.style.width = 10 + 'px';
		instance.reply.style.height = 10 + 'px';
		instance.resize();
		

		instance.formTable = document.createElement('table');
		instance.formTable.className = 'blogReply';
		instance.formTable.style.width = '100%';
		instance.formTable.style.marginTop = '10px';

		instance.subject = document.createElement('input');
		instance.message = document.createElement('textarea');
		instance.cancelButton = document.createElement('button');
		instance.postButton = document.createElement('button');
		instance.previewButton = document.createElement('button');

		instance.subject.style.width = '350px';

		instance.cancelButton.onclick = instance.close;
		instance.postButton.onclick = instance.submit;
		instance.previewButton.onclick = instance.replyPreview;

		instance.cancelButton.style.margin = '4px';
		instance.postButton.style.margin = '4px';
		instance.previewButton.style.margin = '4px';

		instance.cancelButton.innerHTML = 'Cancel';
		instance.postButton.innerHTML = 'Post';
		instance.previewButton.innerHTML = 'Preview';


		var t = instance.formTable;
		var r3 = t.insertRow(0);
		var r2 = t.insertRow(0);
		var r1 = t.insertRow(0);
		var r3c1 = r3.insertCell(0);
		r3c1.setAttribute('colspan','2');
		var r2c1 = r2.insertCell(0);
		r2c1.setAttribute('colspan','2');
		var r1c2 = r1.insertCell(0);
		var r1c1 = r1.insertCell(0);

		r1c1.style.textAlign = 'right';
		r1c2.style.fontWeight = 'bold';
		r2c1.style.textAlign = 'center';
		r1c1.appendChild(document.createTextNode('Subject'));
		r1c2.appendChild(instance.subject);
		r2c1.appendChild(instance.message);
		r3c1.style.padding = '4px';
		r3c1.style.textAlign = 'right';
		instance.message.style.width = '550px';
		instance.message.style.height = '350px';
		
		r3c1.appendChild(instance.cancelButton);
		r3c1.appendChild(instance.postButton);
		r3c1.appendChild(instance.previewButton);
		document.body.appendChild(instance.modalBackground);
		document.body.appendChild(instance.reply);

		instance.reply.appendChild(instance.formTable);


		$(instance.reply).animate({ width: instance.rect.width, left: instance.finalLeft }, instance.animationTimer, instance.animationEasing, function () {
			$(instance.reply).animate({ height: instance.rect.height  }, instance.animationTimer, instance.animationEasing, function(){
				instance.subject.focus();
				instance.subject.select();
			});
		});
		return instance;
	}
	instance.close = window.replyCancel = function (e) {
		instance.dispose();
	}
	instance.formStruct = function(){
		return {
			message:instance.message.value,
			subject:instance.subject.value
		}
	}
	instance.getReplyMethod = function(button,preview){
		/* find the current form by traversing out from the button until we find the blogReply class element
		that was cloned from the aspx page */
		var e = button.parentNode;
		while(e){
			if(e.className=='blogReply'){
				break;
			}
			e = e.parentNode;
		}
		/* grab the input elements as JSON from the node we just found */
		var f = instance.formStruct();
		f.parentId = args.parentId;
		f.preview = preview;
		return [
			'addReply',
			[
				f
			]
		]
	}
	instance.submit = window.replySubmit = function (button) {
		$.ajax({
			type: "POST",
			url: window.responderURL,
			data: 'method1=' + encodeURIComponent(JSON.stringify(instance.getReplyMethod(button,false))),
			processData: false,
			dataType: "json",
			success:instance.submitCallback
		});
	}
	instance.replyPreview = window.replyPreview = function (button) {
		$.ajax({
			type: "POST",
			url: window.responderURL,
			data: 'method1=' + encodeURIComponent(JSON.stringify(instance.getReplyMethod(button,true))),
			processData: false,
			dataType: "json",
			success:function(e){
				/* keep the reference to the orginal button so we can traverse back to the form */
				instance.previewCallback(e,button);
			}
		});
	}
	instance.submitCallback = function(e){
		e = e.method1;
		if(e.error!=undefined){
			alert(e.desc);
			return;/* error accessing method */
		}
		e = e.addReply;
		if(e.error!=0){
			alert(e.desc);
			return;/* method returns an error */
		}
		instance.replyId = e.replyId;
		instance.close();
		/* now refresh the current replies block */
		document.getElementById("blogReplies").innerHTML = '<img src="/img/a_g_loading.gif"> Loading ...';
		$.ajax({
			type: "POST",
			url: "reply.aspx",
			data: 'refreshReplies=true&entryId='+args.parentId,
			processData: false,
			dataType: "html",
			success:instance.loadRepliesBlock
		});
		
	}
	instance.loadRepliesBlock = function (e) {
		/* e contains the replies */
		document.getElementById("blogReplies").innerHTML = e;
		window.location = '#'+instance.replyId;
	}
	instance.previewCallback = function (e,button) {
		/* keep the reference to the orginal button so we can traverse back to the form */
		e = e.method1;
		if(e.error!=undefined){
			alert(e.desc);
			return;/* error accessing method */
		}
		e = e.addReply;
		if(e.error!=0){
			alert(e.desc);
			return;/* method returns an error */
		}
		/* no errors */
		instance.preview.style.width = 10 + 'px';
		instance.preview.style.height = 10 + 'px';
		document.body.appendChild(instance.preview);
		$(instance.preview).animate({ width: instance.previewRect.width, left: instance.finalPreviewLeft }, instance.animationTimer, instance.animationEasing, function () {
			$(instance.preview).animate({ height: instance.previewRect.height  }, instance.animationTimer, instance.animationEasing);
		});
		instance.preview.innerHTML = '<h3 style="text-align:left;">Subject: '+e.subject+'</h3>' + '<p>'+e.message+'</p>';
		instance.previewSubmit = document.createElement('button');
		instance.previewCancel = document.createElement('button');
		instance.previewSubmit.onclick = function(e){
			/* keep the reference to the orginal button so we can traverse back to the form */
			window.replySubmit(button);
		}
		instance.previewCancel.onclick = function(e){
			instance.preview.innerHTML = '';
			document.body.removeChild(instance.preview);
		}
		instance.preview.appendChild(instance.previewSubmit);
		instance.preview.appendChild(instance.previewCancel);
		instance.previewSubmit.innerHTML = 'Post';
		instance.previewCancel.innerHTML = 'Cancel';
	}
	instance.dispose = function(){
		document.body.removeChild(instance.modalBackground);
		document.body.removeChild(instance.reply);
		if(instance.preview){
			if(instance.preview.parentNode){
				instance.preview.parentNode.removeChild(instance.preview);
			}
		}
		window.replyPreview = undefined;
		window.replyCancel = undefined;
	}

	return instance.init();
}
/* approve of a blog reply.  Replaced numberNode argument with new number of approves
	numberNode: the DHTML Element that contains the number of approves
	replyId: the Id of the reply
*/
function approve(numberNode,replyId){
	var request = [
		'setReplyState',
		[
			{
				replyId:replyId,
				approve:true,
				disapprove:false,
				inappropriate:false
			}
		]
	]
	$.ajax({
		type: "POST",
		url: window.responderURL,
		data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
		processData: false,
		dataType: "json",
		success: function(e){
			numberNode.innerHTML= e.method1.setReplyState.approves;
		}
	});
}
/* disapprove of a blog reply.  Replaced numberNode argument with new number of disapproves
	numberNode: the DHTML Element that contains the number of disapproves
	replyId: the Id of the reply
*/
function disapprove(numberNode,replyId){
	var request = [
		'setReplyState',
		[
			{
				replyId:replyId,
				approve:false,
				disapprove:true,
				inappropriate:false
			}
		]
	]
	$.ajax({
		type: "POST",
		url: window.responderURL,
		data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
		processData: false,
		dataType: "json",
		success: function(e){
			numberNode.innerHTML = e.method1.setReplyState.disapproves;
		}
	});
}
/*	flag a reply inappropriate and return an alert that says as much to the user.
	replyId: the Id of the reply
*/
function inappropriate(replyId){
	var request = [
		'setReplyState',
		[
			{
				replyId:replyId,
				approve:false,
				disapprove:false,
				inappropriate:true
			}
		]
	]
	$.ajax({
		type: "POST",
		url: window.responderURL,
		data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
		processData: false,
		dataType: "json",
		success: function(){
			alert('Message reported to site administrator.');
		}
	});
}
/* update every item in the cart at once
on callback the function will <strike>attempt</strike> to set the form and qtys to the value in the ajax callback
accepts one argument dictionary {
	button:<DHTML button element that will contain the 'updating' message (usualy the one pressed>
	updateMessage:<the message to display in the button on click default:'Updating Cart...'>
	form<the DHTML element that contains the inputs that make up the cart (forms and QTYS)>
	cartTableId:< the Id of the cart table default:'cart'>
}
*/
function updateCart(args){
	var instance = {};
	if(!(args.form==undefined||args.form==null)){
		var formArguments = getInputs(args.form);
	}else{
		var formArguments = {};
	}
	args.form = undefined;
	if(args.button){
		instance.originalButtonHTML = args.button.innerHTML;
		args.button.innerHTML = args.updateMessage||'Updating Cart...';
	}
	args.showCartDetails = true;
	$.extend(true, formArguments, args);
	instance.updateCartCallback = function(e){
		var e = e.method1.updateCart;
		var cb = {};
		var g = function(i){return document.getElementById(i);};
		var table = document.getElementById(args.cartTableId||'cart');
		var h = table.rows.length;
		var j = e.items.length;
		if(j==0){window.location="/"};
		cb.chk = function(){
			for(var x=1;(h-1)>x;x++){/* don't check the first or last row */
				var inCart = false;
				for(var y=0;j>y;y++){
					if((table.rows[x].id=='row'+encodeXMLId(e.items[y].cartId))){
						inCart = true;
					}
				}
				if(!inCart){
					/* if one was missing, remove it and start over */
					table.removeChild(table.rows[x]);
					cb.chk.call();
					break;
				}
			}
		}
		cb.chk();/* check every row and see if the item is still in the cart */
		for(var x=0;j>x;x++){
			var i = e.items[x];
			var eId = encodeXMLId(i.cartId);
			if(i.qty==0){
				var row = g('row'+eId);
				var table = row.parentNode;
				table.removeChild(row);
			}else{
				g('p'+eId).innerHTML = '$' + parseFloat(i.price).toFixed(2);
				g('l'+eId).innerHTML = '$' + parseFloat(parseFloat(i.price)*parseFloat(i.qty)).toFixed(2);
				g(eId).value = i.qty;
				var k = i.inputs.length;
				for(var y=0;k>y;y++){
					var n = g(i.inputs[y].id);
					if(n){
						if(n.type.toLowerCase()=='checkbox'){
							n.checked = Boolean(i.inputs[y].value);
						}else{
							n.value = i.inputs[y].value
						}
					}
				}
			}
		}
		g('subTotal').innerHTML = '$' + parseFloat(e.subTotal).toFixed(2);
		g('estShipTotal').innerHTML = '$' + parseFloat(e.estShipTotal).toFixed(2);
		g('grandTotal').innerHTML = '$' + parseFloat(e.grandTotal).toFixed(2);
		g('discountTotal').innerHTML = '$' + parseFloat(e.discountTotal).toFixed(2);
		g('taxTotal').innerHTML = '$' + parseFloat(e.taxTotal).toFixed(2);
		if(args.button){
			args.button.innerHTML = instance.originalButtonHTML;
			args.button.disabled = false;
		}
	}
	instance.init = function(){
		var request = [
			'updateCart',
			[formArguments]
		]
		$.ajax({
			type: "POST",
			url: window.responderURL,
			data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
			processData: false,
			dataType: "json",
			success: instance.updateCartCallback
		});
	}
	instance.init();
}
/* update a single item in the cart
on callback the function will <strike>attempt</strike> to set the form and qtys to the value in the ajax callback
accepts one argument dictionary {
	button:<DHTML button element that will contain the 'updating' message (usualy the one pressed>
	updateMessage:<the message to display in the button on click default:'Updating Cart...'>
	form<the DHTML element that contains the inputs that make up the cart (forms and QTYS)>
}
*/
function updateCartItem(args){
	if(!(args.form==undefined||args.form==null)){
		var formArguments = getInputs(args.form);
	}else{
		var formArguments = {};
	}
	args.form = undefined;
	args.showCartDetails = true;
	var instance = {};
	$.extend(true, formArguments, args);
	instance.updateCartItemCallback = function(e){
		var e = e.method1.updateCartItem;
		var g = function(i){return document.getElementById(i);};
		var eId = encodeXMLId(args.cartId);
		if(args.qty==0){
			var row = g('row'+eId);
			var table = row.parentNode;
			table.removeChild(row);
			if(table.rows.length==2){window.location='/'};
		}else{
			g('p'+eId).innerHTML = '$' + parseFloat(e.price).toFixed(2);
			g('l'+eId).innerHTML = '$' + parseFloat(parseFloat(e.price)*parseFloat(e.qty)).toFixed(2);
		}
		g('subTotal').innerHTML = '$' + parseFloat(e.subTotal).toFixed(2);
		g('estShipTotal').innerHTML = '$' + parseFloat(e.estShipTotal).toFixed(2);
		g('grandTotal').innerHTML = '$' + parseFloat(e.grandTotal).toFixed(2);
		g('discountTotal').innerHTML = '$' + parseFloat(e.discountTotal).toFixed(2);
		g('taxTotal').innerHTML = '$' + parseFloat(e.taxTotal).toFixed(2);
	}
	var request = [
		'updateCartItem',
		[formArguments]
	]
	$.ajax({
		type: "POST",
		url: window.responderURL,
		data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
		processData: false,
		dataType: "json",
		success: instance.updateCartItemCallback
	});
}
/* adds an item 
on callback the function will <strike>attempt</strike> to set the form and qtys to the value in the ajax callback
accepts Form<DHTML Element contaning form inputs and qty>, dictionary <additional inputs to add to the form (qty and itemNumber for example)>,
callbackProcedure<the procedure to run if the item is successfully added to the cart>)
*/
function addToCart(form,args,callbackProcedure){
	var instance = {};
	if(args==undefined){
		args = {};
	}
	instance.init = function(){
		var formArguments = getInputs(form);
		$.extend(true, args, formArguments);/* combine form args with function args */
		var request = [
			'addToCart',
			[args]
		]
		$.ajax({
			type: "POST",
			url: window.responderURL,
			data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
			processData: false,
			dataType: "json",
			success: instance.addToCartCallback
		});
	}
	instance.addToCartCallback = function(e){
		e = e.method1;
		if(e.error!=undefined){
			alert(e.desc);
			return;/* error accessing method */
		}
		e = e.addToCart;
		if(e.error!=0){
			alert(e.desc);
			return;/* method returns an error */
		}
		if(callbackProcedure!=undefined){
			callbackProcedure.apply(this,[e]);
		}
	}
	validateForm(form,instance.init);
}
/* empties the cart of the current session and blankifies the cart element 'lines' by removing all the children */
function emptyCart(callbackProcedure){
	var request = [
		'emptyCart',
		['']
	]
	$.ajax({
		type: "POST",
		url: window.responderURL,
		data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
		processData: false,
		dataType: "json",
		success: function(e){
			if(callbackProcedure){
				callbackProcedure.apply(this,[e,this]);
			}else{
				history.go(-1);
			}
		}
	});
}
/* places an order using the current sesisons cart 
accepts one dictionary object {
	form:<the DHTML element containing all the inputs for placing an order>
	button:<the button to attach progress messages to and disable when pushed (usualy the place order button)>
	successCallbackProcedure:<the procedure to run when the order has been placed successfully signature:(orderCallbackInformationDictionary) (usually window.location=blah)>
}
*/
function placeOrder(args) {
	var instance = {};
	if(args.button==undefined){return;};
    validateForm(args.form, function () {
		var formArguments = getInputs(args.form);
		args.userId = "";
		args.soldBy = "";
		args.requisitionedBy = "";
		args.parentOrderId = "";
		args.deliverBy = "";
		args.purchaseOrder = "";
		args.manifestNumber = "";
		args.vendorAccountNumber = "";
		args.FOB = "";
		args.scannedImage = "";
		args.comments = "";
		args.termId = "";
		args.approvedBy = "";
		args.scannedImage = "";
		args.orderDate = "";
		args.cardType = "";
		args.billToEmail = "";
		args.billToComments = "";
		args.billToEmailAds = false;
		args.billToCompany = "";
		args.shipToEmail = "";
		args.shipToComments = "";
		args.shipToEmailAds = false;
		args.shipToCompany = "";
		args.billToSendShipmentUpdates = false;
		args.billToSpecialInstructions = "";
		args.billToRateId = -1;
		args.sendOrderConfirmEmail = true;
		$.extend(true, args, formArguments);/* combine form args with function args */
		/* remove HTML objects or safari JSON.stringify will fail */
		instance.button = args.button;
		instance.form = args.button;
		instance.successCallbackProcedure = args.successCallbackProcedure;
		args.button = undefined;
		args.form = undefined;
		args.successCallbackProcedure = undefined;
		var request = [
			'placeOrder',
			[args]
		]
        $.ajax({
            type: "POST",
            url: window.responderURL,
            data: 'method1=' + encodeURIComponent(JSON.stringify(request)),
            processData: false,
            dataType: "json",
            success: function(e){
				if(e.method1.error!=undefined){
					alert(e.method1.desc);
					return;
				}
				if(e.method1.placeOrder.error!=0){
					instance.button.disabled = false;
					new pointOutAProblem({
						obj: instance.button,
						message: e.method1.placeOrder.desc,
						fixMessage: "Ok",
						onFixProbelm: function (e) {
							return false;
						}
					});
					return;
				}
				if(instance.successCallbackProcedure){
					instance.successCallbackProcedure.apply(this,[e.method1.placeOrder]);
				}
			}
        });
        return null;
    });
}
/* adds a review to an item, requires the user to logon using the logon procedure 
accepts one argument dictionary {
	marginTop:<the margin above the absolutly positioned DIV default: 50>
	width:<the width of the dialog (DIV) defaut:600>
	height:<the heigh of the dialog (DIV) default:435
	animationTimer:<time for the animation to complete default: 'fast' (JQuery, 'fast','slow',100 etc)
	animationEasing:<easing method of the animation default: 'linear' (JQuery easing methods)
	updateTargetId:<the Id of the target the callback will replace with the full list of reviews>
	itemNumber:<the itemNumber being reviewed>
}
*/
function addReview(args) {
	if(window.user.userId==-1||window.user==undefined){
		logon({
			callbackProcedure:function(){
				addReview(args);
			}
		});
		return;
	}
	var instance = {};
	if(args==undefined){
		args = {};
	}
	instance.margin = {
		top:args.marginTop||50
	}
	instance.rect = {
		width:args.width||600,
		height:args.height||435
	}
	instance.animationTimer = args.animationTimer||'fast';
	instance.animationEasing = args.animationEasing||'linear';
	instance.resize = function () {
		var p = {
			t:document.documentElement.scrollTop,
			l:document.documentElement.scrollLeft,
			h:document.documentElement.clientHeight,
			w:document.documentElement.clientWidth
		}
		instance.modalBackground.style.height = p.h + 'px';
		instance.modalBackground.style.width = p.w + 'px';
		instance.modalBackground.style.top = p.t + 'px';
		instance.modalBackground.style.left = p.l + 'px';
		instance.review.style.top = instance.finalTop() + 'px';
		instance.review.style.left = (document.documentElement.clientWidth / 2 - (instance.rect.width / 2)) + 'px';
	}
	instance.init = function () {
		instance.review = document.createElement('div');
		instance.modalBackground = document.createElement('div');
		
		instance.finalLeft = (document.documentElement.clientWidth / 2) - (instance.rect.width / 2);
		instance.finalTop = function(){return document.documentElement.scrollTop + instance.margin.top};
		instance.review.style.top = instance.finalTop();
		instance.review.style.left = (document.documentElement.clientWidth / 2 - (instance.rect.width / 2)) + 'px';
		instance.modalBackground.style.background = 'url(/img/25PctAlphaBlackDot.png)';
		instance.modalBackground.style.position = 'absolute';
		instance.modalBackground.style.zIndex = '9996';
		instance.review.className = 'replyWindow';
		instance.review.style.zIndex = '9997';
		instance.review.style.position = 'absolute';
		appendEvent('resize', window.document, instance.resize, false);
		appendEvent('scroll', window.document, instance.resize , false);
		instance.review.style.width = 10 + 'px';
		instance.review.style.height = 10 + 'px';
		instance.resize();
		

		instance.formTable = document.createElement('table');
		instance.formTable.className = 'blogReply';
		instance.formTable.style.width = '100%';
		instance.formTable.style.marginTop = '10px';


		instance.message = document.createElement('textarea');
		instance.cancelButton = document.createElement('button');
		instance.postButton = document.createElement('button');

		instance.cancelButton.onclick = instance.close;
		instance.postButton.onclick = instance.submit;

		instance.cancelButton.style.margin = '0 4px 4px 4px';
		instance.postButton.style.margin = '0 4px 4px 4px';

		instance.cancelButton.innerHTML = 'Cancel';
		instance.postButton.innerHTML = 'Post';

		var stars = [
			document.createElement('button'),
			document.createElement('button'),
			document.createElement('button'),
			document.createElement('button'),
			document.createElement('button')
		];
		var x;
		var ratingHolder = document.createElement('div');
		instance.rating = document.createElement('input');
		var ratingSpan = document.createElement('span');
		ratingHolder.style.height = '25px';
		ratingHolder.style.width = '190px';
		ratingSpan.style.display = 'block';
		ratingSpan.style.cssFloat = 'right';
		ratingSpan.style.marginTop = '6px';
		instance.rating.value = 0;
		for(var x=0;5>x;x++){
			stars[x].setAttribute('index',x);
			stars[x].onmouseover = function(e) {
				$(this).addClass('ui-state-hover', 0); 
			};
			
			stars[x].onmouseout = function(e,x){
				$(this).removeClass('ui-state-hover', 0);
			};
			stars[x].onclick = function(e) {
				var y;
				var z = this.getAttribute('index');
				instance.rating.value = z;
				var u = false;
				for (var y = 0; 5 > y; y++) {
					if (u) {
						stars[y].innerHTML = '<img src="/img/star_gray.png" alt="">';
					} else {
						stars[y].innerHTML = '<img src="/img/star.png" alt="">';
					}
					if (z == stars[y].getAttribute('index')) {
						u = true;
					};
				}
				ratingSpan.innerHTML = (parseInt(z)+1)+' of 5';
			};
			stars[x].style.paddingBottom = '2px';
			stars[x].className = 'starButton';
			stars[x].innerHTML = '<img src="/img/star_gray.png" alt="">';
			ratingHolder.appendChild(stars[x]);
		}
		ratingHolder.appendChild(ratingSpan);
		stars[4].onclick();

		var t = instance.formTable;
		var r3 = t.insertRow(0);
		var r2 = t.insertRow(0);
		var r1 = t.insertRow(0);
		var r3c1 = r3.insertCell(0);
		r3c1.setAttribute('colspan','2');
		var r2c1 = r2.insertCell(0);
		r2c1.setAttribute('colspan','2');
		var r1c2 = r1.insertCell(0);
		var r1c1 = r1.insertCell(0);

		r1c1.style.textAlign = 'right';
		r1c2.style.fontWeight = 'bold';
		r2c1.style.textAlign = 'center';
		r1c1.appendChild(document.createTextNode('Rate this item'));
		r1c2.appendChild(ratingHolder);
		r2c1.appendChild(instance.message);
		r3c1.style.padding = '4px';
		r3c1.style.textAlign = 'right';
		instance.message.style.width = '545px';
		instance.message.style.height = '350px';
		
		r3c1.appendChild(instance.cancelButton);
		r3c1.appendChild(instance.postButton);
		document.body.appendChild(instance.modalBackground);
		document.body.appendChild(instance.review);
		instance.review.appendChild(instance.formTable);

		$(instance.review).animate({ width: instance.rect.width, left: instance.finalLeft }, instance.animationTimer, instance.animationEasing, function () {
			$(instance.review).animate({ height: instance.rect.height  }, instance.animationTimer, instance.animationEasing, function(){
				instance.message.focus();
				instance.message.select();
			});
		});

		return instance;
	}
	instance.submit = function(){
		if(instance.message.value.length==0){
			alert('You must eneter a message along with your review.');
			return;
		}
		$.ajax({
			type: "POST",
			processData:false,
			url: window.responderURL,
			data: 'method1=["addReview",[' + JSON.stringify({
				rating:instance.rating.value,
				message:instance.message.value,
				objId:args.itemNumber,
				objType:'itemNumber'
			}) + ']]',
			dataType: "json",
			success: function(e) {
				var rev = document.getElementById(args.updateTargetId);
				if (rev) {
					$(rev).load('/detail.aspx?reviews=1&item='+args.itemNumber,function(){
						window.location = '#'+e.method1.addReview.reviewId;
					});
				}
				instance.close();
			}
		});
	}
	instance.dispose = function(){
		document.body.removeChild(instance.modalBackground);
		document.body.removeChild(instance.review);
	}
	instance.close = function (e) {
		instance.dispose();
	}
	instance.init();
}
/* 
	JS based form validation
	uses pointOutAProblem to display invalid form entries
	upon valid form applies callbackProcedure
*/
function validateForm(form, callbackProcedure) {
    var self = this;
    formElements = $(form).find(':input');
    var i = null;
	var h = formElements.length;
    for (var x = 0; h > x; x++) {
        i = formElements[x];
        if (i.tagName.toLowerCase() == "input" || i.tagName.toLowerCase() == "select" || i.tagName.toLowerCase() == "textarea") {
            if (i.type == "text" && i.name.match(window.askLeaveBlank)) {
                if (i.value.length == 0 && i.getAttribute("ignorevalidation") != "1") {
                    new pointOutAProblem({
                        obj: i,
                        message: "Are you sure you want to leave this field blank?",
                        ignoreMessage: "I want to leave it blank",
                        fixMessage: "I want to go back and fix it",
                        onFixProbelm: function (e) {
                            e.focus();
                            e.select();
                            return false;
                        },
                        onIgnoreProbelm: function (e) {
                            e.setAttribute("ignorevalidation", "1");
                            return validateForm(form, callbackProcedure);
                        }
                    });
                    return null;
                };
            } else if (
				i.name.match(window.cannotBeBlank)
				&&  (!i.name.match(window.cannotBeBlankExceptions))
				) {
                if (i.value.length == 0) {
                    new pointOutAProblem({
                        obj: i,
                        message: i.title + ' cannot be left blank',
                        fixMessage: "Close",
                        onFixProbelm: function (e) {
                            e.focus();
                            return false;
                        }
                    });
                    return null;
                };
            } else if (i.name.match(window.cannotBeDefault)) {
                if (window.defaultValues.indexOf(i.value)!=-1) {
                    new pointOutAProblem({
                        obj: i,
                        message: "Please select a value to continue.",
                        fixMessage: "Close",
                        onFixProbelm: function (e) {
                            e.focus();
                            return false;
                        }
                    });
                    return null;
                }
            };
        };
    };
    callbackProcedure.apply(self, [self]);
};
/* utility */
/* creates a menu (DIV) with an animation - works hierarchaly */
function openMenu(targetMenu, caller, params) {
	if (caller.getAttribute('menu') == '1' || targetMenu==undefined) { return null; };
	var self = this;
	params = params || {};
	self.caller = caller;
	self.caller.setAttribute('menu', '1');
	self.supressOnClick = params.supressOnClick || false;
	self.supressOnMouseout = params.supressOnMouseout || false;
	self.animate = params.animate || true;
	self.slide = params.slide || ["down"];
	self.easingRevealMenu = params.easingOut || window.easeOut;
	self.easingHideMenu = params.easingIn || window.easeIn;
	self.easingHideMenuTime = params.hideSpeed || 0;
	self.easingRevealMenuTime = params.revealSpeed || 0;
	self.offsetTop = params.offsetTop || 0;
	self.offsetLeft = params.offsetLeft || 0;
	self.delay = params.delay || 75;
	self.dispose = function () {
		removeEvent('mouseout', self.caller, self.close, true);
		if (self.timer) {
			removeEvent('click', self.caller, self.init, false);
			clearTimeout(self.timer);
		} else {
			if (self.menu) {
				removeEvent('click', self.menu, self.close, false);
				removeEvent('mouseout', self.menu, self.close, true);
				self.caller.removeChild(self.menu);
				self.menu = null;
			}
		};
		return null;
	};
	self.close = function (e) {
		var rel = e.relatedTarget || e.toElement;
		if (isChildOf(rel, self.caller) || isChildOf(rel, self.menu)) {
			return null
		};
		self.caller.setAttribute('menu', '0');
		if (self.timer) {
			return self.dispose();
		} else {
			if (self.animate) {
				$(self.menu).animate({ top: "+=" + self.pos.y, opacity: 0 }, self.easingHideMenuTime, self.easingHideMenu, function () {
					return self.dispose();
				});
				return null;
			} else {
				return self.dispose();
			}
		};
	};

	self.init = function () {
		removeEvent('click', self.caller, self.init, false);
		if (self.timer) {
			clearTimeout(self.timer);
			self.timer = null;
		};
		var org = targetMenu;
		if (org == undefined) { return null };
		self.pos = getPositionUntilAbsolute(self.caller);
		self.menu = targetMenu.cloneNode(true);
		self.menu.style.position = 'absolute';
		self.menu.style.display = 'block';
		self.menu.style.visibility = 'visible';
		self.menu.style.zIndex = '9999';
		/* append and animate */
		self.caller.appendChild(self.menu);
		/* get the size of the item we just cloned */
		var dim = { h: parseInt(self.menu.offsetHeight), w: parseInt(self.menu.offsetWidth) };
		for (var x = 0; self.slide.length > x; x++) {
			if (self.slide[x].toLowerCase() == "down") {
				if (self.animate) {
					self.menu.style.top = self.pos.y + 'px';
					self.menu.style.left = self.pos.x + 'px';
					self.pos.y += self.caller.offsetHeight;
				} else {
					self.pos.y += self.caller.offsetHeight;
					self.menu.style.top = (self.pos.y) + 'px';
					self.menu.style.left = self.pos.x + 'px';
				}
			} else if (self.slide[x].toLowerCase() == "right") {
				if (self.animate) {
					self.menu.style.top = (self.pos.y) + 'px';
					self.menu.style.left = (self.pos.x) + 'px';
					self.pos.x += self.caller.offsetWidth;
				} else {
					self.pos.x += self.caller.offsetWidth;
					self.menu.style.top = (self.pos.y) + 'px';
					self.menu.style.left = (self.pos.x) + 'px';
				}
			} else if (self.slide[x].toLowerCase() == "left") {
				if (self.animate) {
					self.menu.style.top = (self.pos.y) + 'px';
					self.menu.style.left = (self.pos.x) + 'px';
					self.pos.x -= (dim.w);
				} else {
					self.pos.x -= (dim.w);
					self.menu.style.top = (self.pos.y) + 'px';
					self.menu.style.left = (self.pos.x) + 'px';
				}
			}
		}
		self.pos.y -= self.offsetTop;
		self.pos.x -= self.offsetLeft;
		if (self.animate) {
			/* vanish */
			self.menu.style.opacity = '0';
			if (self.menu.addEventListener) {
				/* get small */
				self.menu.style.width = '0';
				self.menu.style.height = '0';
				var aniOptions = {
					top: self.pos.y + 'px',
					left: self.pos.x + 'px',
					opacity: 1,
					height: dim.h + 'px',
					width: dim.w + 'px'
				}
			} else {
				/* don't get small for IE */
				var aniOptions = {
					top: self.pos.y + 'px',
					left: self.pos.x + 'px',
					opacity: 1
				}
			}

			$(self.menu).animate(aniOptions, self.easingRevealMenuTime, self.easingRevealMenu);
		}
		if (!self.supressOnMouseout) {
			appendEvent('mouseout', self.menu, self.close, true);
		}
	};
	/* add close procedure */
	if (!self.supressOnMouseout) {
		appendEvent('mouseout', self.caller, self.close, true);
	}
	if (!self.supressOnClick) {
		appendEvent('click', self.caller, self.init, false);
	}
	/* start the timer */
	self.timer = setTimeout(self.init, self.delay);
}
/* checks to see if this object is a child of the current object */
function isChildOf(e, parentObj) {
	while (e) {
		if (e == parentObj) {
			return true;
		}
		e = e.parentNode;
	}
	return false;
}
/* gets the position of the element */
function getPosition(e) {
    var eleft = 0;
    var etop = 0;
    while (e.offsetParent) {
        eleft += e.offsetLeft;
        etop += e.offsetTop;
        eleft -= e.scrollLeft;
        etop -= e.scrollTop;
        e = e.offsetParent;
    }
    return { x: eleft, y: etop };
};
/* gets the position of the element until it finds an absolutly positioned element*/
function getPositionUntilAbsolute(e) {
	var eleft = 0;
	var etop = 0;
	while (e.offsetParent) {
		if (e.style.position == 'absolute') {
			break;
		}
		eleft += e.offsetLeft;
		etop += e.offsetTop;
		eleft -= e.scrollLeft;
		etop -= e.scrollTop;
		e = e.offsetParent;
	}
	return { x: eleft, y: etop };
}
/* cross browser addEventListener *//* gets the position of the element */
function appendEvent(type, listener, appendedFunction, capture) {
	if (listener) {
		if (listener.addEventListener) {
			listener.addEventListener(type, appendedFunction, capture);
		} else if (listener.attachEvent) {
			listener.attachEvent('on' + type, appendedFunction);
		} else {
			//alert('Can\'t attach event to listener!');
		}
	}
}
/* cross browser removeEventListener *//* gets the position of the element */
function removeEvent(type, listener, removedFunction, capture) {
	if (listener) {
		if (listener.removeEventListener) {
			listener.removeEventListener(type, removedFunction, capture);
		} else if (listener.detachEvent) {
			listener.detachEvent('on' + type, removedFunction);
		} else {
			//alert('Can\'t unattach event from listener!');
		}
	} else {
		//alert('No function to detach found for event on' + type);
	}
}
/* uses JQuery selector to find all inputs in a DHTML object and turns them into an structure/object/dictionary/whatever */
function getInputs(form) {
    if (form) {
		var t = {};
        inputs = $(form).find(':input');
        for (var i = inputs.length - 1; i >= 0; --i) {
            if (inputs[i].type == 'checkbox') {
                if (inputs[i].name.length == 0) { continue; };
                if (inputs[i].checked) {
                    t[inputs[i].name] = true;
                } else {
                    t[inputs[i].name] = false;
                }
            } else if (inputs[i].type == 'radio') {
                if (inputs[i].name.length == 0) { continue; };
                if (inputs[i].checked) {
					t[inputs[i].name] = inputs[i].checked;
                }
            } else {
                if (inputs[i].name.length == 0) { continue; };
                t[inputs[i].name] = inputs[i].value;
            }
        }
        return t;
    } else {
        return {};
    }
}
/* creates a UUID (hence the name createUUID) */
function createUUID() {
    /*http://www.rfc-archive.org/getrfc.php?rfc=4122 4.4.  Algorithms for Creating a UUID from Truly Random or Pseudo-Random Numbers */
    var s = [];
    var hexDigits = '0123456789ABCDEF';
    for (var i = 0; i < 32; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    /*bits 12-15 of the time_hi_and_version field to 0010*/
    s[12] = '4';
    /*bits 6-7 of the clock_seq_hi_and_reserved to 01*/
    s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1);
    var uuid = s.join('');
    return uuid.substring(0, 8) + '-' + uuid.substring(8, 12) + '-' + uuid.substring(12, 16) + '-' + uuid.substring(16, 20) + '-' + uuid.substring(20, 32);
}
/* encodes strings for safe transport in JSON */
function jsonEncode(str) {
    return str.replace(/"/g, '\"').replace(/\\/g, '\\\\');
}
/* turns GUIDs into JS/DHTML safe Ids */
encodeXMLId = function(e){
	return 'd'+e.replace(/}/g,'').replace(/{/g,'').replace(/-/g,'_');
}
/* used by validate to point out problems with forms */
function pointOutAProblem(params) {
    if (params.obj.pointOutAProblem) { return null };
    var self = this;
    params.obj.pointOutAProblem = self;
    var pos = getPosition(params.obj);
    self.dialog = document.createElement("div");
    self.uiDialog = $(".ui-dialog-content")[0];
    if (self.uiDialog == undefined) {
        self.uiDialog = { scrollTop: 0 };
    }
    self.dialog.className = 'pointOutAProblem';
	self.dialog.style.position = 'absolute';
    self.dialog.style.top = (pos.y + 10 - self.uiDialog.scrollTop) + "px";
    self.dialog.style.left = (pos.x + params.obj.offsetWidth + 40) + "px";
    self.dialog.innerHTML = '\
	<div class="pointOutAProblemArrowLeft" style="float:left;height:15px;width:15px;margin:-15px 0 0 -25px;text-shadow:#000 1px 1px 1px;">&#8656;</div>\
    <div class="ui-corner-all ui-state-hover" style="padding:4px;">\
    ' + params.message + '</div>';
    self.fixProbelm = document.createElement("button");
    self.fixProbelm.className = "ui-corner-all ui-state-default";
    self.fixProbelm.style.margin = '4px';
    self.fixProbelm.innerHTML = params.fixMessage;
    if (params.ignoreMessage) {
        self.ignoreProbelm = document.createElement("button");
        self.ignoreProbelm.className = "ui-corner-all ui-state-default";
        self.ignoreProbelm.style.margin = '4px';
        self.ignoreProbelm.innerHTML = params.ignoreMessage;
        self.ignoreProbelm.onclick = function () {
            self.close();
            params.onIgnoreProbelm.apply(self, [params.obj, self]);
            params.obj.pointOutAProblem = null;
            return null;
        };
        self.dialog.appendChild(self.ignoreProbelm);
    }
    self.close = function () {
		removeEvent("keypress", params.obj, self.close, false);
        self.dialog.innerHTML = '';
        document.body.removeChild(self.dialog);
        removeEvent("change", params.obj, self.close, false);
        removeEvent('scroll', window, self.redraw, false);
        removeEvent('scroll', $(".ui-dialog-content")[0], self.redraw, false);
        params.obj.style.backgroundColor = 'white';
        self = null;
		
    };
    self.fixProbelm.onclick = function () {
        self.close();
        params.onFixProbelm.apply(self, [params.obj, self]);
        params.obj.pointOutAProblem = null;
        return null;
    };
    appendEvent('scroll', window, self.redraw = function () {
        var pos = getPosition(params.obj);
        self.dialog.style.top = (pos.y + 10 - self.uiDialog.scrollTop) + "px";
        self.dialog.style.left = (pos.x + params.obj.offsetWidth + 4) + "px";
        return null;
    }, false);
    appendEvent('scroll', $(".ui-dialog-content")[0], self.redraw, false);
    appendEvent("keypress", params.obj, self.close, false);
	
    self.dialog.appendChild(self.fixProbelm);
    document.body.appendChild(self.dialog);
    self.flash = function () {
        $(params.obj).animate({ backgroundColor: window.pulseColor1 }, 500, 'linear', function () {
            $(params.obj).animate({ backgroundColor: window.pulseColor2 }, 500, 'linear', function () {
                if (self) {
                    self.flash();
                };
            });
        });
    }
    $(self.dialog).animate({ left: (pos.x + params.obj.offsetWidth + 4) }, 700, 'easeOutBounce');
    self.flash();
};
