/**
 * base JavaScript for Kotex.com
 * requires: jquery.js
 */
 
// global page init functions

// enable styles for js-enabled browsers
if(document.getElementById && document.createTextNode) {
	document.getElementsByTagName('html')[0].className = document.getElementsByTagName('html')[0].className + ' js';
};
 
// prevent background image flicker in IE
try {
	document.execCommand("BackgroundImageCache", false, true);
} catch(err) {};

$(document).ready(function () {
	var log = KC.Util.log,
		cookie = KC.Util.cookie;
		
	// IE png fix
	$.ifixpng(baseUrl + 'images/blank.gif');
	$('img, div, span, a').ifixpng();
		
	// hide specific elements until fully loaded
	$(".home-image img").css({opacity: 0});
	$(".home-image div").hide();
	
	// fade in specific elements onload
	$(window).load(function () {
		KC.fadeInStory($(".home-image img"));
		
		//$("#product-detail #nav-category").find("ul").css("visibility", "visible"); DISABLED PER E.T.
	});
		
	// highlight current product in category nav on product detail
	$("#product-detail #nav-category a").each(function () {
		if (location.href.toLowerCase() === this.href.toLowerCase()) {
			var $this = $(this);
			$this.replaceWith("<strong>" + $this.html() + "</strong>");
		}
	});
	
	// insert "home" link?
	if (location.pathname !== "/" && location.pathname.toLowerCase() !== "/default.aspx") {
		$("#nav ul:first").prepend('<li><a href="/" title="Kotex.com home">Home</a></li>');
	}
	
	// form hints
	$("input.hint").hint();
	
	// persist search value
	if (KC.Util.query.search) {
		$("#search").val(KC.Util.query.search);
	}
	
	// class form fields
	$("input[type=text]").addClass("text");
	$("input[type=password]").addClass("password");
	
	// activate sliders
	$(".slider .closed").each(function () {
		var s = new KC.Slider(this);
	});
	
	// activate popup menus
	$("#nav-products > ul > li").each(function () {
		var m = new KC.PopupMenu(this);
	});
	
	// all products page nav
	$("#all-products ul ul a").bind("mouseover", function () {
		var $this = $(this),
			$a = $this.parents("ul:first").prev("a");
			
		function restore ($that, newcategory) {
			var $a = $that.parents("ul:first").prev("a");
			if (newcategory) {
				// restore initial image and href
				$a.find("img").removeClass("on").fadeOut(10);
				$a.attr("href", $a.data("initialhref"));
			}
			// restore initial label
			$that.html($that.data("initiallabel")).removeClass("hover");
		};
		
		// cache initial href for category
		if(!$a.data("initialhref")) {
			$a.data("initialhref", $a.attr("href"));
		}
		
		// handle the hover, unless this element is already "hovered"
		if (!$this.hasClass("hover")) {
			// restore previously hovered link
			if ($(window).data("selectedproduct")) {
				// restore old category image if entering a new category
				restore($(window).data("selectedproduct"), ($this.parents("ul:first")[0] !== $(window).data("selectedproduct").parents("ul:first")[0]));
			}
			// keep reference to this element so we can restore it later
			$(window).data("selectedproduct", $this);
			// show selected image
			$this.data("image").fadeIn(500, function () {
				// hide other images
				$a.find("img.on").removeClass("on").fadeOut(500);
				// update image link
				$a.attr("href", $this.attr("href"));
				$(this).addClass("on");
			});
			// show full label
			$this.html($this.data("hoverlabel")).addClass("hover");
		}
	}).each(function () {
		// load product images and cache initial/hover labels
		var $this = $(this),
			i = $("<img />")
				.appendTo($this.parents("ul:first").prev("a"))
				.css({position: "absolute", left: 0, top: 0})
				.attr("src", "images/" + $(this).attr("class"))
				.hide();
		$this.data("image", i);
		$this.data("hoverlabel", $this.attr("title"));
		$this.data("initiallabel", $this.html().replace(/<[^>]+>/g, ""));
	});
	
	// hide select elements in IE < 7 when the drop downs are visible
	if ($.browser.msie && parseInt($.browser.version, 10) < 7) {
		$(document).bind("show.KCmenu", function () {
			$("select").css("visibility", "hidden");
		});
		
		$(document).bind("hide.KCmenu", function () {
			$("select").css("visibility", "visible");
		});
	}
	
	// remove title attribute text to prevent tooltips from obscuring page text
	$("#content a, #sidebar a").one("mouseover", function () {
		$(this).attr("title", "");
	});
});
 
