dlabs.settings.scripts.push('global.js');
/*
 *
 *
 *	DO NOT MODIFY THIS FILE WITHOUT CONSULTING A FRONTEND DEVELOPER
 *
 *
 */
// SECTION : static properties
Object.type							= typeof Object();
Boolean.type						= typeof Boolean();
Function.type						= typeof Function();
String.type							= typeof String();
Number.type							= typeof Number();
RegExp.type							= typeof RegExp(1);
Array.type							= typeof Array();
Function.empty						= new Function();
String.empty						= new String();
String.whiteSpace					= ' ';
dlabs.exceptions.nullReference		= 'Object reference not set to an instance of an object.';
dlabs.exceptions.invalidArgument	= 'Invalid argument.';
// SECTION : AddThis configuration - DO NOT MODIFY THIS SECTION WITHOUT CONSULTING A SEO DIRECTOR
var addthis_pub						= 'dmseo'; 
var addthis_logo					= dlabs.settings.urls.media + '/images/logo-ehow-142.gif';
var addthis_logo_background			= 'ffffff';
var addthis_logo_color				= '333333';
var addthis_brand					= '<sup>eHow.com</sup>';
var addthis_options					= 'facebook, stumbleupon, google, delicious, mixx, twitter, buzz, digg, more';
var addthis_localize				= { email: 'Email a Friend', email_caption: 'Email a Friend' };
var addthis_hover_delay				= 200;
var addthis_use_addressbook			= true;
/* jQuery ScrollTo */
(function($){var o=$.scrollTo=function(a,b,c){o.window().scrollTo(a,b,c)};o.defaults={axis:'y',duration:1};o.window=function(){return $($.browser.safari?'body':'html')};$.fn.scrollTo=function(l,m,n){if(typeof m=='object'){n=m;m=0}n=$.extend({},o.defaults,n);m=m||n.speed||n.duration;n.queue=n.queue&&n.axis.length>1;if(n.queue)m/=2;n.offset=j(n.offset);n.over=j(n.over);return this.each(function(){var a=this,b=$(a),t=l,c,d={},w=b.is('html,body');switch(typeof t){case'number':case'string':if(/^([+-]=)?\d+(px)?$/.test(t)){t=j(t);break}t=$(t,this);case'object':if(t.is||t.style)c=(t=$(t)).offset()}$.each(n.axis.split(''),function(i,f){var P=f=='x'?'Left':'Top',p=P.toLowerCase(),k='scroll'+P,e=a[k],D=f=='x'?'Width':'Height';if(c){d[k]=c[p]+(w?0:e-b.offset()[p]);if(n.margin){d[k]-=parseInt(t.css('margin'+P))||0;d[k]-=parseInt(t.css('border'+P+'Width'))||0}d[k]+=n.offset[p]||0;if(n.over[p])d[k]+=t[D.toLowerCase()]()*n.over[p]}else d[k]=t[p];if(/^\d+$/.test(d[k]))d[k]=d[k]<=0?0:Math.min(d[k],h(D));if(!i&&n.queue){if(e!=d[k])g(n.onAfterFirst);delete d[k]}});g(n.onAfter);function g(a){b.animate(d,m,n.easing,a&&function(){a.call(this,l)})};function h(D){var b=w?$.browser.opera?document.body:document.documentElement:a;return b['scroll'+D]-b['client'+D]}})};function j(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
/* jQuery LocalScroll */
(function($){var g=location.href.replace(/#.*/,''),h=$.localScroll=function(a){$('body').localScroll(a)};h.defaults={duration:1e3,axis:'y',event:'click',stop:1};h.hash=function(a){a=$.extend({},h.defaults,a);a.hash=0;if(location.hash)setTimeout(function(){i(0,location,a)},0)};$.fn.localScroll=function(b){b=$.extend({},h.defaults,b);return(b.persistent||b.lazy)?this.bind(b.event,function(e){var a=$([e.target,e.target.parentNode]).filter(c)[0];a&&i(e,a,b)}):this.find('a,area').filter(c).bind(b.event,function(e){i(e,this,b)}).end().end();function c(){var a=this;return!!a.href&&!!a.hash&&a.href.replace(a.hash,'')==g&&(!b.filter||$(a).is(b.filter))}};function i(e,a,b){var c=a.hash.slice(1),d=document.getElementById(c)||document.getElementsByName(c)[0],f;if(d){e&&e.preventDefault();f=$(b.target||$.scrollTo.window());if(b.lock&&f.is(':animated')||b.onBefore&&b.onBefore.call(a,e,d,f)===!1)return;if(b.stop)f.queue('fx',[]).stop();f.scrollTo(d,b).trigger('notify.serialScroll',[d]);if(b.hash)f.queue(function(){location=a.hash;$(this).dequeue()})}}})(jQuery);
// SECTION : String methods
String.replace = function(){
	var _string = arguments[0];
	
	if(typeof _string !== String.type)
		return _string;
	
	if(arguments.length != 0)
		for(var i = 1, n = arguments.length; i !== n; i++)
			while(_string.indexOf(arguments[i]) !== -1){ _string = _string.replace(arguments[i],String.empty) };
	
	return _string;
};
String.format = function(){
	if(arguments.length == 0)
		return null;
	
	var _string = arguments[0];
		
	for(var i = 1, n = arguments.length; i < n; i++)		
		_string = _string.replace(RegExp('\\{' + (i-1) + '\\}','gm'),arguments[i]);
	
	return _string;
};
String.toRegExp = function(pattern, flags){
	return new RegExp(pattern.replace(/[\[\]\\{}()+*?.$^|]/g, function(m){return '\\'+m;}),flags);
};
String.isNullOrEmpty = function(value){
	return typeof value === String.type && value.length ? value.trim().length == 0 : true;
};
String.prototype.trim = function(){
	return this.replace(RegExp.filter.whitespace,String.empty);
};
String.prototype.toHex = function(){
	return parseInt(this,10).toHex();
};
String.prototype.truncate = function(threshold,preserve,literal){ // refactor
	if (this.length > threshold){
		var string = this.substring(0,threshold).replace(/\w+$/,'').trim();
		
		return (preserve) ? String.format('{0} <span style="display:none;">{1}</span>',(literal) ? string + literal : string,escape(this)) : (literal) ? string + literal : string;
	}
	
	return (this) ? this.toString() : '';
};
// SECTION : RegExp methods
RegExp.filter = {
	whitespace: /^\s+|\s+$/g,
	nonAlphaNumeric: /[^0-9a-zA-Z]/g,
	nonNumeric: /[^0-9]/g,
	nonAlpha: /[^a-zA-Z]/g
};
RegExp.match = {
	alphaNumeric : /^[0-9a-zA-Z]+$/,
	alphaNumericWhitespace : /^[0-9a-zA-Z\s]+$/
};
// SECTION : Array methods
Array.prototype.contains = function(value){
	for (var i = 0, n = this.length; i < n; i++)
		if(this[i] === value)
			return true;
			
	return false;
};
Array.prototype.remove = function(from, to){
	var rest = this.slice((to || from) + 1 || this.length);
	
	this.length = from < 0 ? this.length + from : from;

	return this.push.apply(this, rest);
};
if(!Array.prototype.indexOf){ // ECMA-262 standard
	Array.prototype.indexOf = function(elt /*, from*/){
		var len = this.length;
		var from = Number(arguments[1]) || 0;
    
		from = (from < 0)
			? Math.ceil(from)
			: Math.floor(from);
    
		if(from < 0)
			from += len;

		for(; from < len; from++)
			if (from in this && this[from] === elt)
				return from;

		return -1;
	};
}
// SECTION : Boolean methods
Boolean.parse = function(value){
	switch(typeof value){
		case Number.type:
			return value > 0;
		case Function.type:
			return value() || false;
		case Object.type:
			return value && value.length ? value.length > 0 : false;
		case String.type:
			var _string = value.trim().toLowerCase();

			return _string.length
				? _string == 'true' || _string == 'on' || _string == 'success' || (isNaN(_string) ? false : parseInt(_string,10) > 0) 
				: false;
	}

	return false;
}
// SECTION : utilities
function parseBoolean(value){ // deprecated: use Boolean.parse(value) instead
	return Boolean.parse(value);
}
dlabs.utils.parseRGB = function(value){ // ripped from http://jquery.offput.ca/highlightFade/
	var result;

	if (value && value.constructor === Array && value.length === 3)
		return value;
	if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(value))
		return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];
	if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(value))
		return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];
	if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(value))
		return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];
	if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(value))
		return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];
};
dlabs.utils.removeLinkByHref = function(href, timeout){
	return (function remove(){
		for(var links = document.getElementsByTagName('link'), i = 0 , n = links.length; i < n; i++)
			if(links[i].href.indexOf(href) !== -1)
				return jQuery(links[i]).attr('href','#').remove();
		
		if(--timeout !== 0)
			setTimeout(remove, 1000);
	})();
};
dlabs.utils.deferScript = function(url, fn){
	jQuery(window).ready(function(){
		jQuery.getScript(url, function(script){
			eval(script);
			setTimeout(fn, 10);
		});
	});
};
dlabs.utils.cleanObject = function(object){
	for(var property in object)
		if(typeof object[property] === 'undefined')
			delete object[property];
			
	return object;
};
// jQuery properties and plugins
jQuery.browser.msie6 = jQuery.browser.msie && jQuery.browser.version < 7;
jQuery.each(['lt','gt'], function(i, n){
	jQuery.fn[n] = function(num, fn){
		return this.filter(':' + n + '(' + num + ')', fn);
	};
});
jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'borderColor', 'color', 'outlineColor'], function(i, attr){
	jQuery.fx.step[attr] = function(fx){
		if (fx.state === 0){
			fx.end = dlabs.utils.parseRGB( fx.end );
			fx.start = (function(elem, attr){
				var color;

				do {
					color = jQuery.curCSS(elem, attr);

					if (color.length !== 0 && color !== 'transparent' || jQuery.nodeName(elem, 'body'))
						break; 

					attr = 'backgroundColor';
				} while ( elem = elem.parentNode );

				return dlabs.utils.parseRGB(color);
			})(fx.elem, attr);
		}

		fx.elem.style[attr] = 'rgb(' + [
			Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
			Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
			Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
		].join(',') + ')';
	};
});
jQuery.fn.disableTextSelect = function(){
	return this.each(function(){
		jQuery(this).bind(jQuery.browser.msie ? 'selectstart' : 'mousedown',
			function(){ return false; }
		);
	});
};
jQuery.fn.hoverClass = function(className){
	return String.isNullOrEmpty(className) ? this : this.each(function(){
		jQuery(this).hover( 
			function(){ jQuery(this).addClass(className); },
			function(){ jQuery(this).removeClass(className); }
		);
	});
};
jQuery.fadeBorderDefaults = {
	complete: null,
	duration: 400
};
jQuery.fn.fadeBorder = function(color, options){
	options = jQuery.extend({ }, jQuery.fadeBorderDefaults, options);
	
	return this.each(function(){
		jQuery(this).stop(true).animate({ borderColor: color }, options);
	});
};
jQuery.slideHeightDefaults = {
	easing: 'swing',
	height: null,
	complete: null,
	duration: 400
};
jQuery.fn.slideHeight = function(options){
	options = jQuery.extend({ }, jQuery.slideHeightDefaults, options);

	return this.each(function(){
		var $this = jQuery(this);
		
		$this.animate({ height: options.height === null ? $this.find('*').height() : options.height }, options);
	});
};
jQuery.slideWidthDefaults = {
	easing: 'swing',
	width: null,
	complete: null,
	duration: 400
};
jQuery.fn.slideWidth = function(options){
	options = jQuery.extend({ }, jQuery.slideWidthDefaults, options);

	return this.each(function(){
		var $this = jQuery(this);
		
		$this.animate({ width: options.width === null ? $this.find('*').width() : options.width }, options);
	});
};
jQuery.tooltipDefaults = {
	delay: 400,
	speed: 100,
	maxWidth: 250,
	className: 'ToolTip',
	xOffset: 0,
	yOffset: 2
};
jQuery.fn.tooltip = function(message, options){
	// private properties
	var self = this;
	var timeoutId = null;
	
	// private methods
	function killTimer(){ clearTimeout(timeoutId); }
	
	// public properties
	self.options = jQuery.extend({ }, jQuery.tooltipDefaults, options);
	self.tooltip = jQuery('<span></span>')
		.addClass(self.options.className)
		.css('position', 'absolute')
		.html(message)
		.hide();
	
	// public methods
	self.hideTooltip = function(){
		killTimer();
		
		timeoutId = setTimeout(function(){
			self.tooltip.fadeOut(self.options.speed);
		}, self.options.delay);
		
		return self;
	};
	self.showTooltip = function(target){	
		var _$target = jQuery(target);
		var _position = _$target.offset();
		
		_position.top += _$target.height() + self.options.yOffset;
		_position.left += self.options.xOffset;
		
		killTimer();
		self.tooltip.css(_position);
		
		if(self.tooltip.width() > self.options.maxWidth)
			self.tooltip.width(self.options.maxWidth);

		self.tooltip.fadeIn(self.options.speed);
		
		return self;
	};
	self.destroy = function(){
		self.tooltip.remove();
		self.unbind('.ToolTip');
		
		for(var property in self)
			delete self[property];

		return self;
	};
	
	return self.each(function(){
		jQuery(this)
			.bind('mouseover.ToolTip', function show(){ self.showTooltip(this); })
			.bind('mouseout.ToolTip', self.hideTooltip);
		self.tooltip
			.bind('focus.ToolTip', killTimer)
			.bind('blur.ToolTip', self.hideTooltip)
			.bind('mouseover.ToolTip', killTimer)
			.bind('mouseout.ToolTip', self.hideTooltip)
		jQuery(function(){
			self.tooltip.appendTo('body');
		});
	});
};

