/**
 * $Id: include.js,v 1.167 2018/05/10 15:16:00 cvs Exp $
 *
 * @author Frederick J Richart
 * @copyright Copyright © 2006-2017, Useful Media Planet, LLC, All rights reserved.
 */
var Utilities, _FUWutil, _FUW = {}, AnimatedImage;
/**
 * @param String id is a unique identifier for this particular animation.
 * @param String delay
 * @param Object settings
 * @param Object imageSet
 * @param String trans_option
 */
AnimatedImage = _FUW.AnimatedImage = function (id, delay, settings, imageSet, trans_option) {
	var t = this, tempSet, i, c;
	t.objectClass = 'AnimatedImage';
 	t.id = id;
 	t.delay = delay;
 	t.settings = settings;
 	if (settings.randomize) {
 		tempSet = imageSet;
 		imageSet = [];
 		while(c = tempSet.length) {
 			i = Math.floor(Math.random() * c);
 			imageSet.push(tempSet[i]);
 			tempSet.splice(i,1);
 		}
 	}
 	t.imageSet = imageSet;
 	t.trans_option = trans_option;
 	t.pan_easing = '';
 	t.flipTimerID = 0;
 	t.path = t.trans_effect = t.width = '';
 	t.paging_div = t.container = null;
 	t.images = [];
 	t.imgarray = [];
 	_FUW.U.onload(t);
 };
 _FUW.AnimatedImage.prototype = {
	image : null,
 	onPageLoad : function() {
		var i=0, t = this,
			src, imageElement, e, w, h, o, alt, imagesContainer, v,
			animate = true,
			U = _FUW.U,
			settings = t.settings,
			imageSet = t.imageSet,
			numImages = imageSet.length,
			thumbsDiv = null,
			wrapperElement, pos,
			popup = t.popup = U.getElementById('AnimatedImagePopupContainer'),
			isSlider = t.isSlider = (settings.trans_effect == 'slider'),
			isVertical = t.isVertical = settings.vertical_slides,
			id = t.id,
			oldIE = U.IE67;

		t.inTransition = false;
		imageElement = t.image = U.getElementById('animated_image_id' + id);
		t.link = U.getElementById('animated_image_link' + id);
		t.title = U.getElementById('animated_image_title' + id);
		t.html = U.getElementById('animated_image_html' + id);

		// Handle configuration of popup container if it exists
		if (popup) {
			$(popup).css({display:'block',zIndex:-1});
			$('#AnimatedImagePopupContainer > .AnimatedImagePopupTable').css({width:(v=settings.popup_width)? v : settings.width + 60});
			pos = U.getAbsPosition(popup, null, true);
			$('body').append(popup);
			$(popup).css({top:pos.top + 'px',left:pos.left + 'px'});
			t.popupBody = e = U.getElementById('AnimatedImagePopupBody');
		//	$(e).css({width:settings.width});
			U.Adjust(popup, pos.top, pos.left);
			$(popup).css({display:'none'});
			t.popupBlock = e = U.getElementById('AnimatedImagePopupBlocker');
			$('body').append(e);
		}
		imagesContainer = t.container = imageElement.parentNode;
		t.anchor = imagesContainer.parentNode;
		if (settings instanceof Object) {
			if (settings.thumbs) {
				thumbsDiv = U.getElementById('animated_image_thumbs' + id);
			}
			if (isSlider) {
				// For this we want the width/height to be the thumb values.
				settings.large_width = settings.width;
				settings.large_height = settings.height;
				settings.width = settings.thumb_width;
				settings.height = settings.thumb_height;
				t.sliderWidth = settings.total_thumb_width = settings.thumb_width + settings.slide_spacing;
				t.slideRight = false;
				t.containerWidth = $(imagesContainer).width();
				U.addClass(imagesContainer, 'AnimatedImageSlider');
			} else {
				U.addClass(imagesContainer, 'AnimatedImageNormal');
			}
			t.path = '';
			for(i in settings) t[i] = settings[i];
			if (!t.num_slides) t.num_slides = 1;
			/*
			 * Compute the center of the display space for those transition effects
			 * that need to know this.
			 */
			t.cleft = Math.round((t.width) / 2) + 'px';
			t.ctop = Math.round((t.height) / 2) + 'px';
		} else {
			t.path = settings;
		}
		if (t.paging_div) t.paging_div = document.getElementById(t.paging_div);
		alt = imageElement.getAttribute("alt");
		t.index = t.trans_effect == 'flashy' ? numImages : 0;
		t.flipping = true;
		for(i=0; i<numImages; i++) {
			imageElement = new Image();
			o = imageSet[i];
			if (o instanceof Object) {
				src = o.src;
			} else {
				src = o;
				o = new Object();
				o.src = src;
			}
			o.index = i;
			imageElement.info = o;
			if (t.path) src = t.path + (src.substr(0,1) == '/' ? '' : '/') + src;
			o.src = imageElement.src = src;
			if (isSlider) {
				o.large_width = o.width;
				o.large_height = o.height;
				v = U.scaleObject(o.width, o.height, t.width, t.height);
				o.width = v.width;
				o.height = v.height;
			}
			if (w = o.width) {
				imageElement.setAttribute("width", w);
				imageElement.setAttribute("height", h = o.height);
				imageElement.setAttribute("alt", alt);
				if (t.trans_effect != 'jflip') {
					o.left = imageElement.style.left = (v = Math.max(0, Math.round((t.width - w) / 2))) + 'px';
					o.right = (v + w) + 'px';
					o.top = imageElement.style.top = (v = Math.max(0, Math.round((t.height - h) / 2))) + 'px';
					o.bottom = (v + h) + 'px';
					imageElement.style.position = "absolute";
				}
				/*
				 * Here we either add the image to the end or in the case of the first
				 * image we replace the one that was loaded with the page with the
				 * one we just generated (they should be the same).
				 */
				if (i) {
					imageElement.style.display = "none";
					imagesContainer.appendChild(imageElement);
				} else {
					imagesContainer.replaceChild(imageElement, t.image);
					t.image = imageElement;
				}
				if (isSlider) {
					/*
					 * The sliders require building each image frame with its
					 * photo, title, and text into .
					 */
					v = '<div class="AnimatedImageWrapper"></div>';
					if (settings.enable_popup) {
						imageElement.onclick = function(event){t.openPopup(event, this.info, true);};
						$(imageElement).addClass('Pointer');
					} else if (o.url) v = '<a class="AnimatedImageWrapper" href="' + o.url + '"></a>';
					$(imageElement).wrap(v);
					o.wrapper = wrapperElement = imageElement.parentNode;
					if (isVertical) $(wrapperElement).css({marginBottom:settings.slide_spacing + 'px'});
					else $(imageElement).css({marginRight:settings.slide_spacing + 'px'});
					$(imageElement).css({'float':'left', display:'', position:''});
					if (settings.title_height) {
						$(wrapperElement).append(e = document.createElement('div'));
						$(e).addClass('AnimatedImageSliderTitle');
						$(e).css({width:settings.thumb_width + 'px',height:settings.title_height + 'px'});
						if (v = o.title) $(e).append(v);
					}
					if (settings.text_height) {
						$(wrapperElement).append(e = document.createElement('div'));
						$(e).addClass('AnimatedImageSliderHTML');
						$(e).css({width:settings.thumb_width + 'px',height:settings.text_height + 'px'});
						if (v = o.html) $(e).append(v);
					}
					if (!i) t.wrapper = wrapperElement;
					if ((i) >= settings.num_slides) $(wrapperElement).css({display:'none'});
				}
			}
			if (isSlider){
				animate = !isVertical && numImages > settings.num_slides;
			} else {
				// Setup the initial title and HTML entries
				o.title = (t.title && o.title) ? t.createDiv(t.title, o.title, i, 'AnimatedImageTitleInner', 'AnimatedImageTitleSelector') : null;
				o.html = (t.html && o.html) ? t.createDiv(t.html, o.html, i, 'AnimatedImageHTMLInner','AnimatedImageHTMLSelector') : null;
			}

			//If we are generating thumb indicators, it is done here.
			if (thumbsDiv && !isSlider) {
				thumbsDiv.appendChild(e = document.createElement("div"));
				e.className = i ? "AnimatedImageThumbContainer" : "AnimatedImageSelectedThumbContainer";
				o.thumb = e;
				if (settings.thumbs == 'num') U.setElementText(e, (i + 1) + '', false);
				e.info = o;
				e.onclick = function(e){t.click(e);};
			}
			o.panorama = (o.width > t.width);
			o.imageElement = imageElement;
			t.images[i] = o;
		}
		// Add thumbs ending element
		if (thumbsDiv) {
			if (isSlider) {
				if (animate) {
					$(thumbsDiv).addClass('SliderThumbs');
					thumbsDiv.appendChild(t.sliderLeft = e = document.createElement("div"));
					$(e).addClass('AnimatedImageLeftArrow');
					e.onclick = function(e){t.clickLeft(e);};
					if (oldIE) $(e).append('«');

					thumbsDiv.appendChild(t.sliderRight = e = document.createElement("div"));
					$(e).addClass('AnimatedImageRightArrow');
					e.onclick = function(e){t.clickRight(e);};
					if (oldIE) $(e).append('»');
				}
			} else {
				e = document.createElement("div");
				e.className = "AnimatedImageThumbEnd";
				thumbsDiv.appendChild(e);
			}
		}

		// Set the initial image's title/html height
		o = t.images[0];
		if (e = t.title && o.title) $(e).css({height:$(o.title).height()});
		if (e = t.html && o.html) $(e).css({height:$(o.html).height()});
		t.current = t.images[0];
		/*
		 * Don't start animation if we only have 1 image or if the display time
		 * is zero.
		 */
		if (numImages < 2 || t.delay == 0 || !animate) return;

		switch (t.trans_effect) {
			case 'flashy':
				t.flip(null);
				break;
			case 'jflip':
				t.imgarray = [];
				t.allLoaded = false;
				t.checkTimerID = setInterval(function(){t.checkLoaded();}, 1000);
				$(t.images).each(function(){
					i = this.imageElement;
					t.imgarray.push(i);
				});
				t.flip(null);
				break;
			default:
				t.display(t.images[0]);
		};
	},
	createDiv : function(parentNode, html,i, classname, selname) {
		var pos,
			d = document.createElement('div'),
			U = _FUW.U,
			cn = classname ? ' class="' + classname + '"' : '';

		if (selname) d.setAttribute('class', selname);
		if (i) parentNode.appendChild(d);
		else U.replaceElementContent(parentNode, d);

		/*
		 * Have to trick this stupid browser to get it to have "layout" otherwise
		 * the block finds itself in some totally off the wall place when we do
		 * the absolute position.  Setting min-height is one way to trigger this.
		 */
		if (U.IE67) $(d).css({'min-height':'1px'});

		// Locate postion before we make absolute
		pos = U.getAbsPosition(d);
		if (U.IE67) $(d).css({'min-height':'none'});

		$(d).css({position:'absolute',top:pos.top + 'px',left:pos.left + 'px',width:pos.width + 'px',opacity:i ? 0 : 1, display:i ? 'none':'block'});
		// wrap html to keep IE from getting winky when this is just plain text
		d.innerHTML = '<div' + cn +'>' + html + '</div>';
		if (!i) $(parentNode).css({height:$(d).height()});
		return d;
	},
	click : function(event) {
		var t = this, e, evt = window.event || event;
		e = evt.target ? evt.target : evt.srcElement;
		if (e && e.info) {
			if (t.flipTimerID) clearInterval(t.flipTimerID);
			t.flipping = false;
			t.flip(e.info.index);
		}
	},
	clickLeft : function(event) {
		var t = this;
		if (t.inTransition) {
			t.clickQueue = t.clickLeft;
			return;
		}
		t.clickQueue = null;
		t.slideRight = false;
		t.flip(null);
	},
	clickRight : function(event) {
		var t = this;
		if (t.inTransition) {
			t.clickQueue = t.clickRight;
			return;
		}
		t.clickQueue = null;
		t.slideRight = true;
		t.flip(null);
	},
	openPopup : function(event, o, isModal) {
		var t=this, U = _FUW.U,
			block = t.popupBlock,
			popup = t.popup,
			settings = t.settings;

		if (t.popupOpen || !popup) return;
		$('.AnimatedImagePopupCloseLink').each(function(index, element){
				element.onclick = function(event){t.closePopup(event);};
		});
		if (isModal) $(block).css({display:'block',zIndex:U.Zindex++});
		$(popup).css({display:'block',zIndex:U.Zindex++});
		$('AnimatedImagePopupTable').css({width:(settings.large_width + 20) + 'px'});
		t.loadPopup(o);
		U.eventCancel(event);
		t.popupOpen = true;
		return false;
	},
	loadPopup : function(o) {
		var t = this, U = _FUW.U, v,e,
			popup = t.popup,
			container = t.popupBody,
			imageElement = new Image(),
			oldIE = U.IE67;

		t.popupCurrentObject = o;
		$(container).empty();
		$(container).append('<div class="AnimatedImagePopupLeftArrow"></div>', imageElement, '<div class="AnimatedImagePopupRightArrow"></div>');
		$(container).wrapInner('<div class="AnimatedImagePopupWrapper"></div>');
		imageElement.setAttribute('src', o.src);
		imageElement.setAttribute('width', o.large_width);
		imageElement.setAttribute('height', o.large_height);
		$(imageElement).addClass('AnimatedImagePopupImage');
		$('.AnimatedImagePopupLeftArrow').click(function(e){t.switchPopup(-1);});
		$('.AnimatedImagePopupRightArrow').click(function(e){t.switchPopup(1);});
		if (oldIE) {
			$('.AnimatedImagePopupLeftArrow,.AnimatedImagePopupRightArrow').addClass('oldIE');
			$('.AnimatedImagePopupLeftArrow').append('〈');
			$('.AnimatedImagePopupRightArrow').append('〉');
		}
//		$(imageElement).wrap('<div style="text-align:center"></div>');
		if (v = o.url) {
			$(imageElement).wrap('<a href="' + o.url + '"></a>');
		}
		if (v = o.title) {
			$(container).append(e = document.createElement('div'));
			$(e).addClass('AnimatedImagePopupTitle');
			$(e).append(v);
		}
		if (v = o.html) {
			$(container).append(e = document.createElement('div'));
			$(e).addClass('AnimatedImagePopupHTML');
			$(e).append(v);
		}
		U.Adjust(popup, false);
		return false;
	},
	switchPopup : function(next) {
		var t = this, index,
			setLength = t.imageSet.length,
			o = t.popupCurrentObject;
		if (!t.popupOpen || !o) return;
		index = o.index + next;
		if (index < 0) index = setLength -1;
		else index = index % setLength;
		o = t.images[index];
		t.loadPopup(o);
	},
	closePopup : function(event) {
		var t = this;
		if (!t.popupOpen) return;
		if (t.popupBlock) $(t.popupBlock).css({display:'none',zIndex:-1});
		if (t.popup) $(t.popup).css({display:'none',zIndex:-1});
		t.popupOpen = false;
	},
	checkLoaded : function() {
		var t = this, i=0;
		if (!t.allLoaded) {
			for(i in t.images) {
				if (!t.images[i].loaded) return;
			}
			t.allLoaded = true;
			t.flip(null);
		}
		clearInterval(t.checkTimerID);
	},
	start : function() {
		var t = this;
		if (!t.image) return;
		t.flipTimerID = setInterval(function(){t.flip(null);}, this.delay);
	},
	flip : function(newIndex) {
		var t = this, i2=0, i3=0, v = null, o, o2,
			c = t.current,
			ct = c.title,
			ch = c.html,
			ot,oh, imageElement,
			time = t.trans_time,
			sop, eop, opt,
			th = null, hh = null,
			isSlider = t.isSlider,
			easing = t.easing,
			imagesContainer = t.container,
			sliderWidth = t.sliderWidth,
			flipTimerID = t.flipTimerID,
			slideRight = t.slideRight,
			setLength = t.imageSet.length,
			index = t.index,
			numSlides = t.num_slides,
			r,e,s;

		t.inTransition = true;
		if (newIndex === null) {
			if (slideRight) {
				i3 = (index + numSlides -1) % setLength;
				if ((--index) < 0) index = setLength - 1;
				i2 = t.index = index;
			} else {
				i2 = (index + numSlides) % setLength;
				index = t.index = (index + 1) % setLength;
			}
		} else {
			index = t.index = newIndex;
		}
		t.last = ((index+1) == setLength);
		o = t.images[index];
		ot = o.title;
		oh = o.html;

		/*
		 * Set the height of the title/html elements to the max hight of this and next items.
		 * Before measuring the height we cannot have the element set to display:none as it
		 * won't have height in this condition.  Instead we will enable but set invisible
		 */
		if (t.title && !isSlider) {
			if (ot) $(ot).css({'z-index':1000, opacity:0,display:'block'});
			th = Math.max(ct ? $(ct).height() : 0, ot ? $(ot).height() : 0);
			$(t.title).css({height:th});
		}
		if (t.html && !isSlider) {
			if (oh) $(oh).css({'z-index':1000, opacity:0,display:'block'});
			hh = Math.max(ch ? $(ch).height() : 0, oh ? $(oh).height() : 0);
			$(t.html).css({height:hh});
		}
		/*
		 * We seem to have wierdness with IE where randomly the image ends up much larger
		 * here than what we set above.  Rather than trying to figure out why this
		 * piece of junk does this (none of the other browsers do), we'll just keep
		 * resetting the size here.
		 */
		if (o.width) {
			o.imageElement.setAttribute("width", o.width);
			o.imageElement.setAttribute("height", o.height);
		}
		opt = t.trans_option ? t.trans_option : new Object();
		// Hide panorama overflow if new image a panorama but don't change if not (last image could be panorama)
		if (o.panorama || t.isSlider) $(t.anchor).css({overflow:'hidden'});
		switch(t.trans_effect) {
		case 'slider':
			clearInterval(flipTimerID);
			o2 = t.images[i2];
			if (t.isVertical) break;  // Not sliding these (yet)
			$(imagesContainer).width(t.containerWidth + sliderWidth);
			$(o2.wrapper).css({display:''});
			v = -sliderWidth + 'px';
			if (slideRight) {
				$(imagesContainer).css({left:v});
				$(imagesContainer).prepend(o2.wrapper);
			}
			$(imagesContainer).animate({left:slideRight ? '0px' : v}, time, easing, function(){
				t.endTransSlider(o, slideRight ? t.images[i3] : t.wrapper);
			});
			break;
		case "fade":
			clearInterval(flipTimerID);
			time = time / 2;
			if (ct) $(ct).animate({opacity:0},{queue:false, duration:time, easing:easing});
			if (ch) $(ch).animate({opacity:0},{queue:false, duration:time, easing:easing});
			$(t.image).css({opacity:1});
			$(t.image).animate({opacity:0}, time, easing, function(){
				t.image.style.display = 'none';
				if (ot) $(ot).animate({opacity:1},{queue:false, duration:time, easing:easing});
				if (oh) $(oh).animate({opacity:1},{queue:false, duration:time, easing:easing});
				$(o.imageElement).css({opacity:0,display:'inline'});
				$(o.imageElement).animate({opacity:1}, time, easing, function(){
					t.endTrans(o, ct, ot, ch, oh);
				});
			});
			break;
		case "fadeover":
			clearInterval(flipTimerID);
			$(t.image).css({'z-index':2000});
			$(o.imageElement).css({'z-index':1000,opacity:0,display:'inline'});
			if (ct) $(ct).animate({opacity:0},{queue:false, duration:time, easing:easing});
			if (ot) $(ot).animate({opacity:1},{queue:false, duration:time, easing:easing});
			if (ch) $(ch).animate({opacity:0},{queue:false, duration:time, easing:easing});
			if (oh) $(oh).animate({opacity:1},{queue:false, duration:time, easing:easing});
			$(t.image).animate({opacity:0},{queue:false, duration:time, easing:easing});
			$(o.imageElement).animate({opacity:1}, time, easing, function(){
				t.endTrans(o, ct, ot, ch, oh);
			});
			break;
		case "growover":
			clearInterval(flipTimerID);
			$(t.image).css({'z-index':1000});
			$(o.imageElement).css({'z-index':2000,display:'inline',width:'0px',height:'0px',left:t.cleft,top:t.ctop});
			if (ot) {
				if (ct) $(ct).css({'z-index':1000,'background-color':'none'});
				$(ot).css({'z-index':2000,height:'0px',opacity:1,'background-color':'#ffffff'});
				$(ot).animate({height:th,top:'0px'}, time, easing);
			}
			if (oh) {
				if (ch) $(ch).css({'z-index':1000,'background-color':'none'});
				$(oh).css({'z-index':2000,height:'0px',opacity:1,'background-color':'#ffffff'});
				$(oh).animate({height:hh,top:'0px'}, time, easing);
			}
			$(o.imageElement).animate({width:o.width,height:o.height,top:o.top,left:o.left}, time, easing, function(){
				if (ct) $(ct).css({opacity:0});
				if (ch) $(ch).css({opacity:0});
				t.endTrans(o, ct, ot, ch, oh);
			});
			break;
		case "flashy":
			clearInterval(flipTimerID);
			$(t.image).css({display:'none'});
			if (t.last) {
				v = [t.cleft,t.ctop];
				sop = 0.4; eop = 1;
			} else {
				v = t.rndSelect([[o.left,o.top],[t.cleft,o.top],[o.right,o.top],[o.left,o.bottom],[t.cleft,o.bottom],[o.right,o.bottom]]);
				sop = 1; eop = 0.4;
			}
			$(o.imageElement).css({display:'inline',width:'0px',height:'0px',left:v[0],top:v[1],opacity:sop});
			$(o.imageElement).animate({width:o.width,height:o.height,top:o.top,left:o.left,opacity:eop}, time, easing, function(){
				if (ct) $(ct).css({opacity:0});
				if (ch) $(ch).css({opacity:0});

				/* Clear t.image so endTrans doesn't turn off the image.  We
				 * do this because the flashy transition starts the image display
				 * rather than ending it.
				 */
				t.image = null;
				t.endTrans(o, ct, ot, ch, oh);
			});
			break;
		case "explode":
		case "puff":
		case "fold":
		case "clip":
			v = t.rndSelect(['horizontal','vertical']);
		case "drop":
		case "slide":
			if (!v) v = t.rndSelect(['left','right','up','down']);
			clearInterval(flipTimerID);
			$(t.image).css({'z-index':2000});
			$(o.imageElement).css({'z-index':1000,display:'inline'});
			$(t.image).hide(t.trans_effect, jQuery.extend({pieces:25, easing:easing, size:t.height/3, direction:v}, opt), time, function(){
				t.endTrans(o, ct, ot, ch, oh);
			});
			break;
		case "flip":
			clearInterval(flipTimerID);
			if (t.current.panorama) $(t.image).css({width:t.width,left:t.current.left});
			$(t.image).flip(jQuery.extend({easing:easing, direction:t.rndSelect(['rl','lr','tb','bt']), color:t.trans_color, content:$(o.imageElement), onEnd:function(){
				if (t.current.panorama) $(t.image).css({width:t.current.width});
				$(o.imageElement).css({display:'inline'});
				t.endTrans(o, ct, ot, ch, oh);
			}}, opt));
			break;
		case "cube":
			clearInterval(flipTimerID);
			r = t.width / 5;
			e = t.width / 12;
			s = t.width / 10;

			$(imagesContainer).imagecube(jQuery.extend({speed:time, easing:easing, repeat:t.repeat, pause:t.delay,reduction:r,expansion:e,segments:s, beforeRotate:function(current, next){
				if ((current.src.indexOf(".cube"))>0)
					$(current).css({border:'2px solid black'});
				if ((next.src.indexOf(".cube"))>0)
					$(next).css({border:'2px solid black'});
			}, afterRotate:function(current, next){
				o = next.info;
				$(next).css({width:o.width+'px', height:o.height+'px'});
				t.inTransition = false;
			}}, opt));
			break;
		case "jflip":
			clearInterval(flipTimerID);
			$(imagesContainer).jFlip(t.width, t.height, jQuery.extend({background:'#fff', cornersTop:false, curlSize:0.15, circular:false}, opt), $(t.imgarray)).bind("flip.jflip",function(event,index,total){
				if(t.paging_div) {
					$(t.paging_div).html(t.paging + " " + (index+1) + " of " + total);
				}
				t.inTransition = false;
			});
			break;
		case 'slider':
			break;
		default:
			if (o.width) {
				// Disable current and enable new
				imageElement = o.imageElement;
				t.image.style.display = "none";
				imageElement.style.display = 'inline';
				t.image = imageElement;
			} else {
				// Old style - just replace src attribute
				t.image.src = o.src;
			}
			if (ct) $(ct).css({opacity:0,display:'none'});
			if (ot) $(ot).css({opacity:1});
			if (ch) $(ch).css({opacity:0,display:'none'});
			if (oh) $(oh).css({opacity:1});
			t.inTransition = false;
			t.current = o;
		}
	},
	/**
	 * endTrans completes the transition that was started by the transition function
	 * above.  The current image (t.image) is disabled and the new (o) is used as
	 * the new current.  If using links, this makes sure the image is now a link
	 * to the new link, and lastly if the title/html have changed heights this
	 * will also be transitioned.
	 */
	endTrans : function(o, ct, ot, ch, oh) {
		var t = this, e,v,
			easing = t.easing,
			oth = ot ? $(ot).height() : 0,
			cth = ct ? $(ct).height() : 0,
			ohh	= oh ? $(oh).height() : 0,
			chh = ch ? $(ch).height() : 0;

		$(t.image).css({display:'none',left:t.current.left});
		t.image = o.imageElement;
		if (e = t.link) {
			if (v = o.url) {
				e.setAttribute('href', v);
				e.style.width = o.width + 'px';
				e.style.height = o.height + 'px';
				e.style.display = 'block';
				e.target = (v.substr(0,4) == 'http') ? '_blank' : '_self';
			} else {
				e.style.display = 'none';
			}
		}
		// Animate the change in height for title/html
		if ((e = t.title) && oth != cth) $(e).animate({height:oth}, {queue:false, duration:1000, easing:easing});
		if ((e = t.html) && ohh != chh) $(e).animate({height:ohh}, {queue:false, duration:1000, easing:easing});

		// Make sure html and titles have switched
		if (ct) $(ct).css({display:'none'});
		if (ch) $(ch).css({display:'none'});
		if (ot) $(ot).css({opacity:1});
		if (oh) $(oh).css({opacity:1});
		if (t.last && (!t.repeat || t.trans_effect == 'flashy' )) return;
		t.display(o);
	},
	endTransSlider : function(o, oRemove) {
		var t = this,
			lastWrapper = t.wrapper,
			imageContainer = t.container,
			slideRight = t.slideRight;

		$(oRemove).css({display:'none'});
		t.wrapper = o.wrapper;
		if (!slideRight) $(imageContainer).append(lastWrapper);
		$(imageContainer).css({width:t.containerWidth+'px', left:'0px'});
		t.display(o);
	},
	display : function(o) {
		var t = this, thumb,
		flipping = t.flipping;

		// Handle thumb display
		if (thumb = t.current.thumb) thumb.className = "AnimatedImageThumbContainer";
		if (thumb = o.thumb) thumb.className = "AnimatedImageSelectedThumbContainer";
		t.current = o;
		$(t.anchor).css({overflow: (o.panorama || t.isSlider) ? 'hidden' : 'visible'});
		$(o.imageElement).css({left:o.left});
		if (o.panorama) {
			// Panorama
			$(o.imageElement).animate({left:-(o.width-t.width)}, t.pan_time, t.pan_easing, function(){
				if (flipping) t.flipTimerID = setInterval(function(){t.flip(null);}, t.delay);
			});
		} else {
			if (flipping) t.flipTimerID = setInterval(function(){t.flip(null);}, t.delay);
		}
		t.inTransition = false;
		if (t.clickQueue) t.clickQueue(null);
	},
	rndSelect : function(a) {
		var i = Math.min(Math.floor((Math.random() * a.length)), a.length-1);
		return a[i];
	}
};
 _FUW.AnimatedImageUploadEngine = function(formID, imageID, folder, page) {
		var t = this;
		t.objectClass = 'AnimatedImageUploadEngine';
		t.formID = formID;
		t.imageID = imageID;
		t.page = page;
		t.folder = folder;
		t.uploading = false;
		t.savedImage = '';
		_FUW.U.onload(t);
	};