// namespace
var KC = {
	debug: false,
	isIE: $.browser.msie,
	isIE6: ($.browser.msie && $.browser.version < 7),
	launchTellAFriend: function (url) {
	    window.open(url, 'TellAFriend', 'width=460,height=540,scrollbars=1,resizable=1').focus();
	}
};

// homepage bumper message
KC.Overlay = {
	show: function () {
		// hide the page content
		$("#wrapper-outer").hide();
		
		// show the overlay as soon as the DOM is ready
		$(function () {
			$(KC.Overlay.content).insertAfter("#wrapper-outer").click(KC.Overlay.hide);
			$(window).load(function () {
				KC.Overlay.timer = window.setTimeout(KC.Overlay.hide, 5000);
			});
		});
		
		// set the cookie
		KC.Util.cookie("overlay", "true", {expires: 365});
	},
	
	hide: function () {
		window.clearTimeout(KC.Overlay.timer);
		
		if (!KC.isIE6) {
			$("#overlay").fadeOut();
			$("#wrapper-outer").fadeIn();
		} else {
			$("#overlay").hide();
			$("#wrapper-outer").show();
		}
	}
};

// animation classes

KC.animationManager = {
	
	animations: [],
	
	register: function (object, type) {
		this.animations.push({"object": object, "type": type});
		// KC.Util.log(object, type);
	},
	
	notify: function (notifier, type, event) {
		var s = type + event;
		$.each(this.animations, function (i, animation) {
			switch(s) {
				case "slidershow":
					if (animation.type === "slider" || animation.type === "popupmenu") {
						// hide other sliders and menus
						animation.object.hide();
					} else if (animation.type === "carousel") {
						// pause carousel
						animation.object.pause();
					}
					break;
				case "sliderhide":
					if (animation.type === "carousel") {
						// resume carousel
						animation.object.play();
					}
					break;
				case "popupmenushow":
					if (animation.type === "slider") {
						// hide sliders
						animation.object.hide();
					} else if (animation.type === "carousel") {
						// pause carousel
						animation.object.pause();
					} else if (animation.type === "popupmenu") {
						// keep other menus disabled
						window.clearTimeout(animation.object.enabletimer);
						// enable/disable
						if (notifier === animation.object) {
							animation.object.enable();
							$(document).trigger("show.KCmenu");
						} else {
							animation.object.disable();
						}
					}
					break;
				case "popupmenuhide":
					$(document).trigger("hide.KCmenu");
					if (animation.type === "carousel") {
						// resume carousel
						animation.object.play();
					} else if (animation.type === "popupmenu") {
						// enable all menus after short delay
						animation.object.enabletimer = window.setTimeout(function () {
							animation.object.enable();
						}, 400);
						if (notifier === animation.object) {
							$(document).trigger("hide.KCmenu");
						}
					}
					break;
				case "carouselplay":
					break;
				case "carouselpause":
					// hide all sliders
					if (animation.type === "slider") {
						animation.object.hide();
					}
					break;
			}
		});
		// KC.Util.log(notifier, type, event);
	}
};

KC.fadeInStory = function ($el) { // $el is the large image!
	window.setTimeout(function () {
		$el.css({visibility: "visible", opacity: 0, display: "block"}).animate({opacity: 1}, 1000, function () {
			if (KC.isIE) {
				this.style.removeAttribute('filter');
				$el.siblings("div").show();
			} else {
				$el.siblings("div").css({visibility: "visible", opacity: 0, display: "block"}).fadeTo(1000, 1);
			}
		});
	}, 500);
};

KC.fadeOutStory = function ($el) { // $el is the large image!
	$el.siblings("div").hide();
	$el.css({opacity: 0});
};