var SiteLifeAvatars = function(){ // refactor: use namespace
	var batchRequestSize = 10;
	var avatars = new Object();
	var batchCount = -1;
	
	function buildAvatar(url, userName, size){
		if(size != 'Small' && url.indexOf('.Small.') != -1)
			url = url.replace('.Small.', '.' + size + '.');

		return String.format('<img src="{0}" alt="{1}" />', url, userName);
	}
	
	return {
		HasExecuted: function(){
			return batchCount > -1;
		},
		IsComplete: function(){
			return batchCount == 0;
		},
		ProcessResponse: function(batch){
			jQuery(batch.Responses).each(function(i, e){
				var _userId = e.User.UserKey.Key.toLowerCase();

				jQuery(avatars[_userId].element).each(function(){
					jQuery(this).html(buildAvatar(e.User.AvatarPhotoUrl, _userId, avatars[_userId].avatarSize));
				});
			});
			
			batchCount--;
			
			return this;
		},
		Request: function(fn){
			var count = 0;
			var batches = new Array();
			var callback = typeof fn === Function.type
				? function(batch){ SiteLifeAvatars.ProcessResponse(batch); fn(); }
				: SiteLifeAvatars.ProcessResponse
			
			avatars = new Object();
			
			jQuery('.userAvatar').each(function(i){
				var _item = $(this);
				
				if(_item.attr('title').length && !_item.children().length){
					var _size = 'Large';
					var _userId = _item.attr('title').toLowerCase();
					
					if(_item.hasClass('avatarTiny'))
						_size = 'Tiny';
					else if(_item.hasClass('avatarSmall'))
						_size = 'Small';
					else if(_item.hasClass('avatarMedium'))
						_size = 'Medium';
					
					if(avatars[_userId])
						avatars[_userId].element.push(_item);
					else
						avatars[_userId] = { element: [ _item ], avatarSize: _size };

					if(count++ % batchRequestSize == 0)
						batches.push(new RequestBatch());

					batches[batches.length-1].AddToRequest(new UserKey(_userId));
				}
			});
			
			batchCount = batches.length;
			
			for(var i = 0, n = batches.length; i < n; i++)
				batches[i].BeginRequest(dlabs.settings.urls.siteLifeServer, callback);
			
			return this;
		}
	};
}();
var SiteLifeCounts = function(){ // refactor: use namespace
	var friendRequestsElementIds = new Array();
	var privateMessagingElementIds = new Array();

	return {
		ProcessResponse:function(batch){
			if(batch.Responses.length == 0)
				return;

			var batchIndex = 0, friendRequests = 0, unreadCount = 0;
			var friendPageRequests = batch.Responses[batchIndex++].FriendPage;
			var privateMessages = batch.Responses[batchIndex++].PrivateMessageFolderList;
			
			if(friendPageRequests)
				for(var a = 0 , b = friendRequestsElementIds.length; a < b; a++)
					if(friendPageRequests.NumberOfFriends > 0)
						jQuery(document.getElementById(friendRequestsElementIds[a])).append(' (' + friendPageRequests.NumberOfFriends + ')');
			if(privateMessages){
				for(var a = 0, b = privateMessages.FolderList.length; a < b; a++){
					if(privateMessages.FolderList[a].FolderID.toLowerCase() == 'inbox'){
						for(var i = 0, n = privateMessagingElementIds.length, x = privateMessages.FolderList[a].UnreadMessageCount; i < n; i++)
							if(x > 0)
								jQuery(document.getElementById(privateMessagingElementIds[i])).append(' (' + x + ')');

						break;
					}
				}
			}
		},
		Request:function(Username, FriendRequestElementIds, PrivateMessagingElementIds){
			friendRequestsElementIds = FriendRequestElementIds;
			privateMessagingElementIds = PrivateMessagingElementIds;
		
			var requestBatch = new RequestBatch();
			requestBatch.AddToRequest(new FriendPage(new UserKey(Username), 10, 1, true));	// friend requests
			requestBatch.AddToRequest(new PrivateMessageFolderList());	// private messaging
			requestBatch.BeginRequest(dlabs.settings.urls.siteLifeServer, SiteLifeCounts.ProcessResponse);  
		}
	};
}();
function openWindow(url){ // deprecated
    window.open(url,'eHow','right=10,top=10,width=400,height=300,,resizable=1,scrollbars=yes,titlebar=no,toolbar=no');
}
function switchTab(selector, speed){ // refactor: jQuery plugin
	var $tabs = jQuery(selector + ' .TabNavigation li');
	var $contents = jQuery(selector + ' .TabContent');

	if($contents.length < 2)
		return;

	if($contents.filter('.Selected').length == 0)
		$contents.gt(0).hide();
	
	$tabs
		.bind('click', function(){
			var $tab = jQuery(this);
			
			if($tab.hasClass('selected'))
				return false;
				
			$tabs.removeClass('selected');
			$tab.addClass('selected').blur();
			
			if(speed === 0)
				$contents.hide().eq($tabs.index(this)).show();
			else
				$contents.hide().eq($tabs.index(this)).fadeIn(speed||200).eq(0);

			//return false;
		})
		.disableTextSelect();
		
	return { tabs: $tabs, contents: $contents };
}
function submitDidThis(articleId, redirectUrl){ // refactor: use namespace
	if(!dlabs.user.isLoggedIn)
		return document.location.href = redirectUrl;
	
	var $button = jQuery('.DidThisButton');
	
	if($button.hasClass('Button1a'))
		return;
	
	jQuery.get(dlabs.settings.urls.webServices + 'ididthis.aspx?list=none&action=add&un=' + dlabs.user.name + '&article_id=' + articleId, function(){
		dlabs.objects.didThisMembersFaceroll.getPage(1, function(){
			$button
				.prepend('<img alt="Done" src="' + dlabs.settings.urls.media + '/images/graycheckbox.png" />')
				.removeClass('Button3a')
				.addClass('Button1a');
			jQuery('.DidThis .DefaultContent').remove()
			jQuery('.DidThis .Faceroll').css('background-image', String.empty)
		});
	});
}
function setFontSize(id, os){ // refactor: jQuery plugin
	$(id).each(
		function(i){
			$(this).css("font-size", parseInt($(this).css("font-size").split("px")[0]) + os + "px");
	});
}
function jToggleBgColor(selector,color){ // refactor: jQuery plugin
	var $element = jQuery(selector);
	var bgColor = $element.css('background-color');
	
	return $element
		.focus(function(){ $element.css('background-color', color); })
		.blur(function(){ $element.css('background-color', bgColor); });
}