_FUW.AnimatedImageUploadEngine.prototype = {
	onPageLoad : function() {
		var t = this,
			imageID = t.imageID,
			f = xdom.getElementById(t.formID),
			ie = f.photo_file,
			X = _FUW.X;

		t.form = f;
		t.img_file = ie;
		t.img_cell = X.getElementById('animated_image_image_cell' + imageID);
		t.manageImg = X.getElementById('animated_image_edit_photo_' + imageID);
		X.findAssociatedLabel(ie,false);
		X.setOnsubmitEvent(ie, this);
		X.setFormsubmitHandler(ie);
	},
	/**
	 * This method is called by the upload plugin whenever it submits the upload form that initiates a file upload.
	 *
	 * @param upload is the upload object
	 * @param form is the upload form being processed.
	 */
	SubmitForm : function(upload, form) {
		this.uploading = true;
	},
	/**
	 * This method is called by the upload plugin whenever it initiates an AJAX status update call.  It permits
	 * this object to modify the parameters of that call.
	 *
	 * @param upload is the upload object
	 * @param post is the post string
	 */
	uploadStatusRequest : function(upload, post) {
		return post + "&uploadCallback=AnimatedImagesWidgetUploadCallback&AnimatedImagesImageID=" + this.imageID + '&AnimatedImagesPage=' + this.page;
	},
	/**
	 * This method is called by the upload plugin whenever an upload has completed for a given file.
	 *
	 * @param upload
	 * @param path
	 * @param response
	 * @param params
	 */
	uploadComplete : function(upload, response){
		var t = this, U = _FUW.U,
			form = t.form,
			fe = form.photo_file,
			file = response.getAttribute("filename"),
			ic = t.img_cell,
			manageImg = t.manageImg,
			src = t.folder + '/' + file + '?ts=' + (new Date()).getTime();

		if (fe) fe.value = file;
	//	U.setElementText(form.events_photo_upload, 'Replace Photo', false);
		if (ic) {
			ic.innerHTML = '<img src="' + src + '" style="max-width:200px;max-height:200px;" />';
		} else {
			debugger;
		}
		if (manageImg) manageImg.src = src;
		t.uploading = false;
		U.onPageUpdate();
		_FUW.X.setElementFailState(this.img_file, true);
	},
	onElementSubmit : function() {
		var rv = !this.uploading, msg = rv ? '' : "You still have an image upload in progress.  Please wait for this to complete before submitting.";
		_FUW.X.setElementFailState(this.img_file, !this.uploading, msg);
		return rv;
	}
};
Number.prototype.NaN0=function(){return isNaN(this) ? 0 : this;};
_FUW.UtilitiesEngine = function() {
 	var t = this,
		agent = navigator.userAgent;
 	t.objectClass = 'UtilitiesEngine';
	t.Opera = (window.opera && opera.buildNumber) || /OPR\//.test(agent);
	t.WebKit = /WebKit/.test(agent);
	t.IE = t.IE_PRE11 = !t.WebKit && !t.Opera && (/MSIE/gi).test(agent) && (/Explorer/gi).test(navigator.appName);
	t.IE6 = t.IE && /MSIE [56]/.test(agent);
	t.IE7 = t.IE && /MSIE [7]/.test(agent);
	t.IE67 = t.IE && /MSIE [567]/.test(agent);
	t.IE678 = t.IE && /MSIE [5678]/.test(agent);
	t.IE8 = t.IE && /MSIE [8]/.test(agent);
	t.IE9 = t.IE && /MSIE [9]/.test(agent);
	t.IE10 = t.IE && /MSIE [10]/.test(agent);
	t.IE11 = false;
	if (!t.IE && /Trident\/7.0/.test(agent)) {
		// IE11+ trying to sneak by as not IE
		t.IE = t.IE11_PLUS = true;
		t.IE11 = t.IE && /rv:11.0/.test(agent);
	}
	if (t.IE12 = (!t.IE && /Edge\/12/.test(agent))) t.IE11_PLUS = true;
	t.IETouch = t.IE && /Touch/.test(agent);
	t.IEARM = t.IE && /ARM/.test(agent);
	t.Gecko = !t.WebKit && /Gecko/.test(agent);
	t.Chrome = t.WebKit && /Chrome/.test(agent) && !t.Opera;
	t.Mac = agent.indexOf("Mac") != -1;
	t.Android = /Android/.test(agent);
	t.IOS = t.WebKit && /(iPad|iPhone|iPod)/.test(agent);
	t.ChromeIOS = t.IOS && /(Chrome|CriOS)/.test(agent);
	t.Safari = t.WebKit && !/Chrome/.test(agent) && !t.ChromeIOS;
	t.Firefox = /Firefox/.test(agent);
	t.Registry = [];
	t.touchSupport = (('ontouchstart' in window || 'msMaxTouchPoints' in window.navigator) && !t.IE_PRE11);
	t.otherOnLoad = window.onload;
	t.analytics_user = null;
	if (typeof jQuery != "undefined") {
		$(document).ready(function(){t.onDocumentReady();});
	}
	t.loadedImages = [];
	window.onload = function(event) {t.onPageLoad(event);};
	t.otherOnUnload = window.onunload;
	window.onunload = function(event){t.onPageUnload(event);};
	t.otherOnBeforeUnload = window.onbeforeunload;
	window.onbeforeunload = function(event) {var r = t.onBeforeUnload(event); if (r) return r;};
	t.otherOnResize = window.onresize;
	window.onresize = function(event){t.onPageResize(event);t.onPageUpdate(event);};
	if (t.IE11_PLUS) {
		window.addEventListener('pointerup', function(event) {if (event.pointerType == 'touch') t.onTouchEnd(event);});
	} else {
		t.otherOnTouchEnd = window.ontouchend;
		window.ontouchend = function(event){t.onTouchEnd(event);};
	}
	t.addMessageListener(t);
	t.loaded = false;
	t.randomStringValues = [];
	t.loadedCSS = [];
	t.Zindex = 200025;
};
_FUW.UtilitiesEngine.prototype = {
 	/**
 	 * This method is called whenever the browser calls the window.onbeforeunload()
 	 * method.  Any registered objects will have their onBeforeUnload method
 	 * called if that method exists.  This also handles other potential functions
 	 * that may have set windows.onbeforeunload
 	 */
	onBeforeUnload : function(event) {
		var i, r, rv = null;
		try {
			if (this.otherOnBeforeUnload) {
				rv = this.otherOnBeforeUnload(event);
				if (typeof rv === 'string') return rv;
			}
		} catch(e) {
			// IE nonsense (can't use a standalone finally block
		}
		finally {
			for(i=0; i<this.Registry.length; i++) {
				r = this.Registry[i];
				if (r.onBeforeUnload) {
					try {
						rv = r.onBeforeUnload(event);
						if (typeof rv === 'string') return rv;
					} catch(e) {
						// Don't let failures impact others
					}
				}
			}
		}
		return rv;
	},
 	/**
 	 * This method is called whenever the browser calls the window.onunload()
 	 * method.  Any registered objects will have their onPageUnload method
 	 * called if that method exists.  This also handles other potential functions
 	 * that may have set windows.onunload
 	 */
	onPageUnload : function(event) {
		var i,r;
		try {
			if (this.otherOnUnload) this.otherOnUnload(event);
		}
		catch(e) {
			// IE nonsense (can't use a standalone finally block
		}
		finally {
			for(i=0; i<this.Registry.length; i++) {
				r = this.Registry[i];
				if (r.onPageUnload) {
					try {r.onPageUnload(event);}
					catch(e) {
						// Don't let failures impact others
					}
				}
			}
		}
		this.consoleLog('Page About to be Unloaded');
	},
	/**
	 * This method is called whenever the browser has finished loading the page and
	 * calls the window.onload() method.  Any registered objects that have an onPageLoad
	 * method will have that method called.  This also handles other potential functions
	 * that may have set windows.onload.
	 */
	onPageLoad : function(event) {
		var t = this, i,r;

		// Don't let others cause crash
		try {
			if (t.otherOnLoad) t.otherOnLoad(event);
		}
		catch(e) {
			// More IE nonsense (can't use a standalone finally block)
		}
		finally {
			for(i=0; i<t.Registry.length; i++) {
				r = t.Registry[i];
				if (r.onPageLoad) {
					try {r.onPageLoad(event);}
					catch(e) {
						// Don't let failures impact others
					}
				}
			}
			t.loaded = true;
		}
	},
	/**
	 * This method is called if jQuery is loaded and the DOM is loaded and ready.
	 * Any registered objects that have an onDocumentReady method will have that
	 * method called.  Since we might not have jQuery loaded, procedures will need
	 * to handle both onDocumentReady and onPageLoad and deal with the potential
	 * of having both called or just onPageLoad.
	 */
	onDocumentReady : function(event) {
		var i,r;
		for(i=0; i<this.Registry.length; i++) {
			r = this.Registry[i];
			if (r.onDocumentReady) {
				try {r.onDocumentReady(event);}
				catch(e) {
					// Don't let failures impact others
				}
			}
		}
	},
	/**
	 * This method is called whenever the browser has resized the page and calls the
	 * window.onresize() method.  Any registered objects that have an onPageResize
	 * method will have that method called.  This also handles other potential functions
	 * that may have set windows.onresize.
	 */
	onPageResize : function(event) {
		var t = this, i,r,
			Registry = t.Registry;

		// Don't let others cause crash
		try {if (t.otherOnResize) t.otherOnResize(event);}
		catch(e) { /* More IE nonsense (can't use a standalone finally block) */ }
		finally {
			for(i=0; i < Registry.length; i++) {
				r = Registry[i];
				if (r.onPageResize) {
					try {r.onPageResize(event);}
					catch(e) { /* Don't let failures impact others */}
				}
			}
		}
	},
	onTouchEnd : function(event) {
		var i,r;
		// Don't let others cause crash
		try {
			if (this.otherOnTouchEnd) this.otherOnTouchEnd();
		}
		catch(e) {
			// More IE nonsense (can't use a standalone finally block)
		}
		finally {
			for(i=0; i<this.Registry.length; i++) {
				r = this.Registry[i];
				if (r.onTouchEnd) {
					try {r.onTouchEnd(event);}
					catch(e) {
						// Don't let failures impact others
					}
				}
			}
		}
	},
	/**
	 * This method is called whenever an action has happened that should inform
	 * all entities that cache page content in the browser itself.  An example
	 * is the photo album functionality which caches ajax generated entries.
	 */
	flushBrowserCache : function() {
		var i,r;
		for(i=0; i<this.Registry.length; i++) {
			r = this.Registry[i];
			if (r.flushBrowserCache) {
				try {r.flushBrowserCache();}
				catch(e) {
					// Don't let failures impact others
				}
			}
		}
	},
	sendMouseEvent : function(target, eventName) {
		var event;
		if (!target) return false;
		if (!this.IE11_PLUS && target[eventName]) {
			target[eventName]();
			return true;
		} else {
			if (document.createEvent) {
				event = document.createEvent('MouseEvents');
				event.initMouseEvent(eventName, true, true, window, 0,0,0,0,0,false,false,false,false,0,null);
				target.dispatchEvent(event);
				return true;
			}
			return false;
		}
	},
	/**
	 * Send a mouse type event named eventName to an element id'd by the elementID
	 * value.  Is useful in capturing an event in another place or in elements
	 * encompassing a form element and directing that event to the form element.
	 *
	 * @param elementID
	 * @param eventName
	 */
	sendEventTo : function(elementID, eventName) {
		var t = this,
			element = t.getElementById(elementID);

		t.sendMouseEvent(element, eventName);
	},
	/**
	 * Use this method to register an object to be called on load, unload, and page update
	 * It actually just calls register() and you should use register() as the name is more
	 * meaningful.
	 * @param obj
	 */
	onload : function(obj) {this.register(obj);},
	/**
	 * Use this method to register an object to be called on load, unload, and page update.
	 * It is identical to onload() but the name is more meaningful
	 * @param obj
	 */
	register : function(obj) {
		var t = this;
		t.Registry.push(obj);
		if (t.loaded) {
			if (obj.onDocumentReady) obj.onDocumentReady();
			if (obj.onPageLoad) obj.onPageLoad();
		}
	},
	/**
	 * Use this method to unregister an object. The object will no longer be called
	 * on load, unload, etc.
	 * @param obj
	 */
	unregister : function(obj) {
		var t = this, i,
			Registry = t.Registry;

		for(i=0; i < Registry.length; i++) {
			if (Registry[i] === obj) Registry.splice(i, 1);
		}
	},
	/**
	 * This method can be called if the page has been altered and you want to inform
	 * registered objects of that event.  Any registered objects that have an onPageUpdate
	 * method will be invoked.  This does not correspond with any browser generated
	 * event.
	 */
	onPageUpdate : function() {
		var i,r;
		for(i=0; i<this.Registry.length; i++) {
			r = this.Registry[i];
			if (r.onPageUpdate)
				r.onPageUpdate();
		}
	},
	onPageReload : function(xdomAjax) {
		var rv = true, i, r;
		for(i=0; i<this.Registry.length; i++) {
			r = this.Registry[i];
			if (r.onPageReload && !r.onPageReload(xdomAjax))
				rv = false;
		}
		return rv;
	},
	eventCancel : function (e) {
       if (!e) {
         if (window.event) e = window.event;
         else return;
       }
       if (e.cancelBubble != null) e.cancelBubble = true;
       if (e.stopPropagation) e.stopPropagation();
       if (e.preventDefault) e.preventDefault();
       if (window.event) e.returnValue = false;
       if (e.cancel != null) e.cancel = true;
    },
    noSubmit : function(e) {
    	if (e === true) return true;
    	this.eventCancel(e);
    	return false;
    },
    scrollTriggeredDropdown: function(id, triggerLow, triggerHigh, speed) {
    	id = '#'+id;
    	if (!speed) speed = 1000;
    	$(document).ready(function() {
    		$(id).hide();
    		$(window).scroll(function(){
    			var top = $(window).scrollTop();
    			_FUW.U.consoleLog('top:' + top + '; Low:'+triggerLow+'; High:'+triggerHigh);
    			if (top >= triggerHigh) $(id).fadeIn(speed);
    			if (top <= triggerLow) $(id).fadeOut(speed);
    		});
    	});
    },
	/**
	 * Handle common and safe message requests such as obtaining the size of the page.
	 * These are typically things needed by a page inquiring an iframe about the body
	 * size so iframe size can be adjusted.
	 *
	 * @param event
	 */
	onmessage : function(event) {
		var t = this, e=null, pos, a, s = '0,0';
		// Not checking domain so don't pass anything back of value
		a = event.data.split(':');
		switch (a[0]) {
		case 'getbodysize':
			if (a[1]) e = t.getElementById(a[1]);
			if (!e) e = document.getElementsByTagName('body')[0];
			if (e) {
				pos = t.getAbsPosition(e);
				s = pos.mWidth + ',' + pos.mHeight;
			}
			// If an ID is passed in, send that as part of the return message
			if (a[2]) s += ':' + a[2];
			event.source.postMessage('bodysize:' + s, event.origin);
			break;
		default:
			// Do nothing
		}
	},
	addMessageListener : function(listener) {
		var f = listener, w = window;
		if (typeof listener == 'object') f = function(event) {
			listener.onmessage(event);
		};
		if (w.addEventListener) w.addEventListener('message', f, false);
		else if (w.attachEvent) w.attachEvent('onmessage', f);
	},
	sendMessage : function(contentWindow, message, targetOrigin) {
		var v;
		if (v = contentWindow.contentWindow) contentWindow = v;
		if (contentWindow.postMessage) {
			contentWindow.postMessage(message, targetOrigin ? targetOrigin : '*');
			return true;
		}
		return false;
	},
	zerofill : function (num, len) {
		return (Array(len).join("0") + num).slice(-len);
	},
	getInt : function(value) {
		if (typeof value == 'string') value = parseInt(value);
		return value;
	},
	/**
	 * Proportionally compute the proportionally scaled dimensions of an object
	 * given a maximum height and width.
	 */
	scaleObject : function(width, height, maxWidth, maxHeight) {
		var t = this, ratio, newWidth, newHeight, scaleWidth, scaleHeight;

		width = t.getInt(width);
		height  = t.getInt(height);
		maxHeight = t.getInt(maxHeight);
		maxWidth = t.getInt(maxWidth);
		ratio = width / height;
		newWidth = maxHeight * ratio;
		newHeight = maxWidth / ratio;
		if (newWidth < maxWidth) {
			/* Typical portrait */
			scaleWidth = Math.round(newWidth);
			scaleHeight = Math.round(newWidth/ratio);
		} else {
			/* Typical landscape */
			scaleWidth = Math.round(newHeight*ratio);
			scaleHeight = Math.round(newHeight);
		}
		return {width: scaleWidth, height: scaleHeight};
	},
	isFlashEnabled : function() {
		var fo,
			hasFlash = false;

		try {
			fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
			if (fo) hasFlash = true;
		} catch(e) {
			if (navigator.mimeTypes['application/x-shockwave-flash'] != undefined) hasFlash = true;
		}
		return hasFlash;
	},
	doResizeIframe : function(t, iframe, body) {
		var h, w;
		h = t.IE ? body.offsetHeight : body.scrollHeight;
		w = t.IE ? body.offsetWidth : body.scrollWidth;
		if (h && w) {
			iframe.style.width = w + 30 + "px";
			iframe.style.height = h + 30 + "px";
		}
	},
	resizeIframe : function(id, iframe) {
		var t = this, body, frame;
		// IE has a bizzarre setup where the iframe element isn't really the iframe jeeze louise.
		frame = t.IE ? window.frames[id] : iframe;
		body = frame.contentDocument ? frame.contentDocument.body :frame.document.body;
		t.doResizeIframe(t, iframe, body);
		// interval = window.setInterval(function(){t.doResizeIframe(t, iframe, body);}, 200);
	},
	toggleDisplayClass : function(id, linkid, disableSibs, ClassBase) {
		var t = this, cursor, parent, e,
			element = t.getElementById(id),
			link = t.getElementById(linkid),
			classOff = ClassBase + 'Off',
			classOn = ClassBase + 'On';

		if (element) {
			if (t.hasClass(element, classOff)) {
				cursor = 'ns-resize';
				t.replaceClass(element, classOff, classOn);
			} else {
				cursor = 'ns-resize';
				t.replaceClass(element, classOn, classOff);
			}
			if (link) link.style.cursor = cursor;
			if (disableSibs) {
				parent = element.parentNode;
				for(e = parent.firstChild; e; e = e.nextSibling) {
					if (e == element) continue;
					t.replaceClass(e, classOn, classOff);
				}
			}
		}
	},
	toggleDisplay : function(id, linkid, disableSibs) {
		var t = this, cursor, parent, e,
			element = t.getElementById(id),
			display = t.getStyle(element, 'display'),
			link = t.getElementById(linkid);
		if (element) {
			if (display == 'none') {
				cursor = 'ns-resize';
				display = 'block';
			} else {
				cursor = 'ns-resize';
				display = 'none';
			}
			element.style.display = display;
			if (link) link.style.cursor = cursor;
			if (disableSibs) {
				parent = element.parentNode;
				for(e = parent.firstChild; e; e = e.nextSibling) {
					if (e == element) continue;
					e.style.display = 'none';
				}
			}
		}
	},
	getStyle : function(element, style) {
		if (!element) return null;
		if (document.defaultView) {
			// Remove camelcase
			style = style.replace(/[A-Z]/g, function(a){
				return '-' + a;
			});
			try {
				return document.defaultView.getComputedStyle(element, null).getPropertyValue(style);
			} catch (ex) {
				// Old safari might fail
				return null;
			}
		}
		// Camelcase it, if needed
		style = style.replace(/-(\D)/g, function(a, b){
			return b.toUpperCase();
		});

		if (style == 'float')
			style = this.IE ? 'styleFloat' : 'cssFloat';

		// IE & Opera
		if (element.currentStyle) return element.currentStyle[style];
		return element.style[style];
	},
	replaceClass : function(e, oldClass, newClass) {
		if (!e) return '';
		this.removeClass(e, oldClass);
		this.addClass(e, newClass);
		return e.className;
	},
	addClass : function(e, className) {
		if (!e) return '';
		if (this.hasClass(e, className)) return e.className;
		return e.className = e.className ? e.className + ' ' + className : className;
	},
	removeClass : function(e, className) {
		var t = this, re = new RegExp("(^|\\s+)" + className + "(\\s+|$)", "g"), s;
		if (!e) return '';
		if (t.hasClass(e, className)) {
			s = e.className.replace(re, ' ');
			s = s != ' ' ? s.replace(/^\s*|\s*$/g, '') : '';
			e.className = s;

			// Empty class attr
			if (!s) {
				e.removeAttribute('class');
				e.removeAttribute('className');
			}
		}
		return e.className;
	},
	hasClass : function(e, className) {
		if (!e) return false;
		return (' ' + e.className + ' ').indexOf(' ' + className + ' ') !== -1;
	},
	/**
	 * This will return the first child node found that has a class name matching
	 * the className parameter.  When using this you should be sure that you do not
	 * have multiple child elements with this class name or the results will be
	 * unpredictable. Null is returned if no element is found with that class name
	 *
	 * @param e
	 * @param className
	 */
	getChildWithClass : function(e, className) {
		var t = this,
			child, rv;

		for(child = e.firstChild; child; child = child.nextSibling) {
			if (child.nodeType != 1) continue;
			if (t.hasClass(child, className)) return child;
			if (rv = t.getChildWithClass(child, className)) return rv;
		}
		return null;
	},
	getParentWithClass : function(e, className) {
		var t = this,
			parent;
		for (parent = e.parentNode; parent; parent = parent.parentNode) {
			if (parent.nodeType != 1) return null;
			if (t.hasClass(parent, className)) return parent;
		}
		return null;
	},
	getStylePixelValue : function(element, style) {
		var v, px;
		if (!element) return 0;
		v = this.getStyle(element, style);
		px = v.indexOf('px');
		if (px == -1) return 0;
		return parseInt(v).NaN0();
	},
	isContainingBlock : function(element) {
		if (!element) return false;
		var pos = this.getStyle(element, "position");
		return pos != "static";
	},
	/**
	 * This is the same code used in Adjust to get window/scroll dimensions.  Sometime
	 * when I have more time this and getWindowPosition need to be analyzed to see
	 * which is the right way to do things.  It is used in the SizeMatcher below
	 */
	getWindowDimensions : function() {
		var IE = this.IE, st, wh, sl, ww;
		return {
			wh : wh = IE ? document.documentElement.clientHeight : window.innerHeight,
			ww : ww = IE ? document.documentElement.clientWidth : window.innerWidth,
			st : st = IE ? document.documentElement.scrollTop : window.pageYOffset,
			sl : sl = IE ? document.documentElement.scrollLeft : window.pageXOffset,
			sb : st + wh,
			sr : sl + ww
		};
	},
	getWindowPosition : function() {
		var w=0, h=0, x;
		if (this.IE678 && document.compatMode=='CSS1Compat' &&
			    document.documentElement &&
			    document.documentElement.offsetWidth ) {
			w = document.documentElement.offsetWidth;
			h = document.documentElement.offsetHeight;
		} else if (document.body && document.body.offsetWidth) {
			w = document.body.offsetWidth;
			h = document.body.offsetHeight;
			// It seems as if this is the correct value when the page is less than the window height
			if (window.innerWidth && window.innerHeight) {
				if ((x = window.innerWidth) > w) w = x;
				if ((x = window.innerHeight) > h) h = x;
			}
		}
		else if (window.innerWidth && window.innerHeight) {
			w = window.innerWidth;
			h = window.innerHeight;
		} else if (typeof document.documentElement != 'undefined' &&
				   typeof document.documentElement.clientWidth != 'undefined' &&
				   document.documentElement.clientWidth != 0) {
			w = document.documentElement.clientWidth;
			h = document.documentElement.clientHeight;
		} else {
			x = document.getElementsByTagName('body')[0];
			w = x.clientWidth; h = x.clientHeight;
		}
		return {left:0,top:0,right:w,bottom:h};
	},
	getAbsPosition : function(element, className, pageAbs){
		if (!element) return {};
		var t = this,
			left = 0,
			top = 0,
			w, h,
			e = element, // boxModel = !this.IE || document.compatMode == 'CSS1Compat',
			pl = t.getStylePixelValue(element, 'padding-left'),
			pr = t.getStylePixelValue(element, 'padding-right'),
			pt = t.getStylePixelValue(element, 'padding-top'),
			pb = t.getStylePixelValue(element, 'padding-bottom'),
			bl = t.getStylePixelValue(element, 'border-left-width'),
			bt = t.getStylePixelValue(element, 'border-top-width'),
			br = t.getStylePixelValue(element, 'border-right-width'),
			bb = t.getStylePixelValue(element, 'border-bottom-width'),
			ml = t.getStylePixelValue(element, 'margin-left'),
			mr = t.getStylePixelValue(element, 'margin-right'),
			mt = t.getStylePixelValue(element, 'margin-top'),
			mb = t.getStylePixelValue(element, 'margin-bottom');

		/* Not doing this...
		if (this.IE && false) {
			e = e.getBoundingClientRect();
			var bodyElement = boxModel ? document.documentElement : document.body;
			// Skipping this for now
			// x = t.getStyle(t.select('html')[0], 'borderWidth'); // Remove border
			// x = (x == 'medium' || boxModel && !t.isIE6) && 2 || x;
			// e.top += t.win.self != t.win.top ? 2 : 0; // IE adds some strange extra cord if used in a frameset
			left = e.left + bodyElement.scrollLeft; // - x;
			top = e.top + bodyElement.scrollTop; // - x;
			element.absPosition = {
				left   : left,
				top    : top,
				right  : parseInt(e.offsetWidth) + left + pl + pr,
				bottom : parseInt(e.offsetHeight) + top + pt + pb
			};
			return element.absPosition;
		}
		*/

		while (e){
			left += (e.offsetLeft || 0) + this.getStylePixelValue(e, 'border-left-width');
			top += (e.offsetTop || 0) + this.getStylePixelValue(e, 'border-top-width');
			if (!e.offsetParent) {
				// this is the body element - account for margin and padding
				left += t.getStylePixelValue(e, 'padding-left') + t.getStylePixelValue(e, 'margin-left');
				top += t.getStylePixelValue(e, 'padding-top') + t.getStylePixelValue(e, 'margin-top');
			}
			e = e.offsetParent;
			if (!pageAbs && this.isContainingBlock(e)) {
				if (this.IE8 || this.Opera) break;
				// It seems IE & Opera count border width on this element and the others don't.
				left += this.getStylePixelValue(e, 'border-left-width');
				top += this.getStylePixelValue(e, 'border-top-width');
				break;
			}
		}
		w = parseInt(element.offsetWidth);
		h = parseInt(element.offsetHeight);
		element.absPosition = {
			left   : left,
			top    : top,
			right  : w + left, /* + pl + pr, */
			bottom : h + top, /* + pt + pb; */
			width  : w,
			height : h,
			paddingTop : pt,
			paddingRight : pr,
			paddingBottom: pb,
			paddingLeft: pl,
			borderTop: bt,
			borderRight: br,
			borderBottom: bb,
			borderLeft: bl,
			cssWidth: w - pl - pr,
			cssHeight: h - pt - pb,
			bWidth: w + bl + br,
			bHeight: h + bt + bb,
			mWidth: w + bl + br + ml + mr,
			mHeight: h + bt + bb + mt + mb
		};
		return element.absPosition;
	},
	ResizeAdjust : function(e) {
		if (e.ResizeAdjuster) return;
		e.ResizeAdjuster = new _FUW.ResizeAdjustor(e);
	},
	/**
	 * Adjusts a popup window to make sure it isn't off the bottom of the browser
	 * view area.  This has been fixed a number of times and I think it is right
	 * now.  Essentially we want to move the popup so that it's bottom/right is
	 * inside the viewable area of the screen, then adjust so that we didn't push
	 * the top/left off the viewable area.  If the popup is completely inside the
	 * view area, no adjustment is made
	 *
	 * The top and left parameters must be the offsets within the popup's positioning
	 * block (not the ABS position on the screen).  Set top=false if you don't know
	 * this and need to have Adjust look it up.
	 */
	Adjust : function(e, top, left) {
		var t = this, pos, win, off, v;

		// If caller didn't pass top/left, look it up
		if (top === false) {
			pos = t.getAbsPosition(e, false, false);
			top = pos.top;
			left = pos.left;
		}
		pos = t.getAbsPosition(e, null, true);

		// Obtain the left/right/top/bottom of the scroll area of the screen
		win = t.getWindowDimensions();
		$(window).height();
		// First check if  popup top is off the top of the scroll area and move down
		if (pos.top < win.st) {
			// Get an offset to make the top of the popup just inside the top of the scroll area
			off = win.st - pos.top + 20;
			e.style.top = (top + off) + 'px';
			pos.top += off;
			top += off;
			pos.bottom += off;
		}
		// If popup bottom is off the bottom of the scroll area...
		if (pos.bottom > win.sb) {

			// Get an offset to make bottom of popup just inside the bottom of the scroll area
			off = win.sb - pos.bottom - 20;

			// Adjust if we would push the top off the top of the scroll area
			if ((v = pos.top + off) < win.st) off += (win.st - v);

			// Set the popup's new top
			e.style.top = (top + off) + 'px';
		}

		// If popup right side is off the right side of the scroll area of the screen...
		if (pos.right > win.sr) {

			// Get an offset to make the right side of popup just inside the right of the scroll area
			off = win.sr - pos.right - 20;

			// Adjust if we would push the left of the popup off the left of the scroll area
			if ((v = pos.left + off) < win.sl) off += (win.sl - v);

			// Set the popup's new left
			e.style.left = (left + off) + 'px';
		}
	},
	/**
	 * Causes the screen to scroll so that the scrollTarget element is positioned
	 * at the top of the scroll area.  The offset parameter is added so the element
	 * is offset pixels from the top of the scroll area.  This is messy and only
	 * called from two locations in drag.js and xdom.js.  Both use the native
	 * scrollIntoView method instead if that is available.
	 *
	 * @param scrollTarget
	 * @param offset
	 */
	scrollToTarget : function(scrollTarget, offset) {
		var t = this, beforeTop, afterTop,
			pos =  t.getAbsPosition(scrollTarget, null, true),
			scrollElement = scrollTarget.parentNode,
			newTop = pos.top - (offset ? offset : 0);
		// Find innermost scrolled container
		while(scrollElement)  {
			if (scrollElement.clientHeight < scrollElement.scrollHeight && scrollElement.clientHeight >0) {
				beforeTop = $(scrollElement).scrollTop();
				$(scrollElement).scrollTop(newTop);
				afterTop = $(scrollElement).scrollTop();
				if (afterTop == newTop || beforeTop != afterTop) break;
			}
			scrollElement = scrollElement.parentNode;
			if (!scrollElement) $(document).scrollTop(newTop);
		}
	},
	/**
	 * Special purpose method to "open" the expandable login form by
	 * enabling all the rows following the row this element is placed.
	 */
	openLoginForm : function(e, requireHTTPS) {
		var t = this, row, form = e.form;
		if (requireHTTPS && window.location.protocol !== 'https:') {
			window.location = 'https://' + window.location.hostname + window.location.pathname + window.location.hash;
		}
		if (!e || e.formOpened) return;
		if (t.openElement) t.closeLoginForm(t.openElement);
		t.openElement = e;
		e.formOpened = true;
		e.savedValue = e.value;
		e.value='';
		e.style.color='#000';
		for (row = e.parentNode.parentNode; row; row = row.nextSibling) {
			if (row.nodeType != 1) continue;
			row.style.display = "block";
		}
		form.style.border = "2px solid";
		form.style.padding = "5px";

		/**
		 * Yet another convoluted workaround for this piece of junk!  In IE6/7 the
		 * submit click does nothing.  This is probably related to the fact that
		 * the buttons and some other parts of the form were in table rows that were
		 * hidden (display:none).  I can figure no other way to make this damn thing
		 * work.  NOTE: the button name must be "submit_button" or thise code needs
		 * to change to reflect another name.
		 */
		if (_FUW.U.IE67) {
			form.submit_button.onclick = function(e){
				if (form.SecureLogin) form.SecureLogin.submit();
				else form.submit();
			};
		}
	},
	/**
	 * Special purpose method to "close" an expandable login form "opened"
	 * by openLoginForm.  It disables all but the first row.
	 */
	closeLoginForm : function(e) {
		var t = this, row;
		if (!(e = t.openElement)) return;
		t.openElement = null;
		e.formOpened = false;
		e.value = e.savedValue;
		e.style.color = '#777';
		for (row = e.parentNode.parentNode.nextSibling; row; row = row.nextSibling) {
			if (row.nodeType != 1) continue;
			row.style.display = "none";
		}
		e.form.style.border = "0px";
		e.form.style.padding = '0px';
	},
	/**
	 * Special purpose method to open/close a popopen container.  This is typically
	 * used for things like Frequently Asked Questions or other things where you
	 * want a link that opens up content below.
	 */
	PopopenContainerClick : function(link, event) {
		var t = this,
			icon = link.firstChild,
			container = link.parentNode.nextSibling,
			state = link.xhtmlToggleState ? true : false;

		link.xhtmlToggleState = !state;
		if (state) {
			// Close up
			t.removeClass(icon, 'iconf-collapse');
			t.addClass(icon, 'iconf-expand');
			container.style.display = 'none';
		} else {
			// Re-open
			t.removeClass(icon, 'iconf-expand');
			t.addClass(icon, 'iconf-collapse');
			container.style.display = '';
		}
		this.onPageUpdate();
		return true;
	},
	setupAnalytics : function(domain, tracker_id, delay) {
		var t = this;
		$(document).ready(function(){
			var gaJsHost = "https://www.";

			$.getScript(gaJsHost + "google-analytics.com/ga.js", function(){
				var pageTracker = null,
					timer=null,
					filetypes = /\.(zip|exe|pdf|doc*|xls*|ppt*|mp3)$/i;

				try {
					pageTracker = window.pageTracker = _gat._getTracker(tracker_id);
					pageTracker._setDomainName(domain);
					// pageTracker._initData(); // This has been deprecated
					pageTracker._trackPageview();
					if (t.analytics_user) pageTracker._setVar(t.analytics_user);
				} catch(err) {}

				/*
				 * Implement a 15 second adjusted bounce event.
				 * Constitutes valid (non-bounce) if user is here this long before
				 * leaving site.
				 */
				if (delay) {
					timer = setInterval(function(){
						clearInterval(timer);
						pageTracker._trackEvent('adj_bounce','read','delay', delay);
					}, delay * 1000);
				}


				$('a').each(function(){
					var href = $(this).attr('href');
					if (!href) return;
					if ((href.match(/^https?\:/i)) && (!href.match(document.domain))){
						$(this).click(function() {
							var extLink = href.replace(/^https?\:\/\//i, '');
							pageTracker._trackEvent('External', 'Click', extLink);
						});
					}
					else if (href.match(/^mailto\:/i)){
						$(this).click(function() {
							var mailLink = href.replace(/^mailto\:/i, '');
							pageTracker._trackEvent('Email', 'Click', mailLink);
						});
					}
					else if (href.match(filetypes)){
						$(this).click(function() {
							var extension = (/[.]/.exec(href)) ? /[^.]+$/.exec(href) : undefined,
								filePath = href.replace(/^https?\:\/\/(www.)mydomain\.com\//i, '');
							pageTracker._trackEvent('Download', 'Click - ' + extension, filePath);
						});
					}
				});
			});
		});
	},
	setupAnalyticsUser : function(user) {
		this.analytics_user = user;
	},
	setupAnalyticsGA : function(domain, tracker_id, delay) {
		var t = this;
		(function(window,document,tag,url,ga_var,element,first_script){
			window['GoogleAnalyticsObject'] = ga_var;
			window[ga_var] = window[ga_var] || function(){
				(window[ga_var].q = window[ga_var].q || []).push(arguments)
			},window[ga_var].l=1*new Date();
			element = document.createElement(tag);
			first_script = document.getElementsByTagName(tag)[0];
			element.async = 1;
			element.src = url;
			first_script.parentNode.insertBefore(element,first_script);
		})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

		if (t.analytics_user) ga('create', tracker_id, 'auto', {userID: t.analytics_user});
		else ga('create', tracker_id, 'auto');
		ga('send', 'pageview');

		$(document).ready(function() {
			var timer=null,
				filetypes = /\.(zip|exe|pdf|doc*|xls*|ppt*|mp3)$/i;

			if (delay) {
				timer = setInterval(function(){
					clearInterval(timer);
					ga('send', 'event', 'adj_bounce','read','delay', delay);
				}, delay * 1000);
			}

			$('a').each(function(){
				var href = $(this).attr('href');
				if (!href) return;
				if ((href.match(/^https?\:/i)) && (!href.match(document.domain))){
					$(this).click(function() {
						var extLink = href.replace(/^https?\:\/\//i, '');
						ga('send', 'event', 'External', 'Click', extLink);
					});
				}
				else if (href.match(/^mailto\:/i)){
					$(this).click(function() {
						var mailLink = href.replace(/^mailto\:/i, '');
						ga('send', 'event', 'Email', 'Click', mailLink);
					});
				}
				else if (href.match(filetypes)){
					$(this).click(function() {
						var extension = (/[.]/.exec(href)) ? /[^.]+$/.exec(href) : undefined,
							filePath = href.replace(/^https?\:\/\/(www.)mydomain\.com\//i, '');
						ga('send', 'event', 'Download', 'Click - ' + extension, filePath);
					});
				}
			});
		});
	},
	setupAnalyticsGT : function(domain, tracker_id, delay) {
		var t = this;

		$(document).ready(function() {
			var timer=null,
				filetypes = /\.(zip|exe|pdf|doc*|xls*|ppt*|mp3)$/i;

			if (delay) {
				timer = setInterval(function(){
					clearInterval(timer);
					t.sendAnalyticsEvent('adj_bounce','read','delay', delay);
				}, delay * 1000);
			}

			$('a').each(function(){
				var href = $(this).attr('href');
				if (!href) return;
				if ((href.match(/^https?\:/i)) && (!href.match(document.domain))){
					$(this).click(function() {
						var extLink = href.replace(/^https?\:\/\//i, '');
						t.sendAnalyticsEvent('External', 'Click', extLink);
					});
				}
				else if (href.match(/^mailto\:/i)){
					$(this).click(function() {
						var mailLink = href.replace(/^mailto\:/i, '');
						t.sendAnalyticsEvent('Email', 'Click', mailLink);
					});
				}
				else if (href.match(filetypes)){
					$(this).click(function() {
						var extension = (/[.]/.exec(href)) ? /[^.]+$/.exec(href) : undefined,
							filePath = href.replace(/^https?\:\/\/(www.)mydomain\.com\//i, '');
						t.sendAnalyticsEvent('Download', 'Click - ' + extension, filePath);
					});
				}
			});
		});
	},
	sendAnalyticsEvent : function(category, event, data) {
		if ('gtag' in window) {
			gtag('event', event, {'event_category':category,'event_label':data});
			return;
		}
		if ('ga' in window) {
			ga('send', 'event', category, event, data);
			return;
		}
		if ('pageTracker' in window) {
			pageTracker._trackEvent(category, event, data);
		}
	},
	LoadImage : function(src) {
		var e = document.createElement('img');
		e.setAttribute('src', src);
		this.loadedImages.push(e);
	},
	/**
	 * Yes, doing the hard way because yet again IE7 works stupidly.  We get
	 * an 'unknow' runtime error when you try to to something simple like set
	 * innerHTML
	 */
	setElementText : function(e, text, append) {
		if (!e || !e.nodeType) return;
		if (!append) while (e.firstChild) e.removeChild(e.firstChild);
		e.appendChild(document.createTextNode(text));
	},
	/**
	 * Utility to replace all content in the specified parent element with the
	 * single node passed in.
	 *
	 * @param e
	 * @param node
	 */
	replaceElementContent : function(e, node) {
		while (e.firstChild) e.removeChild(e.firstChild);
		if (node) e.appendChild(node);
	},
	/**
	 * The setSelector method sets a select control to one of its values.  If the
	 * value parameter is not one of the select's options the first entry will be
	 * selected.
	 *
	 * @param e
	 * @param value
	 */
	setSelector : function(e, value) {
		if (!e) return;
		var first = e.firstChild,
			next = first,
			found = false;
		for (;next; next = next.nextSibling) {
			if (!/^(option)$/i.test(next.tagName) || next.value != value) continue;
			found = true;
			break;
		}
		e.value = found ? value : first.value;
	},
	addStyleRules : function(styleString) {
		var element = document.createElement('style');
		element.type = 'text/css';
		element.innerHTML = "\n" + styleString + "\n";
		document.getElementsByTagName('head')[0].appendChild(element);
	},
	/**
	 * The loadCSS method dynamically loads a css file if that file has not yet
	 * been loaded.  This is initially being used to load the downloadable icon
	 * fonts for management on sites that were completed before this was available
	 *
	 * @param url
	 * @param testString
	 */
    loadCSS : function(url, testString) {
    	var t = this, i, link,
    		styleSheets = document.styleSheets;

    	if (!testString) testString = url;
    	if (t.loadedCSS[testString]) return;
    	t.loadedCSS[testString] = true;
    	for(i=0; i < styleSheets.length; i++) {
    		if (styleSheets[i].href.indexOf(testString) != -1) return;
    	}
    	if (document.createStyleSheet) {
    		document.createStyleSheet(url);
    	} else {
    		link = document.createElement('link');
    		link.rel = 'stylesheet';
			link.type = 'text/css';
    		link.href = url;
    		document.getElementsByTagName('head')[0].appendChild(link);
    	}
    },
    loadIconf : function() {
    	this.loadCSS('http:fredsusedwebsites.com/icons/iconf.css', 'fredsusedwebsites.com/icons/iconf.css');
    },
	/**
	 * The loadJavascript method dynamically loads javascript or a javascript file.
	 * When loading javascript, this initiates the process but does not guarantee
	 * that the file is loaded.  If you need to know when the file has loaded you
	 * should add a timer with callback to test for file's presence.
	 *
	 * @param src
	 * @param path
	 * @return void
	 */
	loadJavascript : function (src, path) {
		var e = document.createElement('script');
		e.setAttribute('type', 'text/javascript');
		e.setAttribute('language', 'javascript');
		if (path) e.setAttribute('src', path);
		else {
			e.text = src;
			e.setAttribute('defer', 'defer');
		}
		document.getElementsByTagName('head')[0].appendChild(e);
	},
	/**
	 * Parse a JSON string and return the object.  We attempt to do the safe thing
	 * and use jQuery parseJSON, but if it isn't loaded we default to the eval method.
	 * This should normally be OK since we are always getting this data from our
	 * website. Null is returned if there is any kind of error parsing the string.
	 *
	 * @param json
	 * @returns object
	 */
	parseJSON : function(json) {
		try {
			// Attempt to use native JSON parser first
			try {return window.JSON.parse(json);} catch(e){}
			// That didn't work see if we can use jQuery
			if (typeof jQuery != 'undefined') return jQuery.parseJSON(json);
			return eval('(' + json + ')');
		} catch(e) {}
		return null;
	},
	getElementById : function(id) {
		var v;
		if ((typeof jQuery != 'undefined') && (v = $('#' + id).get(0))) return v;
		return document.getElementById(id);
	},
	getFirstXmlElementWithTagName : function(element, tagName) {
		var e, list = element.getElementsByTagName(tagName);
		if (list.length < 1) return null;
		e = list[0];
		return new XMLElementNode(e);
	},
	GetData : function(e) {
		var s,i;
		if (!e.firstChild) return "";
		for (i=0,s=''; i<e.childNodes.length; i++) s += e.childNodes[i].data;
		return s;
	},
	ajaxLog : function(s, doConsole) {
		var X = _FUW.X;
		if (X) X.ajaxLog(s, true);
		if (doConsole) this.consoleLog(s);
	},
	consoleLog : function(a0,a1,a2,a3,a4) {
		if (typeof console !== 'undefined' && console.log) {
			switch(arguments.length){
				case 0: return;
				case 1: console.log(a0);break;
				case 2: console.log(a0,a1);break;
				case 3: console.log(a0,a1,a2); break;
				case 4: console.log(a0,a1,a2,a3);break;
				case 5:
				default: console.log(a0,a1,a2,a3,a4);
			}
		}
	},
	consoleTrace: function(msg, doAjax) {
		var e = new Error('x'),
			s = msg, curr,
            FUNC  = 'function', ANON = "{anonymous}",
            fnRE  = /function\s*([\w\-$]+)?\s*\(/i,
            stack = [],j=0,
            fn,args,i;

		if (typeof console !== 'undefined') {
			if (console.trace) {
				if (console.log) console.log(msg);
				console.trace();
			}
			else if (console.log) {
				console.log(msg + ' ', e.stack);
			}
			if (doAjax) {
				if (e.stack) s += ' ' + e.stack;
				else try {
					curr  = arguments.callee.caller;
					while (curr) {
			            fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;
			            args = stack.slice.call(curr.arguments);
			            i = args.length;
			            while (i--) {
			                switch (typeof args[i]) {
			                    case 'string'  : args[i] = '"'+args[i].replace(/"/g,'\\"')+'"'; break;
			                    case 'function': args[i] = FUNC; break;
			                }
			            }
			            stack[j++] = fn + '(' + args.join() + ')';
			            curr = curr.caller;
			        }
			        s += "\n" + stack.join("\n");
				} catch(e) {
					s += 'No stack trace';
				}
				this.ajaxLog(s);
			}
		}
	},
	consoleError : function(a0,a1,a2,a3,a4) {
		if (typeof console !== 'undefined' && console.error) {
			switch(arguments.length){
				case 0: return;
				case 1: console.error(a0);break;
				case 2: console.error(a0,a1);break;
				case 3: console.error(a0,a1,a2); break;
				case 4: console.error(a0,a1,a2,a3);break;
				case 5:
				default: console.error(a0,a1,a2,a3,a4);
			}
		}
	},
	emptyFieldClick : function(e, text) {
		if (e.value == text) e.value = '';
		this.removeClass(e, 'grayText');
	},
	emptyFieldBlur : function(e, text) {
		if (e.value != '') return;
		e.value = text;
		this.addClass(e, 'grayText');
	},
	runOnLoad : function(func) {
		this.onload({
			func : func,
			onPageLoad : function() {
				this.func();
			}
		});
	},
	/**
	 * Popup a larger version of an icon image.  We are borrowing some of the Photo
	 * Album style classes here and these need to be in the site's style sheet. The
	 * larger image is Adjusted to be sure it is in the visible scroll pane and you
	 * have the option to gray out the website (modal).
	 *
	 * @param isModal
	 * @param src
	 * @param w
	 * @param h
	 */
	openPopupImage : function(isModal, src, w, h) {
		var t=this,
			U = _FUW.U,
			block, popup, img, oimg, p;

		t.popup = popup = xdom.getElementById('PhotoAlbumPopupContainer');
		oimg = t.getElementById('PhotoAlbumPopupImage');
		p = oimg.parentNode;
		if (!popup || !oimg) return;

		/* This incredibly stupid browser will scrunch the image even though width
		 * is set to fit the cell surrounding it even though that cell might not
		 * have a width set.
		 */
		if (t.IE678) {
			p.style.width = w + 'px';
			p.style.height = h + 'px';
		}

		/* Rebuild the image element because just changing the src variable
		 * shows the last image while new is loading (at least on Firefox). This
		 * would give the impresson of having clicked the wrong popup link
		 */
		oimg.removeAttribute('id');
		img = new Image();
		img.setAttribute('src', src);
		if (w) img.setAttribute('width', w);
		if (h) img.setAttribute('height', h);
		img.setAttribute('id', 'PhotoAlbumPopupImage');
		t.addClass(img, 'PhotoAlbumPopupImage');
		img.setAttribute('onclick', '_FUW.U.closePopupImage()');
		img.style.cursor = 'pointer';
		p.replaceChild(img, oimg);

		if (isModal) {
			t.popupBlock = block = t.getElementById('PhotoAlbumPopupBlocker');
			block.style.display = "block";
			block.style.zIndex = U.Zindex++;
		}
		popup.style.display = 'block';
		popup.style.zIndex = U.Zindex++;
		t.Adjust(popup, false);
	},
	closePopupImage : function() {
		var t = this;
		if (t.popupBlock) {
			t.popupBlock.style.display = 'none';
			t.popupBlock.style.zIndex = -1;
		}
		if (t.popup) {
			t.popup.style.display = 'none';
			t.popup.style.zIndex = -1;
		}
	},
	openModalIFrame : function(id, src, width, height, isModal, event) {
		var t=this, popup, e, iframe, ext, pos, b,
			X = _FUW.X,
			wfit = width == 'fit',
			hfit = height == 'fit',
			pageTracker = window.pageTracker,
			link = src.replace(/^https?\:\/\//i, ''),
			win = $(window);

		if (pageTracker) {
			ext = (src.match(/^https?\:/i)) && (!src.match(document.domain));
			pageTracker._trackEvent(ext ? 'External' : 'Internal', 'Modal IFrame', link);
		}

		if (wfit) width =  Math.min(1200, win.width()*0.9);
		if (hfit) height = win.height()*0.9;

		// IE67 screw up horribly with this - just do a popup window
		if (t.IE67) {
			X.openLinkAsPopupWindow(src, width, height);
			if (event) t.eventCancel(event);
			return;
		}
		if ((typeof id) == 'object') {
			if (!(popup = t.iframePopup) || !(iframe = t.iframe)) {
				id.appendChild(popup = t.iframePopup = document.createElement('div'));
				t.addClass(popup, 'ModalPopupContainer');
				$(popup).append('<div class="ModalPopupHead"><a href="javascript:_FUW.U.closeModalIFrame()" class="ModalPopupCloseLink"></a><div style="clear:both"></div></div>');
				popup.appendChild(e = document.createElement('div'));
				t.addClass(e, 'ModalPopupBody');
				e.appendChild(t.iframe = iframe = document.createElement('iframe'));
				t.addClass(e, 'ModalPopupIframe');
				iframe.setAttribute('width', width);
				popup.style.display = 'block';
				pos = t.getAbsPosition(popup);
				popup.style.display = '';
				document.body.appendChild(popup);
				$(popup).css({top:pos.top,left:pos.left});
			}
		} else {
			t.iframePopup = popup = xdom.getElementById(id);
			t.iframe = iframe = t.getElementById(id + '_iframe');
			iframe.parentNode;
			if (!popup || !iframe) return;
		}

		if (event) t.eventCancel(event);
		iframe.setAttribute('src', src);
		if (width) iframe.setAttribute('width', width);
		if (height) iframe.setAttribute('height', height);

		if (isModal) {
			b = X.setModalBlocker(t.Zindex++);
			popup.parentNode.insertBefore(b, popup);
		}
		$(popup).css({display:'block',zIndex:t.Zindex++});
		t.Adjust(popup, false);
		win.resize(function(){
			if (wfit) iframe.setAttribute('width', Math.min(1200, win.width()*0.9));
			if (hfit) iframe.setAttribute('height', win.height()*0.9);
			t.Adjust(popup, false);
		});
	},
	closeModalIFrame : function() {
		var t = this, X = _FUW.X, e;
		X.clearModalBlocker();
		if (e = t.iframePopup) {
			e.style.display = 'none';
			e.style.zIndex = -1;
		}
		if (e = t.iframe) {
			e.setAttribute('src', '');
		}
	},
	uniqueString : function(length) {
		var chars = '01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', rv, i, n;
		do {
			rv = '';
			for (i=0; i<length; i++) {
				n = Math.floor(Math.random() * chars.length);
				rv += chars.substring(n, n+1);
			}
		} while(this.randomStringValues[rv]);
		this.randomStringValues[rv] = true;
		return rv;
	}
};
_FUW.U = _FUWutil = Utilities = new _FUW.UtilitiesEngine();
_FUW.PopupManager = function(id, opts) {
	var t = this,
		U = _FUW.U,
		i=0;
	t.objectClass = 'PopupManager';
	t.id = id;
	if (opts) {
		for(i in opts) t[i] = opts[i];
	}
	t.loaded = false;
	t.managers = i = _FUW.PopupManager.managers;
	i[id] = t;
	U.onload(t);
};
_FUW.PopupManager.managers = [];
_FUW.PopupManager.prototype = {
	onPageLoad : function() {
		var t = this,
			U = _FUW.U,
			e, widget, popup;

		if (t.loaded) return;
		t.loaded = true;
		if (!(t.widget = widget = U.getElementById(t.id))) return;
		if (!(t.popup = popup = U.getChildWithClass(widget, 'ModalPopupContainer'))) return;

		// Find the popup image if it exists
		e = U.getChildWithClass(widget, 'PopupContent');
		if (e && /^img$/i.test(e.tagName)) t.popupImg = e;

		if (t.hoverDelay) {
			popup.onmouseover = function(event) {t.mouseover(event);};
			popup.onmouseout = function(event) {t.mouseout(event);};
		}
		if (e = U.getChildWithClass(widget, 'ModalPopupCloseLink')) {
			e.onclick = function(event) {t.closeContent(event);};
		}
		if (e = U.getChildWithClass(widget, 'PopupContent')) {
			e.onclick = function(event) {t.closeContent(event);};
		}
		if (e = U.getChildWithClass(widget, 'PopupTrigger')) {
			e.onclick = function(event) {t.openContent(event);};
			if (t.hoverDelay) {
				e.onmouseover = function(event) {t.mouseover(event);};
				e.onmouseout = function(event) {t.mouseout(event);};
			}
		}
		t.isOpen = false;
	},
	onDocumentReady : function() {
		// this.onPageLoad();
	},
	mouseover : function(event) {
		var t = this,
			hoverDelay = t.hoverDelay,
			timerID = 0;
		t.resetOutTimer();
		if (t.inTimerID) return;
		t.inTimerID = timerID = setInterval(function(){
			t.openContent(event);
			clearInterval(timerID);
			t.inTimerID = 0;
		}, hoverDelay);
	},
	mouseout : function(event) {
		var t = this,
			hoverDelay = t.hoverDelay,
			timerID = 0;
		t.resetInTimer();
		if (t.outTimerID) return;
		t.outTimerID = timerID = setInterval(function(){
			if (t.isOpen) t.closeContent(event);
			clearInterval(timerID);
			t.outTimerID = 0;
		}, hoverDelay);
	},
	resetInTimer : function() {
		var t = this, v;
		if (v = t.inTimerID) {
			clearInterval(v);
			t.inTimerID = 0;
		}
	},
	resetOutTimer : function() {
		var t = this, v;
		if (v = t.outTimerID) {
			clearInterval(v);
			t.outTimerID = 0;
		}
	},
	openContent : function(event) {
		var t = this, b, pos, v = 0, pimg,
			popup = t.popup,
			managers = t.managers,
			U = _FUW.U, X = _FUW.X,
			zb = U.Zindex++,
			z = U.Zindex++;

		$(popup).css({display:'block',zIndex:z,maxWidth:'none'});
		if (pimg = t.popupImg) $(pimg).css({width:'auto'});
		if (!t.popupMoved && !t.popupNoMove) {
			t.popupMoved = true;
			pos = U.getAbsPosition(popup, '', true);
			document.body.appendChild(popup);
			$(popup).css({top:pos.top,left:pos.left});
		}
		if (t.isModal) {
			b = X.setModalBlocker(zb);
			popup.parentNode.insertBefore(b, popup);
		}
		U.Adjust(popup, false);
		$(popup).css({maxWidth:''});
		if (pimg) $(pimg).css({width:''});
		t.resetOutTimer();
		for(v in managers) {
			if (v != t.id) managers[v].closeContent();
		}
		t.isOpen = true;
	},
	closeContent : function() {
		var t = this,
			X = _FUW.X,
			popup = t.popup;
		if (!t.isOpen) return;
		if (t.isModal) X.clearModalBlocker();
		$(popup).css({display:'none',zIndex:-1});
		t.isOpen = false;
		t.resetInTimer();
	}
};
function XMLElementNode(e) {
	this.element = e;
}
XMLElementNode.prototype = {
	GetData : function() {return _FUW.U.GetData(this.element);},
	DecodeGetData : function(isDoubleEncoded) {
		var s = decodeURIComponent(this.GetData());
		return isDoubleEncoded ? decodeURIComponent(s) : s;
	},
	getAttribute : function(name){return this.element.getAttribute(name);}
};
/**
 * Utility that will cause the bottom and/or right sides of the subject element
 * to match those of the target element by adjusting the height and/or width of
 * the adjustor element.  You MUST make sure that the adjustor element height/width
 * changes will directly cause the subject element to change.  The height is adjusted
 * unless doHeight is false and doWidth is true.  The width is adjusted only if
 * doWidth is true.
 *
 * You may also specify h/w offsets.  When specified the target is adjusted not
 * to match the subject but rather to the offset from the target.
 *
 * NOTE: The size matcher has a defect where the adjustment is computed incorrectly
 * if the adjustor element has style sheet padding set. This needs to be fixed but
 * will need some extended testing to make sure nothing is broken in any of the
 * existing sites that use this.  The code needs to subtract the top/bottom or
 * right/left padding from the height/width value since the padding counts towards
 * the real width.
 *
 * @param subjectID
 * @param targetID
 * @param adjustorID
 * @param hOffset
 * @param wOffset
 * @param doHeight
 * @param doWidth
 * @oaran noReduce
 * @param useMinStyle
 * @return
 */
SizeMatcher = _FUW.SizeMatcher = function (subjectID, targetID, adjustorID, hOffset, wOffset, doHeight, doWidth, noReduce, useMinStyle) {
	var t = this;
	t.objectClass = 'SizeMatcher';
	t.subjectID = subjectID;
	t.targetID = targetID;
	t.adjustorID = adjustorID;
	t.doHeight = doHeight || !doWidth;
	t.doWidth = doWidth;
	t.hOffset = hOffset ? hOffset : 0;
	t.wOffset = wOffset ? wOffset : 0;
	t.started = false;
	t.targetIsWindow = false;
	t.reduce = noReduce ? false : true;
	t.wStyle = useMinStyle ? 'minWidth' : 'width';
	t.hStyle = useMinStyle ? 'minHeight' : 'height';
	_FUW.U.onload(t);
};
_FUW.SizeMatcher.prototype = {
	onPageLoad : function() {
		var t = this;
		if (t.started) return;
		t.started = true;
		if (!(t.subject = document.getElementById(t.subjectID))) return;
		if (t.targetID == 'window') t.targetIsWindow = true;
		else if (!(t.target = document.getElementById(t.targetID))) return;
		if (!(t.adjustor = document.getElementById(t.adjustorID))) return;
		t.doResize();
		t.interval = window.setInterval(function(){t.doResize();}, 200);
	},
	onDocumentReady : function() {
		this.onPageLoad();
	},
	doResize : function() {
		var t = this, spos, tpos, ntpos, v, adj = t.adjustor, apos=false, wd, U = _FUW.U, xshrink=0, yshrink=0;
		spos = U.getAbsPosition(t.subject);
		if (t.targetIsWindow) {
			tpos = U.getWindowPosition();
			wd = U.getWindowDimensions();
			yshrink = Math.min(adj.offsetHeight, tpos.bottom - wd.wh);
			xshrink = Math.min(adj.offsetWidth, tpos.right - wd.ww);
		} else {
			tpos = U.getAbsPosition(t.target);
		}
		if (/^(img)$/i.test(adj.tagName)) apos = _FUW.U.getAbsPosition(adj);
		if (t.doHeight && (spos.bottom != (tpos.bottom + t.hOffset) || yshrink)) {
			v = Math.max(parseInt(adj.offsetHeight) + tpos.bottom - spos.bottom + t.hOffset - yshrink, 0);
			if (v >= spos.height || t.reduce) adj.style[t.hStyle] = v + 'px';
			if (apos && !t.doWidth) adj.style[t.wStyle] = apos.width + 'px';
		}
		if (t.doWidth && (spos.right != (tpos.right + t.wOffset) || xshrink)) {
			v = Math.max(parseInt(adj.offsetWidth) + tpos.right - tpos.top + t.wOffset - xshrink, 0);
			if (v >= spos.width || t.reduce) adj.style[t.wStyle] = v + 'px';
			if (apos && !t.doHeight) adj.style[t.hStyle] = apos.height + 'px';
		}
		// Stop adjusting if we have impacted the target
		if (t.targetIsWindow) return;
		ntpos = _FUW.U.getAbsPosition(t.target);
		if (tpos.bottom != ntpos.bottom || tpos.top != ntpos.top || tpos.left != ntpos.left || tpos.right != ntpos.right) {
			window.clearInterval(t.interval);
		}
	}
};
ShadowBox = _FUW.ShadowBox = function (id, c, bg, cr, bc, bw, sc, so, ss, sx, sy) {
	var t = this;
	t.objectClass = 'ShadowBox';
	t.id = id;
	t.color = c;
	t.bgcolor = bg;
	t.corner = cr;
	t.borderColor = bc;
	t.borderWidth = bw;
	t.shColor = sc;
	t.shOpacity = so;
	t.shSigma = ss;
	t.shX = sx;
	t.shY = sy;
	_FUW.U.onload(t);
};
_FUW.ShadowBox.prototype = {
	onPageLoad : function() {
		var t = this, n,
			U = _FUW.U,
			sc = document.getElementById(t.id), pad;

		if (!sc) return;
		pad = t.pad = sc.parentNode;
		if (!U.hasClass(pad, 'shadowbox_pad')) return;
		n = t.cell = pad.parentNode;
		if (U.hasClass(n, 'shadowbox_cell')) {
			while(n && !U.hasClass(n, 'shadowbox_outer')) n = n.parentNode;
			if (!n) return;
		}
		t.outer = n;
		if (!U.hasClass(n, 'shadowbox_outer')) return;
		t.w = t.h = 0;
		t.doResize();
		t.interval = window.setInterval(function(){t.doResize();}, 200);
	},
	doResize : function() {
		var t = this,
			pad = t.pad,
			w = pad.offsetWidth,
			h = pad.offsetHeight,
			v, st;

		if (t.w == w && t.h == h) return;
		t.w = w; t.h = h;
		st = 'url(/images/dropimg.php?shadowbox=1&w=' + w + '&h=' + h;
		if (v = t.color) st += '&color=' + encodeURIComponent(v);
		if (v = t.bgcolor) st += '&bgcolor=' + encodeURIComponent(v);
		if (v = t.corner) st += '&corner=' + encodeURIComponent(v);
		if (v = t.borderColor) st += '&border_color=' + encodeURIComponent(v);
		if (v = t.borderWidth) st += '&border_width=' + encodeURIComponent(v);
		if (v = t.shColor) st += '&shcolor=' + encodeURIComponent(v);
		if (v = t.shOpacity) st += '&shopacity=' + encodeURIComponent(v);
		if (v = t.shSigma) st += '&shsigma=' + encodeURIComponent(v);
		if (v = t.shX) st += '&shx=' + encodeURIComponent(v);
		if (v = t.shY) st += '&shy=' + encodeURIComponent(v);
		t.outer.style.backgroundImage = st + ')';
	}
};
WarningBlocker = _FUW.WarningBlocker = function (blocker_id, blocked_id) {
	var t = this;
	t.objectClass = 'WarningBlocker';
	t.blocker_id = blocker_id;
	t.blocked_id = blocked_id;
	_FUW.U.onload(t);
};
_FUW.WarningBlocker.prototype = {
	onPageLoad : function() {
		var t = this, w, h, blocker, blocked, pos;
		blocker = document.getElementById(t.blocker_id);
		blocked = document.getElementById(t.blocked_id);
		if (!blocker || !blocked) return;
		w = blocked.offsetWidth;
		h = blocked.offsetHeight;
		pos = _FUW.U.getAbsPosition(blocked);
		blocker.style.display = "block";
		blocker.style.left = pos.left + "px";
		blocker.style.top = pos.top + "px";
		blocker.style.width = w + "px";
		blocker.style.height = h + "px";
	},
	onPageUpdate : function() {
		this.onPageLoad();
	}
};
/*
* The constructor function: creates a cookie object for the specified
* document, with a specified name and optional attributes.
* Arguments:
*   document:	The Document object that the cookie is stored for. Required.
*   name:		A string that specifies a name for the cookie. Required.
*   time:		An optional number that specifies the time the cookie expires.
*					time is expressed as a unix timestamp so is the number of seconds
*					since epoch. A time of 0 makes the cookie transient.
*   path:		An optional string that specifies the cookie path attribute.
*   domain:		An optional string that specifies the cookie domain attribute.
*   secure:		An optional Boolean value that, if true, requests a secure cookie.
*/
CookieUtil = _FUW.CookieUtil = function (document, name, time, path, domain, secure) {
	var t = this;
	t.objectClass = 'CookieUtil';
	t.document = document;
	t.name = name;
	t.expiration = (time * 1) ? new Date(time * 1000) : null; // Date takes milliseconds
	t.path = path ? path : null;
	t.domain = domain ? domain : null;
	t.secure = secure ? true : false;
};
_FUW.CookieUtil.prototype = {
	store : function (value) {
		var cookie = this.name + '=' + value;
		if (this.expiration) cookie += '; expires=' + this.expiration.toGMTString();
		if (this.path) cookie += '; path=' + this.path;
		if (this.domain) cookie += '; domain=' + this.domain;
		if (this.secure) cookie += '; secure';

		// Now store the cookie by setting the magic Document.cookie property.
		this.document.cookie = cookie;
	},
	read : function() {
		// First, get a list of all cookies that pertain to this document.
		// We do this by reading the magic Document.cookie property.
		var allcookies = this.document.cookie, start, end;
		if (allcookies == "") return false;

		// Now extract just the named cookie from that list.
		start = allcookies.indexOf(this.name + '=');
		if (start == -1) return false;   // Cookie not defined for this page.
		start += this.name.length + 1;  // Skip name and equals sign.
		end = allcookies.indexOf(';', start);
		if (end == -1) end = allcookies.length;
		return allcookies.substring(start, end);
	},
	remove : function() {
		var cookie;
		cookie = this.name + '=';
		if (this.path) cookie += '; path=' + this.path;
		if (this.domain) cookie += '; domain=' + this.domain;
		cookie += '; expires=Fri, 02-Jan-1970 00:00:00 GMT';
		this.document.cookie = cookie;
	}
};
_FUW.WidgetLoader = function(opts) {
	var t = this,
		U = _FUW.U,
		i = null, s = '', sp =  '',
		w = opts.width + '',
		h = opts.height + '',
		doStyle = w || h;

	t.objectClass = 'WidgetLoader';
	t.id = U.uniqueString(12);
	for(i in opts) t[i] = opts[i];
	if (doStyle) {
		s += ' style="';
		if (w) {
			if (/^\d+$/.test(w)) w += 'px';
			s += 'width:' + w + ';';
			sp = ' style="width:' + w + ';"';
		}
		if (h) {
			if (/^\d+$/.test(h)) h += 'px';
			s += 'height:' + h + ';';
		}
		s += '"';
	}
	document.write('<span' + sp + '><iframe id="' + t.id + '" src="' + t.url + '" frameborder="0"' + s + '></iframe></span>');
	U.addMessageListener(t);
	t.TimerID = setInterval(function(){t.checkSize();}, 200);
};
_FUW.WidgetLoader.prototype = {
	checkSize : function() {
		var t = this, U = _FUW.U, iframe = U.getElementById(t.id);
		if (!iframe) return;
		t.iframe = iframe;
		/*
		 * 2015-09-21 Added the iframe ID to the getbodysize request.  Without this,
		 * when there are more than one iframe widgets the onmessage code below
		 * would act on the messages from all the widgets.  The net result was
		 * a bizzare sizing battle.
		 */
		U.sendMessage(iframe, 'getbodysize:ExternalWidgetWrapper:' + t.id);
	},
	onmessage : function(event) {
		var t = this, U = _FUW.U, message = event.data, a, h, s, iframe = t.iframe, parent;
		if (!iframe) return;
		parent  = iframe.parentNode;
		a = message.split(':');
		//parent.setAttribute('title', message);
		switch (a[0]) {
			case 'bodysize':
				// break out if id of another widget
				if (a[2] && a[2] != t.id) break;
				s = a[1].split(',');
				t.h = s[1];
				if (!(h = parseInt(s[1]))) break;
				h += (U.IE8 ? 25 : 15);
				parent.style.display = 'inline-block';
				parent.style.height = h + 'px';
				iframe.style.height = h + 'px';
				break;
			default:
				// do nothing
		}
	}
};
_FUW.ResizeAdjustor = function(element) {
	var t = this;
	t.objectClass = 'ResizeAdjustor';
	t.element = element;
	//$(window).resize(function() {t.reAdjust();});
	_FUW.U.register(t);
};
_FUW.ResizeAdjustor.prototype = {
	onPageResize : function() {
		var t = this,
			element = t.element;
		_FUW.U.Adjust(element, false);
	}
};
/**
 * The AutoHide class provides the javascript support for links that auto-open to
 * show additional content when the mouse hovers over the link or when the user
 * clicks the ► arrow along the side.  This can be used for Frequently Asked Questions
 * or widget entries where the initial display is a list that the user can open.
 *
 * The opts parameter is an object with the following possible configuration properties
 * hoverDelay - number of milliseconds after hover before open is triggered (default 750)
 * expandTime - number of milliseconds to animate the auto open (default 300)
 * collapseTime - number of milliseconds to animate the auto close (default 300)
 * analytics - object with analytics category, event and data values
 *
 * @param id
 * @param opts
 */
_FUW.AutoHide = function(id, opts) {
	var t = this, i=null;
	t.objectClass = 'AutoHide';
	t.id = id;
	t.isOpen = false;
	if (!opts) $opts = {};
	for(i in opts) t[i] = opts[i];
	if (!t.easing) t.easing = 'easeOutQuad';
	_FUW.U.register(this);
};
/**
 * The _FUW.AutoHide.toggle is a static method that can be called to toggle the
 * "open" state of the AutoHide class associated with the provided id parameter.
 * The element parameter is the browser element that was clicked and invoked this
 * by setting the "onclick" attribute.
 *
 * @param element
 * @param id
 */
_FUW.AutoHide.toggle = function(element, id) {
	var entry;
	if (!(entry = _FUW.AutoHide.GetEntry(element, id))) return;
	entry.toggle();
};
/**
 * The _FUW.AutoHide.mouseover static method is used to trigger the mousover monitoring
 * of the AutoHide class.  The appropriate AutoHide class is identified by the
 * id parameter.  The element parameter is the browser element that was hovered and
 * invoked this by setting the "onmouseover" attribute.
 */
_FUW.AutoHide.mouseover = function(element, id) {
	var entry;
	if (!(entry = _FUW.AutoHide.GetEntry(element, id))) return;
	entry.mouseover(element);
};
_FUW.AutoHide.Entries = {};
_FUW.AutoHide.GetEntry = function(element, id) {
	var U = _FUW.U, entry, autoHideElement;
	if (entry = element.AutoHideEntry) return entry;
	if (!(autoHideElement = U.getElementById(id))) return null;
	if (!(entry = autoHideElement.AutoHideEntry)) {
		entry = _FUW.AutoHide.Entries[id];
		if (!entry) return null;
		autoHideElement.AutoHideEntry = entry;
		entry.loadElements(autoHideElement);
		entry.AutoHideElement = autoHideElement;
	}
	element.AutoHideEntry = entry;
	return entry;
};
_FUW.AutoHide.prototype = {
	onPageLoad : function() {
		var t = this,
			U = _FUW.U,
			autoHideElement;
		if (t.loaded) return;
		t.loaded = true;
		if (!(autoHideElement = t.AutoHideElement = U.getElementById(t.id))) return;
		_FUW.AutoHide.Entries[t.id] = autoHideElement.AutoHideEntry = t;
		t.loadElements(autoHideElement);
	},
	loadElements: function(autoHideElement) {
		var t = this, e,
			U = _FUW.U,
			autoHideBase;

		t.AutoHideInner = U.getChildWithClass(autoHideElement, 'AutoHideInner');
		if (t.AutoHideBase = autoHideBase = U.getParentWithClass(autoHideElement, 'AutoHideBase')) {
			t.AutoHideArrow = e = U.getChildWithClass(autoHideBase, 'AutoHideArrow');
			if (e) e.AutoHideEntry = t;
			t.AutoHideStamp = U.getChildWithClass(autoHideBase, 'PublicationStampImage');
		}
	},
	onDocumentReady : function() {
		this.onPageLoad();
	},
	toggle : function() {
		var t = this;
		if (t.animation) return;
		if (t.isOpen) t.collapse();
		else t.expand();
	},
	mouseover : function(element) {
		var t = this, v;
		if (t.animation || t.isOpen || t.hover) return;
		if (!element.onmouseout) element.onmouseout = function() {t.mouseout();};
		t.hover = setInterval(function(){
			clearInterval(t.hover);
			t.hover = 0;
			t.expand();
		}, (v = t.hoverDelay) ? v : 750);
	},
	mouseout : function() {
		var t = this;
		if (t.hover) {
			clearInterval(t.hover);
			t.hover = 0;
		}
	},
	expand : function() {
		var t = this,
			U = _FUW.U, pos,ipos, v,
			autoHideElement = t.AutoHideElement,
			expandTime = (v = t.expandTime) ? v : 300,
			analytics = t.analytics;

		if (analytics) {
			U.sendAnalyticsEvent(analytics.category, analytics.event, analytics.data);
		}
		autoHideElement.style.display = 'block';
		pos = U.getAbsPosition(autoHideElement);
		ipos = U.getAbsPosition(t.AutoHideInner);
		t.animation = true;
		t.isOpen = true;
		t.setArrow();
		$(t.AutoHideStamp).css({display:'none'});
		$(autoHideElement).animate({height:(ipos.bottom - pos.top)}, {queue:false, duration:expandTime, easing:t.easing, complete:function(){
			t.animation = false;
			U.onPageUpdate();
		}});
	},
	collapse : function() {
		var t = this,v,
			autoHideElement = t.AutoHideElement,
			collapseTime = (v = t.collapseTime) ? v : 300;

		t.isOpen = false;
		t.setArrow();
		t.animation = true;
		$(autoHideElement).animate({height:0}, {queue:false, duration:collapseTime, easing:t.easing, complete:function(){
			t.animation = false;
			autoHideElement.style.display = 'none';
			$(t.AutoHideStamp).css({display:''});
			_FUW.U.onPageUpdate();
		}});
	},
	setArrow : function() {
		var t = this,
			arrowElement = t.AutoHideArrow;
		if (!arrowElement) return;
		_FUW.U.setElementText(arrowElement, t.isOpen ? '▼' : '►', false);
	}
};