KC.ArticleNav = (function () {
	var sidebar = null, parent = null, t = null, sidebartop = null, articlemax = null,
		mintohide = 2; 	// we must have (articlemax + mintohide) articles in a category before we instantiate the "view more" function 
						// because it's silly to have "view more" reveal only 1 more article link
	
	function hidearticlelinks () {
		sidebar.find("ul ul.open").removeClass("open").find("li.hideable").hide().end().find(".view-more").show();
	}
	
	function showarticlelinks (ul) {
		ul.addClass("open").find(".view-more").hide().prevAll("li").fadeIn(600);
	}
	
	function scrollhandler () {
		var h = KC.Util.getViewportSize().y,
				scrolly = KC.Util.getScrollOffset().y,
				sidebarheight = sidebar[0].offsetHeight,
				parentheight = parent[0].offsetHeight,
				top;
		// height check to prevent "infinite scrollbars"
		//if (h > sidebarheight) { // DISABLED TO PREVENT SIDEBAR FROM GETTING STUCK AT BOTTOM
			// height check to prevent overlap of footer
			if (parentheight < sidebartop + sidebarheight + scrolly) {
				top =  sidebartop + scrolly + (parentheight - (sidebartop + sidebarheight + scrolly));
			} else {
				top = sidebartop + scrolly;
			}
			sidebar.stop();
			sidebar.animate({top: top + "px"}, 600, "easeOutExpo");
		//}
	}
				
	return {
		init: function ($el, max) {
			if ($el.size()) {
				sidebar = $el;
				parent = sidebar.parent();
				articlemax = max - 1;
				sidebartop = sidebar[0].offsetTop;
				
				// enable "view more" links
				sidebar.find("ul ul").each(function () {
					var $this = $(this);
					if ($this.children("li").size() > articlemax + mintohide) { // we must have (articlemax + mintohide) articles in a category before doing this
						$this.find("li:gt(" + articlemax + ")").addClass("hideable").hide();
						$('<li class="view-more">&gt; <a href="#">view more</a></li>').appendTo($this).find("a").bind("click", function (e) {
							hidearticlelinks();
							showarticlelinks($this);
							scrollhandler();
							e.preventDefault();
						});
						// expand this category if the current article belongs to it
						if ($this.find("li.on").size()) {
							showarticlelinks($this);
							//$this.removeClass("open"); // don't allow this category to close CAN'T DO THIS, 2 CATEGORIES OPEN AT SAME TIME IS PROBABLY TOO TALL
						}
					}
				});
				
				// scroll article sidebar
				$(window).bind("scroll", function () {
					if (t) {
						window.clearTimeout(t);
					}
					t = window.setTimeout(scrollhandler, 100);
				});
				
				// triggered by font resizing
				$(document).bind("ready fontresize", scrollhandler);
			}
		}
	}
}) (); // self-invoking!

KC.Carousel = (function () {
	var $c, $s, $n, $d, current = 0, last = 0, timer = null, stopped = false, that;
	return {
		init: function (c) {
			that = this;
			$c = $(c);
			if (!$c.length) {
				return false;
			}
			$s = $c.find(".slide").css({opacity: 0, zIndex: 1});
			$n = $c.find(".nav").fadeIn("slow");
			$d = $n.find(".direct");
			$c.hover(function () {
					KC.animationManager.notify(that, "carousel", "pause");
					that.pause();
				}, 
				function () {
					KC.animationManager.notify(that, "carousel", "play");
					that.play();
				}
			);
			$n.find(".next").click(function () {
				that.pause();
				stopped = true;
				that.next();
				this.blur();
				return false;
			});
			$n.find(".prev").click(function () {
				that.pause();
				stopped = true;
				that.previous();
				this.blur();
				return false;
			});
			$d.click(function () {
				that.pause();
				stopped = true;
				that.gotoframe($d.index(this));
				this.blur();
				return false;
			});
			last = $s.length - 1;
			KC.animationManager.register(this, "carousel");
			this.show();
			this.play();
		},
		
		show: function () {
			$s.eq(current).css({zIndex: 2}).fadeTo(1000, 1, function () {
				if (KC.isIE) {
					this.style.removeAttribute('filter');
				}
			});
			$n.find(".direct").removeClass("on").eq(current).addClass("on");	
		},
		
		hide: function () {
			$s.eq(current).fadeTo(500, 0).css({zIndex: 1});
		},
		
		pause: function () {
			window.clearInterval(timer);
		},
		
		play: function () {
			if (!stopped) {
				window.clearInterval(timer);
				timer = window.setInterval(that.next, 6000);
			}
		},
		
		gotoframe: function (i) {
			that.hide();
			current = i;
			that.show();
		},
		
		next: function () {
			that.hide();
			current = (current < last) ? current + 1 : 0;
			that.show();
		},
		
		previous: function () {
			that.hide();
			current = (current > 0) ? current - 1 : last;
			that.show();
		}
	};
}) (); // self-invoking!