function jToggleElementOpacity(selector, b){ // refactor: jQuery plugin
	return jQuery(selector)
		.fadeTo(250, b ? 0.33 : 1.0)
		.css('cursor', b ? 'default' : 'pointer');
}
function initTopicGuideMenu(){ // refactor: add to namespace and avoid hardcoding selectors to allow reusablity
	$('.haveSubNav').mouseover(function(){
		$(this).children("a").css("backgroundPosition", "right -17px");
		$('.subNav').eq($('.haveSubNav').index(this)).show();
	});
	$('.haveSubNav').mouseout(function(){
		$(this).children("a").css("backgroundPosition", "right 8px");
		$('.subNav').eq($('.haveSubNav').index(this)).hide();
	});
}
function scrollWindow(swOptions){
	// PRIVATE
	var self = this;
	self.ar;
	// Required Variables
	var itemList = swOptions.itemList;
	var marginWidth = swOptions.marginWidth;
	var itemsPerView = swOptions.itemsPerView;
	var navLeft = swOptions.navLeft;
	var navRight = swOptions.navRight;
	var shadedOpacity = swOptions.shadedOpacity;
	
	var shadedFilter = 'alpha(opacity='+(parseInt(shadedOpacity.substr(1,1))*10)+')';
	
	// Optional Variables
	var viewIndicator = null;
	var pageDisplay = null;
	
	if (swOptions.viewIndicator)
		viewIndicator = swOptions.viewIndicator;
	
	if (swOptions.pageDisplay)
		pageDisplay = swOptions.pageDisplay;
	
	var widgetWidth = itemList.children("li").width();
	var offset = ((widgetWidth + marginWidth)*itemsPerView);
	var numWidgets = itemList.children("li").length;
	var numPages = Math.ceil(numWidgets/itemsPerView);
	var maxRight = 0 - ((numPages - 1) * offset);
	var isCurrentlyScrolling = false;
	
	var animate = function(position){
		if(isCurrentlyScrolling)
			return;
		isCurrentlyScrolling = true;
		
		itemList.animate({ left: position }, 400, 'swing', function(){ isCurrentlyScrolling = false; })
		
		if (position == maxRight){
			lowerOpacity(navRight);
			navRight.unbind("click");
		} else if (navRight.css("opacity") != '1'){
			fullOpacity(navRight);
			navRight.bind("click", self.next);
		}
		
		if (position == 0){
			lowerOpacity(navLeft);
			navLeft.unbind("click");
		} else if (navLeft.css("opacity") != '1'){
			fullOpacity(navLeft);
			navLeft.bind("click", self.previous);
		}
	
		if (viewIndicator)
			setIndicator(position);
	
		if (pageDisplay)
			displayPage(position);
	}
	
	var setIndicator = function(position){
		var currentPage = Math.abs(position)/offset;
		if (viewIndicator){
			viewIndicator.children("li")
				.removeClass("current")
				.each(function(i){
					if (currentPage == i){
						$(this).addClass("current");
					}
				});
		}
	}
	
	var displayPage = function(position){
		var currentWidget = (Math.abs(position)/offset)+1;
		pageDisplay.html(currentWidget+" of "+numWidgets);
	}
	
	var lowerOpacity = function(obj){
		$(obj).css({ opacity: shadedOpacity, filter: shadedFilter });
	}
	
	var fullOpacity = function(obj){
		$(obj).css({ opacity: "1", filter: "alpha(opacity=100)" });
	}
	
	var getCurrentPosition = function(){
		var pos = itemList.css("left");
		var position = pos.substr(0,(pos.length-2));
		return position;
	}
	
	var autoRotate = function(){
		var position = getCurrentPosition();
		var newPosition;
		if (position == maxRight){
			newPosition = 0;
		} else {
			newPosition = parseInt(position) - offset;
		}
		animate(newPosition);
		self.ar = setTimeout(autoRotate, 5000);
	}
	
	var initNavigation = function(){
		if (viewIndicator){
			for (var i=0; i<numPages; i++){
				viewIndicator.append("<li></li>");
			}
			viewIndicator.children("li").eq(0).addClass("current");
		}
	
		lowerOpacity(navLeft);
	
//		navLeft.bind("click", self.previous);
		if (numPages != 1)
			navRight.bind("click", self.next);
		else
			lowerOpacity(navRight);
	}

	// PUBLIC
	this.previous = function(){
		var position = getCurrentPosition();
		var newPosition = parseInt(position) + offset;
		
		animate(newPosition);
	}
	
	this.next = function(){
		var position = getCurrentPosition();
		var newPosition = parseInt(position) - offset;
		
		animate(newPosition);
	}
	
	this.resizeScrollWindow = function(viewerWindow, widgetHeight){
		itemList.children("li").each(function(i){
			if ($(this).height() > widgetHeight){
				widgetHeight = $(this).height();
			}
		});
		viewerWindow.css("height", widgetHeight+"px");
	}
	
	this.goToWidget = function(widgetIndex){
		var widgetPos = parseInt(0 - (widgetIndex * (widgetWidth+marginWidth)));
		var currentPage = Math.floor(Math.abs(widgetPos/offset));
		var startPosition = parseInt(0 - (currentPage * offset));
		animate(startPosition);
		if (currentPage < 1){
			lowerOpacity(navLeft);
		} else if (startPosition == maxRight){
			fullOpacity(navLeft);
			navLeft.bind("click", self.previous);
			lowerOpacity(navRight);
			navRight.unbind("click");
		} else {
			fullOpacity(navLeft);
			navLeft.bind("click", self.previous);
		}
		
		return this;
	}
	
	this.initAutoRotate = function(widget){
		widget.bind("mouseover", function(){
			clearTimeout(self.ar);
		});
		widget.bind("mouseout", function(){
			self.ar = setTimeout(autoRotate,5000);
		});
		
		autoRotate();
	}
	
	initNavigation();
}
$.fn.newFeatureCallout = function(options) {
	var opts = $.extend({}, $.fn.newFeatureCallout.defaults, options);
		return this.each(function() {
			var $this = $(this);
			if (opts.style == '1') {
				var elementWidth = $this.width();
				var elementPaddingTop = $this.css("paddingTop");
				elementPaddingTop = parseInt(elementPaddingTop.substr(0,(elementPaddingTop.length-2)));
				$this.css("position", "relative")
					.prepend('<div class="newFeatureCallout flc"></div>')
					.find(".newFeatureCallout").html('<span>NEW!</span> <strong>'+options.headline+'</strong><p>'+options.copy+'</p><div class="pointer"></div>');
		
				var $calloutBox = $this.find(".newFeatureCallout");
				var calloutWidth = $calloutBox.width();
				var calloutHeight = $calloutBox.height();
				$calloutBox.css("width", calloutWidth+"px")
					.prepend('<a class="close"></a>')
					.find(".pointer").css({top: (calloutHeight+10)+"px", left: Math.floor(calloutWidth/2)+"px"});
				$calloutBox.css({top: "-"+(calloutHeight+elementPaddingTop+10)+"px", left: Math.floor((elementWidth-calloutWidth)/2)+"px"})
					.fadeIn("slow")
					.find(".close").bind("click",function(){
						$calloutBox.fadeOut("fast");												 
					});
			} else if (opts.style == '2') {
				$this.find(opts.childClassToPad).css("paddingLeft", "20px");
				$this.css("position", "relative")
					.prepend('<div class="newFlag"></div>');
				$this.find(".newFlag").css({top: "0px", left: "0px"});
			} else if (opts.style == '3') {
				$this.append('<small class="smallNewCallout">New!</small>');
				var $newTag = $this.find(".smallNewCallout");
				var elementFontSize = $this.css("fontSize");
				var tagFontSize = $newTag.css("fontSize");
				elementFontSize = parseFloat(elementFontSize, 10);
				tagFontSize = parseFloat(tagFontSize, 10);
				var difference = tagFontSize - elementFontSize;
				$newTag.css("top", difference+"px");
			}
		});
}
$.fn.newFeatureCallout.defaults = {
	style: '1',
	headline: 'HEADLINE HERE',
	copy: 'COPY HERE',
	childClassToPad: '.header'
}
$.fn.textResize = function(direction, options) {
	var opts = $.extend({}, $.fn.textResize.defaults, options);
	return this.each(function() {
		var $this = $(this);
		var currentSize = $this.css('fontSize');
		var num = parseFloat(currentSize, 10);
		var unit = currentSize.slice(-2);
		if (direction == 'bigger'){
			num = num * opts.stepSize;
		} else if (direction == 'smaller'){
			num = num / opts.stepSize;
		}
		$this.css({ fontSize: num + unit, lineHeight: "normal" });
	});
}
$.fn.textResize.defaults = {
	stepSize: 1.25
}
function jImageAnimation(container, imageAxisX, imageAxisY, speed, delay){
	var timeoutIds = [ null, null ];
	var imageIndex = 0;
			var self = this;
	
	function getBackgroundPosition(toggle){
		return { backgroundPosition: imageAxisX[toggle ? 1 : 0] + ' ' + imageAxisY[imageIndex] };
	}
	
	container = jQuery(container).css({ backgroundPosition: imageAxisX[0] + ' ' + imageAxisY[0] });
	speed = speed || 600;
	delay = delay || 8000;
	
	self.stop = function(){
		container.stop(true);
		clearTimeout(timeoutIds[1]);
		clearTimeout(timeoutIds[0]);
		
		imageIndex = 0;
		
		return self;
	};
	self.start = function(){
		self.stop();

		(function startAnimation(){
			container.animate(getBackgroundPosition(true), speed, 'swing', function(){
				timeoutIds[1] = setTimeout(function(){
					container.animate(getBackgroundPosition(false), speed, 'swing');
					imageIndex++;
					
					if(imageIndex >= imageAxisY.length)
							imageIndex = 0;
				}, delay - (speed * 2));
			});
					
			timeoutIds[0] = setTimeout(startAnimation, delay);
		})();
		
		return self;
	};
	self.dispose = function(){
		self.stop();
		
		for(var property in self)
			delete self[property];

		return self = null;
	};
}
function jCountdownTimer(targetTime, currentTime, baseUnit){
	/*
	DESCRIPTION
		Countdown Timer

		Parameters
			1) (Required) Target date and time (String)
			2) (Required) Current date and time (String)
			3) (Optional) Unit of time to display (String)
	DEPENDIENCIES
		
	USAGE
		>>> var myCountdownTimer = new jCountdownTimer('1/1/2010', '1/1/2009', 'days');
		>>> myCountdownTimer.getTimeDifference().days
		365
		>>> myCountdownTimer.getBaseUnit()
		"days"
	*/
	
	// private properties
	var self = this;
	var DAY = 60 * 60 * 24;
	var HOUR = 60 * 60;
	var MINUTE = 60;
	var SECOND = 1000;
	var listenerTimeoutIdArray = new Array();
	var listenerFunctionArray = new Array();
	var clockTimeoutId = null;
	var currentTime = currentTime ? new Date(currentTime) : new Date();;
	var targetTime = targetTime ? new Date(targetTime) : currentTime;
	var baseUnits = ['days','hours','minutes','seconds'];
	
	// public properties
	self.baseUnit = typeof baseUnit === Number.type && baseUnit >=0 && baseUnit <=3
		? baseUnits[baseUnit]
		: baseUnit || baseUnits[0];

	// public methods
	self.getBaseUnit = function(index){ return baseUnits[index||0]; };
	self.getCurrentTime = function(){ return currentTime || null; };
	self.getTargetTime = function(){ return targetTime || null; };
	self.getTimeDifference = function(){
		var _difference = (targetTime - currentTime) / SECOND;
		var _time = { days: 0, hours: 0, minutes: 0, seconds: 0 };
		
		if(_difference <= 0)
			return _time;
		
		_time.days = Math.floor(_difference / DAY);
		_time.hours = Math.floor((_difference - _time.days * DAY) / HOUR);
		_time.minutes = Math.floor((_difference - _time.days * DAY - _time.hours * HOUR) / MINUTE);
		_time.seconds = Math.floor((_difference - _time.days * DAY - _time.hours * HOUR - _time.minutes * MINUTE));
		
		switch(self.baseUnit){
			case 1:
			case 'hours':
				_time.hours += _time.days * 24;
				_time.days = 0;
				break;
			case 2:
			case 'minutes':
				_time.minutes += _time.days * 24 * 60 + _time.hours * 60;
				_time.days = _time.hours = 0;
				break;
			case 3:
			case 'seconds':
				_time.seconds = _difference;
				_time.days = _time.hours = _time.minutes = 0;
				break;
		}
		
		return _time;
	};
	self.addEventListener = function(fn){
		var _id = listenerTimeoutIdArray.length == 0 ? 0 : listenerTimeoutIdArray.length - 1;
		
		listenerFunctionArray.push(fn);
		listenerTimeoutIdArray.push((function listen(){
			fn(self.getTimeDifference(),_id);
			listenerTimeoutIdArray[_id] = setTimeout(listen,SECOND);
		})());
		
		return self;
	};
	self.removeEventListener = function(id){
		if(id)
			clearInterval(listenerTimeoutIdArray[id]);
		else
			for(var i = 0, n = listenerTimeoutIdArray.length; i < n; i++)
				clearInterval(listenerTimeoutIdArray.pop());
		
		return self;
	};
	self.stop = function(){
		self.removeEventListener();
		clearTimeout(clockTimeoutId);
		
		return self;
	};
	self.start = function(){
		self.stop();

		(function startClock(){
			currentTime.setSeconds(currentTime.getSeconds() + 1);
			
			clockTimeoutId = setTimeout(startClock, SECOND);
		})();
		
		for(var i = 0, n = listenerFunctionArray.length; i < n; i++)
			self.addEventListener(listenerFunctionArray[i]);
		
		return self;
	};
	self.dispose = function(){
		self.stop();
		
		for(var property in self)
			delete self[property];
		
		return self = null;
	};
}
function Querystring(uri){
	/*
	DESCRIPTION
		Querystring Parser

		Parameters
			1) (Required) URI (String)
	DEPENDIENCIES
		String.prototype.trim
		String.isNullOrEmpty
		String.empty
	USAGE
		>>> var myQuerystring = new Querystring('http://myQuerystring.com/?fu=bar');
		>>> myQuerystring.getField('fu');
		"bar"
		>>> myQuerystring.toString()
		"http://myQuerystring.com/?fu=bar"
	*/

	// private properties
	var self = this;
	var query = new Object();
	var splitUri = (uri || location.toString()).trim().replace(/\+/g,' ').split('?');

	// public properties
	self.path = splitUri[0];
	
	// public methods
	self.contains = function(field){
		return !String.isNullOrEmpty(query[field]);
	};
	self.deleteField = function(field){
		delete query[field];
		return self;
	};
	self.setField = function(field, value){
		if(typeof field !== String.type || !field.length || typeof value === 'undefined')
			throw dlabs.exceptions.invalidArgument;
			
		query[field] = value.toString();

		return self;
	};
	self.getField = function(field){
		return query[field];
	};
	self.toString = function(){
		var _fieldValuePairs = new Array();
		
		for(var field in query)
			_fieldValuePairs.push(field + '=' + query[field]);

		return self.path + '?' + _fieldValuePairs.toString().replace(/,/g,'&');
	};
	self.dispose = function(){
		for(var property in self)
			delete self[property];
		
		return self = null;
	};

	return (function(){
		if(!splitUri[1])
			return;
			
		var _fieldValuePairs = splitUri[1].split('&');
		
		if(!_fieldValuePairs.length)
			return;
		
		for(var i = 0, n = _fieldValuePairs.length; i < n; i++){
			var _fieldValuePair = _fieldValuePairs[i].split('=');

			query[decodeURIComponent(_fieldValuePair[0])] = _fieldValuePair.length == 2
				? decodeURIComponent(_fieldValuePair[1])
				: String.empty;
		}
	})();
}
function HoverFx(triggerSelector, containerSelector){
	/*
	DESCRIPTION
		Hover Effect Builder
		
		Parameters
			1) (Required) CSS selector (String) or jQuery element (Object)
			2) (Required) CSS selector (String) or jQuery element (Object)
	DEPENDIENCIES
		jQuery
	USAGE
		var myHoverEffect = new HoverFx('.MyHoverEffectTrigger', 'MyHoverEffectContainer');
		myHoverEffect.start();
	TODO
		1) add unit test
	*/
	
	// private properties
	var self = this;
	var timeoutId = null;
	
	// private methods
	function hideContainer(){ self.container.slideUp(300); }
	
	// public properties
	self.trigger = jQuery(triggerSelector);
	self.container = jQuery(containerSelector);
	
	// public methods
	self.start = function(){
		self.trigger
			.mouseover(function(){
				clearTimeout(timeoutId);
				
				if(self.container.css('display') == 'none')
					self.container.slideDown(400);	
			})
			.mouseout(function(){ 
				timeoutId = setTimeout(hideContainer, 800);
			});
		
		self.container
			.mouseover(function(){ clearTimeout(timeoutId); })
			.mouseout(function(){ timeoutId = setTimeout(hideContainer, 800);
		});
	};
	self.dispose = function(){
		for(var property in self)
			delete self[property];
		
		return self = null;
	};
}
function Faceroll(selector, uri){
	/*
	DESCRIPTION
		Faceroll Builder

		Parameters
			1) (Required) CSS selector (String) or jQuery element (Object)
			2) (Optional) URI for ajax calls (String)
	DEPENDIENCIES
		jQuery
		Querystring
		SiteLifeAvatars
		String.isNullOrEmpty
	USAGE
		var myFaceroll = new Faceroll('.MyFaceroll');
		myFaceroll.start();
		
		var myAjaxFaceroll = new Faceroll('.MyFaceroll', { uri: '/myfaceroll/ajax.aspx?page=1' });
		myAjaxFaceroll.getPage(1);
	TODO
		1) add unit test
		2) prototype to jQuery plugin
		3) add support for global and local default options
		4) add support for callbacks (i.e. onRequest, onHover, ...)
	*/
	
	// private properties
	var self = this;
	var xhr = null;
	var timeoutId = null;
	var facerollElements = new Array();
	var $container = jQuery(selector);
	var $magnifier = jQuery('<div class="FacerollMagnifier"></div>')
		.appendTo('body');
	var $anchor = jQuery('<a></a>')
		.appendTo($magnifier);
	var $avatar = jQuery('<img />')
		.appendTo($anchor);	
	
	// public properties
	self.uri = uri;
	
	// public methods
	self.start = function(selector){
		var _timeoutId = null;
		var _$faceroll = selector
			? jQuery(selector).find('a')
			: $container.find('a')
			.unbind('mouseover.faceroll')
			.bind('mouseover.faceroll',function(){
				var _$this = jQuery(this);
				var _$avatar = _$this.find('img');
				var _position = _$this.offset();
				var _avatarUrl = _$avatar.attr('src');

				if(String.isNullOrEmpty(_avatarUrl))
					return;
					
				_position.top -= 10;
				_position.left -= 10;

				$avatar
					.attr('src', _avatarUrl)
					.attr('alt', _$avatar.attr('alt')).attr('title', _$avatar.attr('alt'));
				$anchor.attr('href', _$this.attr('href'));
				$magnifier.css(_position).show();
			});

		$magnifier
			.mouseout(function(){ _timeoutId = setTimeout(function(){ $magnifier.fadeOut(); }, 500); })
			.mouseover(function(){ clearTimeout(_timeoutId); });
		
		return self;
	};
	self.getPage = function(pageNumber, fn){
		if(xhr || !self.uri)
			return self;

		var _webServiceQuery = new Querystring(self.uri)
			.setField('page', pageNumber || '1');
			
		$container.addClass('Processing');
		jQuery(facerollElements).fadeTo(200,0);
		setTimeout(function(){
			xhr = jQuery.getJSON(_webServiceQuery.toString(), function(response){			
				if(!response || !response.count)
					return response = xhr = null;

				jQuery(facerollElements).remove();
				jQuery(response.users).each(function(i,e){ // loop through users
					var _$element = jQuery('<a class="userAvatar avatarMedium"></a>')
						.attr('title', e.username)
						.attr('href', e.url)
						.css('opacity', 0)
						.appendTo($container);

					facerollElements.push(_$element[0]);
				});

				if(SiteLifeAvatars.HasExecuted()){
					(function getAvatars(){
						SiteLifeAvatars.IsComplete()
							? SiteLifeAvatars.Request(function(){
								jQuery(facerollElements).fadeTo(200,1)
								self.start();
								clearTimeout(timeoutId);
								setTimeout(function(){
									$container.removeClass('Processing');

									if(typeof fn === Function.type)
										fn($container, response);
									
									xhr = null;
								}, 200);
							})
							: timeoutId = setTimeout(getAvatars, 200);
					})();
				}
			});
		},200);
		
		return self;
	};
	self.dispose = function(){
		for(var property in self)
			delete self[property];
		
		return self = null;
	};
	
	return (function(){
		$container.find('a').each(function(i, e){ facerollElements.push(e); });
	})();
}
function MessageConsole(selector, defaultValue, options){
	/*
	DESCRIPTION
		Message Console

		Parameters
			1) (Required) CSS selector (String) or jQuery element (Object)
			2) (Required) default message (String)
			3) (Optional) options (i.e. animation speed) (Object)
	DEPENDIENCIES
		jQuery
		String.empty
		dlabs.exceptions.invalidArgument
	USAGE
		var myMessageConsole = new MessageConsole('.MyFaceroll', 'Hello World!');
		myFaceroll.update('Note', 1);
		myFaceroll.update('Important', 2);
		myFaceroll.update('Success', 3);
		myFaceroll.update('Critical', 4);
	TODO
		1) add unit test
		2) prototype to jQuery plugin
		3) add support for global and local default options
	*/
	var self = this;
	var $container = jQuery(selector);
	var timeoutId = null;
	var isBusy = false;
	var currentPriority = -1;
	var currentValue = String.empty;
	var classNames = new Array();
	var defaults = {
		speed: 200,
		timeout: 30000,
		opacity: 0.33
	};
	
	function parseClass(priority){
		switch(priority){
			case 4: return 'Critical';
			case 3: return 'Success';
			case 2: return 'Important';
			case 1: return 'Note';
		}
		
		return typeof priority === String.type
			? priority
			: String.empty;
	}
	
	self.reset = function(priority){
		return self.update(defaultValue, priority);
	};
	self.update = function(value, priority){
		clearTimeout(timeoutId);
		
		if((value === currentValue && priority === currentPriority) || (isBusy && priority < currentPriority))
			return self;

		var _animationQueue = $container.queue();

		if(_animationQueue.length > 2)
			$container.queue([ _animationQueue[0] ]);
		
		$container.each(function(i){
			var _$this = jQuery(this);

			_$this.fadeTo(options.speed, 0, function(){
				this.className = classNames[i];
				
				_$this.html(value)
					.addClass(parseClass(priority))
					.fadeTo(options.speed, 1, function(){ isBusy = false; });
			});
		});
		
		isBusy = true;
		currentPriority = priority;
		currentValue = value;
		timeoutId = setTimeout(function(){
			$container.fadeTo(options.speed * 3, options.opacity);
		}, options.timeout);
		
		return self;
	};
	self.dispose = function(){
		for(var property in self)
			delete self[property];
		
		return self = null;
	};
	
	return (function($){
		if($container.length === 0)
			throw dlabs.exceptions.invalidArgument;
		
		options = $.extend({ }, defaults, options);
		
		$container.each(function(){
			classNames.push(this.className);
		});
	})(jQuery);
}
function LoginBox(){
	
}
function SearchBox(options){
	var self = this;
	
	self.types					= ['Articles','Resources','Experts','Members','Videos','Web'];
	self.typeDictionary         = {Articles: 0, Resources: 2, Experts: -1, Memebers: 3, Videos: 4, Web: 5};
	self.altTabClassName		= options.altTabClassName		|| String.empty;
	self.altBlurBackground		= options.altBlurBackground		|| '#ffffff';
	self.altBlurValue			= options.altBlurValue			|| 'Search eHow.com';
	self.blurValue				= options.blurValue				|| String.empty
	self.blurColor				= options.blurColor				|| '#8A9AA6';
	self.blurBackground			= options.blurBackground		|| '#ffffff url('+dlabs.settings.urls.media+'/ui/images/google_custom_search_watermark.gif) no-repeat scroll left center';
	self.focusColor				= options.focusColor			|| '#8A9AA6';
	self.focusBackground		= options.focusBackground		|| '#ffffff';
	self.selectedTabClassName	= options.selectedTabClassName	|| 'selected';
	self.selectedTabElement		= options.selectedTab			|| null;
	self.formElement			= options.form					|| null;
	self.typeElement			= options.typeInput				|| null;
	self.inputElement			= options.input					|| null;
	
	if(self.selectedTabElement)
		jQuery(self.selectedTabElement)
			.addClass(self.selectedTabClassName);
	if(self.inputElement)
		jQuery(self.inputElement)
			.unbind('focus.SearchBox')
			.bind('focus.SearchBox', function(){ self.focus(); })
			.unbind('blur.SearchBox')
			.bind('blur.SearchBox', function(){ self.blur(); });
	if(options.selectedTab)
		jQuery(options.selectedTab).siblings('.Tab').andSelf()
			.unbind('click.SearchBox')
			.bind('click.SearchBox', function(){ self.switchTab(this); });
	if(options.button)
		jQuery(options.button)
			.unbind('click.SearchBox')
			.bind('click.SearchBox', function(){ self.submit(); });
	self.blur();
}
SearchBox.prototype.submit = function(){
	var self = this;

	if(String.isNullOrEmpty(self.inputElement.value) || self.inputElement.value == self.blurValue || self.inputElement.value == self.altBlurValue)
		return self.blur();

	self.formElement.submit();
	
	return self;
};
SearchBox.prototype.focus = function(){
	var self = this;
	
	if(self.inputElement.value == self.blurValue || self.inputElement.value == self.altBlurValue)
		self.inputElement.value = String.empty;
	
	self.inputElement.style.background = self.focusBackground;
	self.inputElement.style.color = self.focusColor;
	
	return self;
};
SearchBox.prototype.blur = function(){
	var self = this;
	
	if(String.isNullOrEmpty(self.inputElement.value) || self.inputElement.value == self.blurValue || self.inputElement.value == self.altBlurValue){
		var hasAltTabClassName = self.selectedTabElement && self.selectedTabElement.className.indexOf(self.altTabClassName) !== -1;
		
		self.inputElement.style.background = hasAltTabClassName ? self.altBlurBackground : self.blurBackground;
		self.inputElement.value = hasAltTabClassName ? self.altBlurValue : self.blurValue;
	}
	
	self.inputElement.style.color = self.blurColor;
	
	return self;
};
SearchBox.prototype.switchTab = function(tabElement, allowAutoSubmit){
	var self = this;

	self.selectedTabElement = tabElement;
	self.typeElement.value = (function(classNames){
		for(var n = classNames.length, i = self.types.length; i > 1; i--)
			for(var a = 0; a < n; a++)
				if(classNames[a] == self.types[i])
				{
					$(self.typeElement).val(i);
					return i.toString();
				}
	})(tabElement.className.split(String.whiteSpace)) || '0';
	
	jQuery(tabElement).addClass(self.selectedTabClassName).siblings().removeClass(self.selectedTabClassName);
	
	return self.submit();
};

dlabs.utils.AddThis = (function(){
	var timeoutId = null;

	return {
		open: function(element, type, delay){
			if(typeof addthis_open !== Function.type)
				throw dlabs.exceptions.nullReference;

			clearTimeout(timeoutId);
			
			timeoutId = setTimeout(function(){
				addthis_open(element, type || '', '[URL]', '[TITLE]');
			}, delay || 250);

			return false;
		},
		close: function(){
			if(typeof addthis_close !== Function.type)
				throw dlabs.exceptions.nullReference;

			clearTimeout(timeoutId);
			addthis_close();

			return false;
		},
		prompt: function(){
			if(typeof addthis_close !== Function.type || typeof addthis_sendto != Function.type)
				throw dlabs.exceptions.nullReference;
			
			clearTimeout(timeoutId);
			addthis_close();
			addthis_sendto();

			return false;									
		},
		bind: function(selector, type, delay){
			var self = this;
			
			jQuery(selector)
				.bind(options.open, function(){ return self.open(this, type, delay); })
				.bind(options.close, function(){ return self.close(); })
				.bind(options.prompt, function(){ return self.prompt(); });

			return self;
		}
	};
})();

dlabs.utils.PrettyDate = (function(){

	var getPrettyDate = function(time) {
		var date = new Date((time || "").replace(/-/g,"/").replace(/[TZ]/g," ")),
			diff = (((new Date()).getTime() - date.getTime()) / 1000),
			day_diff = Math.floor(diff / 86400);
				
		if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 )
			return time;
				
		return day_diff == 0 && (
				diff < 60 && "just now" ||
				diff < 120 && "1 minute ago" ||
				diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||
				diff < 7200 && "1 hour ago" ||
				diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
			day_diff == 1 && "Yesterday" ||
			day_diff < 7 && day_diff + " days ago" ||
			time
	}


	return {
		execute: function() {
			jQuery(".PrettyDate").each(function() {
				var prettyDate = getPrettyDate(jQuery(this).html());
				jQuery(this).html(prettyDate);
			});
		},

		getPrettyDate: function(time) {
			return getPrettyDate(time);
		}
	};
})();