KC.Slider = function (el) {
	var $a = $(el).parent("a"), that = this;
	this.closer = $a.next("span");
	this.panel = $a.find(".open");
	this.shift = (this.panel.attr("width") - 8);
	this.overlay = $a.nextAll(".overlay") || "none";
	this.open = false;
	this.disabled = false;
	this.timer = null;
		
	$a.hover(
		function () {
			if (!that.open && !that.disabled) {
				that.timer = window.setTimeout(function () {
					KC.animationManager.notify(that, "slider", "show");
					that.show();
				}, 400);
			}
		}, 
		function () {
			that.cleartimer();
			that.disabled = false;
		}
	);
	
	this.closer.click(
		function () {
			KC.animationManager.notify(that, "slider", "hide");
			that.hide();
			that.disabled = true; // temporarily disable slider until mouseout
		}
	);
	
	// closers only work in IE if we specify a background color?!?
	if (KC.isIE) {
		this.closer.css({background: "#fff", opacity: 0.05});
	}
	
	KC.animationManager.register(this, "slider");
	
	return this;
};

KC.Slider.speed = (KC.isIE) ? "" : "fast";

KC.Slider.prototype = {
	
	show: function () {
		var that = this;
		this.open = true;
		this.panel
			.animate({left: "-=" + this.shift + "px"}, 400, "easeOutExpo", function () {
				if (that.overlay !== "none") {
					that.overlay.show(KC.Slider.speed);
				}
			});
		this.closer
			.animate({left: "-=" + this.shift + "px"}, 400, "easeOutExpo")
			.css("zIndex", 3);
	},
	
	hide: function () {
		if (this.open) {
			if (this.overlay !== "none") {
				this.overlay.hide(KC.Slider.speed);
			}
			this.open = false;
			this.closer
				.animate({left: "+=" + this.shift + "px"}, 400)
				.css("zIndex", 1);
			this.panel
				.animate({left: "+=" + this.shift + "px"}, 400);
		}
	},
	
	cleartimer: function () {
		window.clearTimeout(this.timer);
	}
	
};

KC.PopupMenu = function (el) {
	var that = this;
	this.li = $(el);
	this.ul = this.li.find("ul");
	this.open = false;
	this.enabletimer = null;
	this.hovertimer = null;
	this.height = null;
	this.minheight = null;
	
	this.li.hover(
		function () {
			window.clearTimeout(that.hovertimer);
			if (that.ul.size() && !that.open) {
				that.hovertimer = window.setTimeout(function () {
					KC.animationManager.notify(that, "popupmenu", "show");
					that.show();
				}, 300);
			}
		}, 
		function () {
			if (that.ul.size()) {
				window.clearTimeout(that.hovertimer);
				if (that.open) {
					that.hovertimer = window.setTimeout(function () {
						KC.animationManager.notify(that, "popupmenu", "hide");
						that.hide();
					}, 300);
				}
			}
		}
	);
	
	KC.animationManager.register(this, "popupmenu");
	
	return this;
};

KC.PopupMenu.prototype = {
	
	show: function () {
		var that = this;
		this.open = true;
		// determine menu height for animation, and store min-height for later use
		this.ul.css({display: "block", opacity: 0});
		this.height = this.ul[0].offsetHeight;
		this.minheight = this.ul.css("minHeight");
		// animate the menu
		this.ul.css({minHeight: 0, height: 0})
			.animate({opacity: 1.0, height: this.height}, 400, function () {
				if (KC.isIE) {
					this.style.removeAttribute('filter');
				}
			});
	},
	
	hide: function () {
		// return;
		var that = this;
		if (this.open) {
			this.ul.animate({opacity: 0, height: 0}, 200, function () {
					var css = {display: "none", minHeight: that.minheight};
					if (KC.isIE6) {
						css.height = that.minheight;
					} else {
						css.height = "auto";
					}
					$(this).css(css);
					that.open = false;
				});
		}
	},
	
	disable: function () {
		this.li.addClass("off");
	},
	
	enable: function () {
		this.li.removeClass("off");
	}
};

KC.Util = {
	log: function () {
		if (KC.debug || location.hash.indexOf("debug") > -1) {
			try {
				console.log(arguments);
			} catch (err) {}
		}
	},
	
	query: (function () {
		var qString, queryStart, query, parts, bits, subbits, returnVals = {};
		qString = window.location.toString();
		queryStart = qString.indexOf('?');
		if (queryStart==-1) {
			return returnVals;
		}
		query = qString.substring(queryStart + 1, qString.length);
		parts = query.split("&");
		for (var i=0; i<parts.length; i++) {
			bits = parts[i].split("=");
			if (bits[1]) {
				subbits = bits[1].split("#");
				returnVals[bits[0].toLowerCase()] = subbits[0]; // query properties are lowercase!
			}
		}
		return returnVals;
	}) (), // self-invoking!
	
	cookie: function (name, value, options) { // adapted from http://www.stilbuero.de/2006/09/17/cookie-plugin-for-jquery/
	    if (typeof value != 'undefined') { // name and value given, set cookie
	        options = options || {};
	        if (value === null) {
	            value = '';
	            options.expires = -1;
	        }
	        var expires = '';
	        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
	            var date;
	            if (typeof options.expires == 'number') {
	                date = new Date();
	                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
	            } else {
	                date = options.expires;
	            }
	            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
	        }
	        var path = options.path ? '; path=' + options.path : '';
	        var domain = options.domain ? '; domain=' + options.domain : '';
	        var secure = options.secure ? '; secure' : '';
	        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
	    } else { // only name given, get cookie
	        var cookieValue = null;
	        if (document.cookie && document.cookie !== '') {
	            var cookies = document.cookie.split(';');
	            for (var i = 0, l = cookies.length; i < l; i++) {
	                var cookie = cookies[i].replace(/^\s+|\s+$/g, "");
	                // Does this cookie string begin with the name we want?
	                if (cookie.substring(0, name.length + 1) == (name + '=')) {
	                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
	                    break;
	                }
	            }
	        }
	        return cookieValue;
	    }
	},
	
	getPageSize: function () {
		var x = Math.max(document.documentElement.scrollWidth || document.body.scrollWidth, document.body.offsetWidth);
		var y = Math.max(document.documentElement.scrollHeight || document.body.scrollHeight, document.body.offsetHeight);
		return {"x": x, "y": y};
	},
	
	getViewportSize: function () {
		var x = self.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
		var y = self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
		return {"x": x, "y": y};
	},
	
	getScrollOffset: function () {
		var x = self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
		var y = self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
		return {"x": x, "y": y};
	},
	
	getElemPosition: function (el) {
		var x = 0, y = 0;
		if (el.offsetParent) {
			do {
				x += el.offsetLeft;
				y += el.offsetTop;
			} while (el = el.offsetParent);
		}
		return {"x": x, "y": y};
	}
};


// jQuery plugins

/*
 * jQuery ifixpng plugin
 * (previously known as pngfix)
 * Version 3.1.2  (2008/09/01)
 * @requires jQuery v1.2.6 or above, or a lower version with the dimensions plugin
 * 
 * Based on the plugin by Kush M., http://jquery.khurshid.com
 *
 * Background position Fixed
 * Also fixes non-visible images
 * (c) Copyright Yereth Jansen (yereth@yereth.nl)
 * personal website: http://www.yereth.nl
 * Company website: http://www.wharf.nl
 * 
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * For a demonstration of the background-position being fixed:
 * http://www.yereth.nl/bgpos.html
 *
 * Plugin page:
 * http://plugins.jquery.com/project/iFixPng2
 *
 */

/**
 *
 * @example
 *
 * optional if location of pixel.gif if different to default which is images/pixel.gif
 * $.ifixpng('media/pixel.gif');
 *
 * $('img[@src$=.png], #panel').ifixpng();
 *
 * @apply hack to all png images and #panel which icluded png img in its css
 *
 * @name ifixpng
 * @type jQuery
 * @cat Plugins/Image
 * @return jQuery
 * @author jQuery Community
 */