(function($){
  var templateCache = {};
  $.fn.template = function tmpl(template, data){
    var fn = !/\W/.test(template) ?
      templateCache[template] = templateCache[template] ||
        tmpl(document.getElementById(template).innerHTML) :
      new Function("obj",
        "var p=[],print=function(){p.push.apply(p,arguments);};" +
        "with(obj){p.push('" +
        template
          .replace(/[\r\t\n]/g, "")
          .split("{!").join("\t")
          .replace(/((^|!})[^\t]*)'/g, "$1\r")
          .replace(/\t=(.*?)!}/g, "',$1,'")
          .split("\t").join("');")
          .split("!}").join("p.push('")
          .split("\r").join("\\'")
      + "');}return p.join('');");
    return data ? this.html(fn( data )) : fn;
  };
})(jQuery);

var Now = new function() {
	var _displayCount = 3,
		_displayInterval = 5000;
	var _initialDelay = 2000;
	var _elementID, _timer, _activityList;			
	
	this.Start = function(ElementID) {				
		setTimeout(function() {
			Now._elementID = ElementID;
			Now._activityList = $("#" + Now._elementID);
			
			$("#" + Now._elementID).bind("mouseenter",function(){
			  clearInterval(_timer);
			}).bind("mouseleave",function(){
			  Now.Next();
			});
			
			_timer = setInterval("Now.Next()", _displayInterval);
		}, _initialDelay);
	}

	this.Next = function() {
		clearInterval(_timer);
		
		var elem = Now._activityList.children("li:last");
		var cb = function() {
			Now._activityList.prepend(elem);
			if ($.browser.msie6)
				elem.show();
			else
				elem.slideDown();					
		};
		elem.hide(cb);
			
		_timer = setInterval("Now.Next()", _displayInterval);
	}
};