;(function($) {

	/**
	 * helper variables and function
	 */
	$.ifixpng = function(customPixel) {
		$.ifixpng.pixel = customPixel;
	};
	
	$.ifixpng.regexp = {
		bg: /^url\(["']?(.*\.png([?].*)?)["']?\)$/i,
		img: /.*\.png([?].*)?$/i
	},
	
	$.ifixpng.getPixel = function() {
		return $.ifixpng.pixel || 'images/pixel.gif';
	};
	
	var hack = {
		base	: $('base').attr('href'),
		ltie7	: $.browser.msie && $.browser.version < 7,
		filter	: function(src) {
			return "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true,sizingMethod=crop,src='"+src+"')";
		}
	};
	
	/**
	 * Applies ie png hack to selected dom elements
	 *
	 * $('img[@src$=.png]').ifixpng();
	 * @desc apply hack to all images with png extensions
	 *
	 * $('#panel, img[@src$=.png]').ifixpng();
	 * @desc apply hack to element #panel and all images with png extensions
	 *
	 * @name ifixpng
	 */
	 
	$.fn.ifixpng = hack.ltie7 ? function() {
		function fixImage(image, source, width, height, hidden) {
			image.css({filter:hack.filter(source), width: width, height: height})
			  .attr({src:$.ifixpng.getPixel()})
			  .positionFix();
		}
		
    	return this.each(function() {
			var $$ = $(this);
			if ($$.is('img') || $$.is('input')) { // hack image tags present in dom
				var source, img;
				if (this.src && this.src.match($.ifixpng.regexp.img)) { // make sure it is png image
					// use source tag value if set 
					source = (hack.base && this.src.substring(0,1)!='/' && this.src.indexOf(hack.base) === -1) ? hack.base + this.src : this.src;
					// If the width is not set, we have a problem; the image is not probably visible or not loaded
					// and we need a work around.
					if (!this.width || !this.height) {
						$(new Image()).one('load', function() {
							fixImage($$, source, this.width, this.height);
							$(this).remove();
						}).attr('src', source);
					// If the image already has dimensions (it's loaded and visible) we can fix it straight away.
					} else fixImage($$, source, this.width, this.height);
				}
			} else if (this.style) { // hack png css properties present inside css
				var imageSrc = $$.css('backgroundImage');
				// Background repeated images we cannot fix unfortunately
				if (imageSrc && imageSrc.match($.ifixpng.regexp.bg) && this.currentStyle.backgroundRepeat == 'no-repeat') {
					imageSrc = RegExp.$1;
					var x = this.currentStyle.backgroundPositionX || 0, y = this.currentStyle.backgroundPositionY || 0;
					if (x || y) {
						var css = {}, img;
						if (typeof x != 'undefined') {
							if (x == 'left') css.left = 0; 
							// if right is 0, we have to check if the parent has an odd width, because of an IE bug
							else if (x == 'right') css.right = $$.width() % 2 === 1 ? -1 : 0;
							else css.left = x;
						}
						if (typeof y != 'undefined') {
							// if bottom is 0, we have to check if the parent has an odd height, because of an IE bug
							if (y == 'bottom') css.bottom = $$.height() % 2 === 1 ? -1 : 0; 
							else if (y == 'top') css.top = 0;
							else css.top = y;
						}
						img = new Image();
						$(img).one('load', function() {
							var x,y, expr = {}, prop;
							// Now the image is loaded for sure, we can see if the background position needs fixing with an expression (in case of percentages)
							if (/center|%/.test(css.top)) {
								expr.top = "(this.parentNode.offsetHeight - this.offsetHeight) * " + (css.top == 'center' ? 0.5 : (parseInt(css.top) / 100));
								delete css.top;
							}
							if (/center|%/.test(css.left)) {
								expr.left = "(this.parentNode.offsetWidth - this.offsetWidth) * " + (css.left == 'center' ? 0.5 : (parseInt(css.left) / 100));
								delete css.left;
							}
							// Let's add the helper DIV which will simulate the background image
							$$.positionFix().css({backgroundImage: 'none'}).prepend(
								$('<div></div>').css(css).css({
									width: this.width,
									height: this.height,
									position: 'absolute',
									filter: hack.filter(imageSrc)
								})
							);
							if (expr.top || expr.left) {
								var elem = $$.children(':first')[0];
								for (prop in expr) elem.style.setExpression(prop, expr[prop], 'JavaScript');
							}
							$(this).remove();
						});
						img.src = imageSrc;
					} else {
						$$.css({backgroundImage: 'none', filter:hack.filter(imageSrc)});
					}
				}
			}
		});
	} : function() { return this; };
	
	/**
	 * positions selected item relatively
	 */
	$.fn.positionFix = function() {
		return this.each(function() {
			var $$ = $(this);
			if ($$.css('position') != 'absolute') $$.css({position:'relative'});
		});
	};

})(jQuery);


// from http://remysharp.com/2007/01/25/jquery-tutorial-text-box-hints/
jQuery.fn.hint = function () {
	return this.each(function () {
		// get jQuery version of 'this'
		var t = jQuery(this); 
		// get it once since it won't change
		var title = t.attr('title'); 
		// only apply logic if the element has the attribute
		if (title) { 
			// on blur, set value to title attr if text is blank
			t.blur(function () {
				if (t.val() == '') {
					t.val(title);
					t.addClass('blur');
				}
			});
			// on focus, set value to blank if current value 
			// matches title attr
			t.focus(function () {
				if (t.val() == title) {
					t.val('');
					t.removeClass('blur');
				}
			});
			
			// clear the pre-defined text when form is submitted
			t.parents('form:first()').submit(function() {
				if (t.val() == title) {
					t.val('');
					t.removeClass('blur');
				}
			});
			
			// now change all inputs to title
			t.blur();
		}
	});
};


// from http://gsgd.co.uk/sandbox/jquery/easing/
jQuery.extend( jQuery.easing, 
{
	easeOutExpo: function (x, t, b, c, d) {
		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
	}
});

/**
 *
 * Copyright (c) 2007 Tom Deater (http://www.tomdeater.com)
 * Licensed under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 * 
 */
 
(function($) {
	/**
	 * equalizes the heights of all elements in a jQuery collection
	 * thanks to John Resig for optimizing this!
	 * usage: $("#col1, #col2, #col3").equalizeCols();
	 */
	 
	$.fn.equalizeCols = function(){
		var height = 0,
			reset = $.browser.msie ? "1%" : "auto";
  
		return this
			.css("height", reset)
			.each(function() {
				height = Math.max(height, this.offsetHeight);
			})
			.css("height", height)
			.each(function() {
				var h = this.offsetHeight;
				if (h > height) {
					$(this).css("height", height - (h - height));
				};
			});
			
	};
	
})(jQuery);

/**
 *
 * Copyright (c) 2008 Tom Deater (http://www.tomdeater.com)
 * Licensed under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * uses an iframe, sized in ems, to detect font size changes then trigger a "fontresize" event
 * heavily based on code by Hedger Wang: http://www.hedgerwow.com/360/dhtml/js-onfontresize.html
 *
 * "fontresize" event is triggered on the document object
 * subscribe to event using: $(document).bind("fontresize", function (event, data) {});
 * "data" contains the current size of 1 em unit (in pixels)
 * 
 */
 
$.onFontResize = (function ($) {
	var $resizeframe = null;
		
	// initialize
	$(document).ready(function () {
		$resizeframe = $("<iframe />")
			.attr("id", "frame-onFontResize" + Date.parse(new Date))
			.css({width: "100em", height: "10px", position: "absolute", borderWidth: 0, top: "-5000px", left: "-5000px"})
			.appendTo("body");
			
		if ($.browser.msie) {
			// use IE's native iframe resize event
			$resizeframe.bind("resize", function () {
				$.onFontResize.trigger($resizeframe[0].offsetWidth / 100);
			});
		} else {
			// everyone else uses script inside the iframe to detect resize
			var doc = $resizeframe[0].contentWindow || $resizeframe[0].contentDocument || $resizeframe[0].document;
			doc = doc.document || doc; 
			doc.open();
			doc.write('<div id="em" style="width:100em;height:10px;"></div>');
			doc.write('<scri' + 'pt>window.onload = function(){var em = document.getElementById("em");window.onresize = function(){if(parent.$.onFontResize){parent.$.onFontResize.trigger(em.offsetWidth / 100);}}};</scri' + 'pt>');
			doc.close();
		}
	});
	
	return {
		// public method, so it can be called from within the iframe
		trigger: function (em) {
			$(document).trigger("fontresize", [em]);
		}
	}
}) (jQuery);

/**
 *
 * Copyright (c) 2007 Tom Deater (http://www.tomdeater.com)
 * Licensed under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 * 
 */
 
(function($) {
	/**
	 * attaches a character counter to each textarea element in the jQuery object
	 * usage: $("#myTextArea").charCounter(max, settings);
	 */
	
	$.fn.charCounter = function (max, settings) {
		max = max || 100;
		settings = $.extend({
			container: "<span></span>",
			classname: "charcounter",
			format: "(%1 characters remaining)",
			pulse: true,
			delay: 0
		}, settings);
		var p, timeout;
		
		function count(el, container) {
			el = $(el);
			if (el.val().length > max) {
			    el.val(el.val().substring(0, max));
			    if (settings.pulse && !p) {
			    	pulse(container, true);
			    };
			};
			if (settings.delay > 0) {
				if (timeout) {
					window.clearTimeout(timeout);
				}
				timeout = window.setTimeout(function () {
					container.html(settings.format.replace(/%1/, (max - el.val().length)));
				}, settings.delay);
			} else {
				container.html(settings.format.replace(/%1/, (max - el.val().length)));
			}
		};
		
		function pulse(el, again) {
			if (p) {
				window.clearTimeout(p);
				p = null;
			};
			el.animate({ opacity: 0.1 }, 100, function () {
				$(this).animate({ opacity: 1.0 }, 100);
			});
			if (again) {
				p = window.setTimeout(function () { pulse(el) }, 200);
			};
		};
		
		return this.each(function () {
			var container = (!settings.container.match(/^<.+>$/)) 
				? $(settings.container) 
				: $(settings.container)
					.insertAfter(this)
					.addClass(settings.classname);
			$(this)
				.bind("keydown", function () { count(this, container); })
				.bind("keypress", function () { count(this, container); })
				.bind("keyup", function () { count(this, container); })
				.bind("focus", function () { count(this, container); })
				.bind("mouseover", function () { count(this, container); })
				.bind("mouseout", function () { count(this, container); })
				.bind("paste", function () { 
					var me = this;
					setTimeout(function () { count(me, container); }, 10);
				});
			if (this.addEventListener) {
				this.addEventListener('input', function () { count(this, container); }, false);
			};
			count(this, container);
		});
	};

})(jQuery);


/**
 * jQuery.ScrollTo - Easy element scrolling using jQuery.
 * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 * Date: 2/19/2008
 * @author Ariel Flesler
 * @version 1.3.3
 */
;(function($){var o=$.scrollTo=function(a,b,c){o.window().scrollTo(a,b,c)};o.defaults={axis:'y',duration:1};o.window=function(){return $($.browser.safari?'body':'html')};$.fn.scrollTo=function(l,m,n){if(typeof m=='object'){n=m;m=0}n=$.extend({},o.defaults,n);m=m||n.speed||n.duration;n.queue=n.queue&&n.axis.length>1;if(n.queue)m/=2;n.offset=j(n.offset);n.over=j(n.over);return this.each(function(){var a=this,b=$(a),t=l,c,d={},w=b.is('html,body');switch(typeof t){case'number':case'string':if(/^([+-]=)?\d+(px)?$/.test(t)){t=j(t);break}t=$(t,this);case'object':if(t.is||t.style)c=(t=$(t)).offset()}$.each(n.axis.split(''),function(i,f){var P=f=='x'?'Left':'Top',p=P.toLowerCase(),k='scroll'+P,e=a[k],D=f=='x'?'Width':'Height';if(c){d[k]=c[p]+(w?0:e-b.offset()[p]);if(n.margin){d[k]-=parseInt(t.css('margin'+P))||0;d[k]-=parseInt(t.css('border'+P+'Width'))||0}d[k]+=n.offset[p]||0;if(n.over[p])d[k]+=t[D.toLowerCase()]()*n.over[p]}else d[k]=t[p];if(/^\d+$/.test(d[k]))d[k]=d[k]<=0?0:Math.min(d[k],h(D));if(!i&&n.queue){if(e!=d[k])g(n.onAfterFirst);delete d[k]}});g(n.onAfter);function g(a){b.animate(d,m,n.easing,a&&function(){a.call(this,l)})};function h(D){var b=w?$.browser.opera?document.body:document.documentElement:a;return b['scroll'+D]-b['client'+D]}})};function j(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