var PreviewBox = function(){
	var _timer;
	var _data = {};
	var _lastUrl = '';
	
	var _itemRegEx = [
//		{pattern:/how_([0-9]+?)_/gi, url:"/ajax/article.aspx?article_id="},
//		{pattern:/members/([^\.]+?)\.html/gi, url:"/ajax/user.aspx?username="}
		];

	var _templates = {
		Article:'<img src="{3}" />'
			+ '<h3><a href="{0}">{1}</a></h3>'
			+ '<span>by {5}</span>'
			+ '{2}'
			,
		User:'<h3><a href="{0}">{1}</a></h3>'
			+ '<span>by {5}</span>'
			+ '{2}'
		};

	function renderData(Data)
	{
		if(Data)
		{
			var output = '', item = {};
			if(Data.article)
			{
				item = Data.article;
				output += formatString(
					_templates.Article,
					item.url,
					item.title,
					item.introduction,
					item.thumbnailUrl,
					item.publishedDate,
					item.author.displayName,
					item.author.username
					);
			}
			
			$("#previewBox").html(output);
		}
	};
	
	function formatString(Input)
	{
		for(var a = 1, cnt = arguments.length; a < cnt; a++)
			Input = Input.replace(new RegExp("\\{" + (a - 1) + "\\}", "gi"), arguments[a]);
		return Input;	
	};
	
	function parse(Url)
	{
		if(Url)
		{
			var tmpData = _data[Url];
			if(tmpData)
			{
				renderData(tmpData);
			}
			else
			{
				var ajaxUrl = null;
				for(var a = 0, cnt = _itemRegEx.length; a < cnt; a++)
				{
					var match = new RegExp(_itemRegEx[a].pattern).exec(Url);
					if(match)
					{
						ajaxUrl = _itemRegEx[a].url + match[1];
						break;
					}
				}

				if(ajaxUrl && ajaxUrl.length > 0)
				{
					_lastUrl = Url;
					$.getJSON(ajaxUrl + "&r=" + Math.floor(Math.random() * 10000), function(data)
					{
						$("#previewBox").html("requesting...");
						PreviewBox.SetAndRender(data);
					});
				}
				else
				{
					OnMouseOut();
				}
			}
		}
	};
	
	return {
		InitLinks: function(ClassName)
		{
			var links = $("." + ClassName);
			links.unbind("mouseover", PreviewBox.HrefOnMouseOver);
			links.unbind("mouseout", PreviewBox.OnMouseOut);
			links.mouseover(PreviewBox.HrefOnMouseOver);
			links.mouseout(PreviewBox.OnMouseOut);
			
			var box = $("#previewBox");
			box.unbind("mouseover", PreviewBox.BoxOnMouseOver);
			box.unbind("mouseout", PreviewBox.OnMouseOut);
			box.mouseover(PreviewBox.BoxOnMouseOver);
			box.mouseout(PreviewBox.OnMouseOut);
		},
		HrefOnMouseOver: function(e)
		{
			var box = $("#previewBox");
			clearTimeout(_timer);

			box.html("loading...");
			parse(this.href);
		
			var newX = e.pageX + 20 +'px',
				newY = e.pageY + 10 +'px';
			box.css({left: newX, top: newY});
			if(box.css("display") == 'none')
				box.fadeIn("fast");
		},
		BoxOnMouseOver: function(e)
		{
			clearTimeout(_timer);
		},
		OnMouseOut: function()
		{
			_timer = setTimeout('$("#previewBox").hide()', 50);
		},
		SetAndRender: function(Data)
		{
			_data[_lastUrl] = Data;
			renderData(Data);
		}
	};
}();
var services = {};
