/* begin MiniStats */
(function($)
{	
	// constructor
	function MiniStats(root, conf)
	{	
		// Private fields ------------------------------------------------------------------
	
		var _root = $(root),
			_domElement = _root[0],
			_self = this,
			_opts = {
				debug: true
			}
			;
			$.extend(_opts, conf);
	
		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			debug: function(str)
			{
				if (_opts.debug == true) {
					try {
						console.log("str: " + str);
					} 
					catch (e) {
						alert("str: " + str);
					}
				}
			}
		});
	
		// Private methods -----------------------------------------------------------------
	
		function init()
		{	
			var rows = _root.find("table > tbody > tr");
			rows.hover(
				function () {
					$(this).addClass("on");
				}, 
				function () {
					$(this).removeClass("on");
				}

			)
		};
	
		// Initialization ------------------------------------------------------------------
		init();
	};

	// jQuery plugin implementation
	$.fn.miniStats = function(conf)
	{
		var opts = {};
		$.extend(opts, conf);
		
		this.each(function()
		{
			var $instance = new MiniStats($(this), opts);
		});
		return this; 
	};
})(jQuery);
/* end MiniStats */
(function($)
{	
	// constructor
	function SportsnetPage(conf)
	{	
		// Private fields ------------------------------------------------------------------
		var _self = this,
			_initQueue = [],
			_initObjectUIDCount = 0,
			_tickIntervalID,
			_curInitObject,
			_curState = "paused",
			_rankMap = {
				CORE: 0, //page starters and core functions (e.g., cookie checker); keep in mind - making everything core defeats the purpose :)
				PAGE_MAJOR: 1, //page elements that need to be shown immediately (e.g., top story)
				PAGE_MINOR: 2, //page elements lower on page, or having initial state that shows content (e.g., scrollers, polls)
				NAV: 3, //site navigation (may be counter-intuitive to have under page content, but usually users are here to browse first)
				AJAX: 4,
				DISPLAY: 5 //less noticable display functions that add polish/details (e.g., ellipsis)
			},
			_opts = {
				debug: false
			}
			;
			$.extend(_opts, conf);
	
		// Public methods ------------------------------------------------------------------
		$.extend(_self, {
			registerInit: function(initObj)
			{
				//{_expression:"p", _contextExpression:"#pHolder", _functionRef:"testFunc", _data:{}, _rank:"PAGE_MAJOR"}
				if (initObj._rank == undefined || _rankMap[initObj._rank] == undefined) {
					initObj._rank = "DISPLAY";
				}
				addToQueue(initObj);
			},
			play: function()
			{	
				if (_curState == "paused") {
					_curState = "playing";
					startTicking();
				}
			},
			pause: function()
			{	
				_curState = "paused";
				stopTicking();
			},
			executeInit: function()
			{
				executeNextInit();
			},
			printQueue: function()
			{
				printQueue();
			}
		});
	
		// Private methods -----------------------------------------------------------------
		function initSubQueues()
		{
			//creates a nested array in _initQueue for each of the ranks, at the index associated with the rank
			//e.g., CORE objects array is index 0 in _initQueue
			for (var curRank in _rankMap) {
				_initQueue[_rankMap[curRank]] = [];
			}
		};
		
		function addToQueue(initObj)
		{
			if (objectIsInQueue(initObj) == false) {
				var targetArrayName = initObj._rank;
				var targetArray = _initQueue[_rankMap[targetArrayName]];
				var oldLen = targetArray.length;
				targetArray.push(initObj);
				debug("## addToQueue ADDED item (_expression: " + initObj._expression + "); items in " + targetArrayName + ": " + targetArray.length + " (was " + oldLen + ")");
			} else {
				debug("## addToQueue DID NOT ADD item with _expression: " + initObj._expression + "; item already exists");
			}
		};
		
		function executeInit()
		{
			//always acts on _curInitObject
			//printObjectProps(_curInitObject);
			var funcExists = $.fn[_curInitObject._functionRef] != undefined;
			if (funcExists == true) {
				//the timeout's to make fireFunction() start its own call stack (can't pass params to setTimeout in IE, so arbitrary function it is)
				setTimeout(function(){
					fireFunction(_curInitObject);
				}, 0);
			}
			else {
				debug("## executeInit; DID NOT FIRE; function not found (_functionRef: '" + _curInitObject._functionRef + "')");
				onExecuteInitComplete();
			}
		};
		
		function fireFunction(initObj)
		{
			var start = new Date().getTime();
			var jqParams = [initObj._expression];
			if (initObj._contextExpression != undefined) {
				var contextJQ = $(initObj._contextExpression);
				jqParams.push(contextJQ);
			}
			var jqResultSet = $.apply($, jqParams);
			jqResultSet[initObj._functionRef](initObj._data);
	
			var end = new Date().getTime();
			var timeToExecute = end - start;
			debug("## executeInit>fireFunction (" + _curInitObject._functionRef + "); timeToExecute: " + timeToExecute);
			
			onExecuteInitComplete();
		};
				
		function onExecuteInitComplete()
		{
			//debug("## onExecuteInitComplete; continuing...");
			setTimeout(executeNextInit, 0); //the timeout's to break out of the call stack
		};
		
		function executeNextInit()
		{
			_curInitObject = getNextInitObject();
			if (_curInitObject == undefined) {
				debug("## executeNextInit - no more initObjects available");
			
				postProcessPage();
			}
			else {
				//test to see if context or element is ready (just need to test one, if context exists, element must)
				var jqObj = _curInitObject._contextExpression != undefined ? $(_curInitObject._contextExpression) : $(_curInitObject._expression);
				var jqObj = jqObj != undefined;
				if (jqObj != undefined) {
					executeInit();
				}
				else {
					debug("## executeNextInit; element/context doesn't exist; not executing and continuing...");
					onExecuteInitComplete();
				}
			}
		};
		
		function getNextInitObject()
		{
			var curObj;
			for (var i=0; i<_initQueue.length; i++) {
				var curArray = _initQueue[i];
				curObj = curArray.shift();
				if (curObj != undefined) break;
			}
			return curObj;
		};
		
		function objectIsInQueue(testObj)
		{
			var isInQ = false;
			for (var curRank in _rankMap) {
				var curSubQueue = _initQueue[_rankMap[curRank]];
				for (var i = 0; i < curSubQueue.length; i++) {
					var curIObj = curSubQueue[i];
					var sameExpr = curIObj._expression == testObj._expression;
					var sameContext = curIObj._contextExpression == testObj._contextExpression;
					var sameFunc = curIObj._functionRef == testObj._functionRef;
					var sameData = haveSameData(curIObj, testObj);
					isInQ = sameExpr && sameContext && sameFunc && sameData;
					if (isInQ == true) break;
				}
				if (isInQ == true) break;
			}
			return isInQ;
		};
		
		function haveSameData(testObj1, testObj2){
			//NOTE: this does not recurse - meant for testing primitive values in options object passed to constructor
			var haveSameData = true;
			//if both are null or undefined, we're done
			var obj1HasData = testObj1._data != undefined && testObj1._data != null;
			var obj2HasData = testObj2._data != undefined && testObj2._data != null;
			var bothHaveData = obj1HasData && obj2HasData;
			if (bothHaveData) {
				for (var curProp in testObj1._data) {
					//debug("testing data " + curProp + "; testObj1: " + testObj1._data[curProp] + "; testObj2:" + testObj2._data[curProp]);
					var isMatch = testObj1._data[curProp] == testObj2._data[curProp];
					//debug("isMatch: " + isMatch);
					if (isMatch == false) {
						haveSameData = false;
						break;
					}
				}
			}
			else {
				haveSameData = obj1HasData == obj2HasData;
			}
			return haveSameData;
		};
		
		function printQueue()
		{
			debug("-------------------\nprintQueue...");
			for (var curRank in _rankMap) {
				var curSubQueue = _initQueue[_rankMap[curRank]];
				debug(curRank + " (" + curSubQueue.length + ")");
				for (var i = 0; i < curSubQueue.length; i++) {
					var curIObj = curSubQueue[i];
					debug(" - _expression: " + curIObj._expression + ", _contextExpression: " + curIObj._contextExpression + ", _functionRef: " + curIObj._functionRef + ", _data: " + curIObj._data);
				}
			}
			debug("done\n-------------------");
		};
		
		function debug(str)
		{
			if (_opts.debug == true) {
				try {
					trace(str);
				} 
				catch (e) {
					alert("debug: " + str);
				}
			}
		};
			
		// generic binding function
		function bind(name, fn)
		{
			if ($.isFunction(fn) == false)
				return;
				
			$(_self).bind(name, fn);
		};
	
		function postProcessPage()
		{
			//run any functions we need to have happen on page load
			
			//reposition columnist image if necessary
			var copyHolder = $("div.column-page-heaader");
			if (copyHolder.height() > 80) { //magic number - any taller and the image shows space below, AND MUST BE MOVED!
				var titleHolder = $("div.opinion-page-header");
				var imageHolder = $("div.columnist-header-pic");
				var yOffset = $.browser.msie6 ? 0 : 3; //magic number (except for ie6?) - 2 for margin-top, 1 for extra pixel in image cropped by div
				var targetTop = copyHolder.offset().top + copyHolder.height() - imageHolder.height() - yOffset;
				imageHolder.css({
					top: targetTop
				});
			}
		};
	
		function init()
		{
			initSubQueues();
		};
	
		// Initialization ------------------------------------------------------------------
		init();
	};
	
	// jQuery plugin implementation
	$.fn.sportsnetPage = function(opts)
	{
		return new SportsnetPage(opts);
	};
})(jQuery);

var sportsnetPage =  $.fn.sportsnetPage({});
(function($)
{	
	// constructor
	function TopNavMenu(root, conf)
	{	
		// Private fields ------------------------------------------------------------------
	
		var _root = $(root),
			_domElement = _root[0],
			_self = this,
			_hotspot = _root.parent(),
			_menu,
			_hideTimer,
			_showWait = 150,
			_hideWait = 250,
			_animDur = 150,
			_menuHeight,
			_positionLeft = "default", //hotspot-left 
			_positionTop = "default", //hotspot-top 
			_opts = {
				debug: false
			}
			;
			$.extend(_opts, conf);
	
		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			toggleMenu: function()
			{
				if (_root.hasClass("on")) {
					_self.debug("calling closeMenu");
					_self.closeMenu();
				}
				else {
					_self.debug("calling doMouseEnter");
					_self.doMouseEnter();
				}
			},
			positionMenu: function()
			{
				if (_menu.hasClass("body-flyout") && _menu.parent()[0].tagName != "BODY") {
					_self.debug("moving menu element to end of document body");
					$("body").append(_menu); //move in-body flyout to end of body (if it's not there already) to avoid messy cascading styles
				}
				
				if (_positionLeft != "default") {
					var targetX;
					switch (_positionLeft) {
						case "hotspot-left":{
							targetX = _hotspot.offset().left;
							break;
						}
						case "hotspot-right":{
							targetY = _hotspot.offset().left + _hotspot.outerWidth();
							break;
						}
					}
					_self.debug("setting left position: " + targetX);
					_menu.css({
						left: targetX
					});
				} else {
					_self.debug("using default _positionLeft");
				}
				if (_positionTop != "default") {
					var targetY;
					switch (_positionTop) {
						case "hotspot-top":{
							targetY = _hotspot.offset().top;
							break;
						}
						case "hotspot-bottom":{
							targetY = _hotspot.offset().top + _hotspot.outerHeight();
							break;
						}
					}
					_self.debug("setting top position: " + targetY);
					_menu.css({
						top: targetY
					});
				} else {
					_self.debug("using default _positionTop");
				}
			},
			openMenu: function()
			{
				if (_root.hasClass("on") == false) {
					_self.debug("openMenu");
					_self.positionMenu();
					_menu.show();
					_menu.animate({height:_menuHeight}, _animDur, "swing", function() { _self.onOpen(); });
				}
			},
			onOpen: function()
			{
				_self.debug("onOpen");
				_root.addClass("on");
			},
			closeMenu: function()
			{
				_self.debug("closeMenu");
				_menu.animate({height:"0px"}, _animDur, "swing", function() { _self.onClose(); });
			},
			onClose: function()
			{
				_self.debug("onClose");
				_menu.hide();
				_root.removeClass("on");
			},
			doMouseEnter: function()
			{
				_self.debug("doMouseEnter");
				clearTimeout(_hideTimer);
				_hideTimer = setTimeout(function(){
					_self.openMenu();
				}, _showWait);
			},
			doMouseLeave: function()
			{
				_self.debug("doMouseLeave");
				clearTimeout(_hideTimer);
				_hideTimer = setTimeout(function(){
					_self.closeMenu();
				}, _hideWait);
			},
			debug: function(str)
			{
				if (_opts.debug == true) {
					try {
						trace(str);
					} 
					catch (e) {
						alert("str: " + str);
					}
				}
			}
		});
	
		// Private methods -----------------------------------------------------------------
		
		// generic binding function
		function bind(name, fn)
		{
			if ($.isFunction(fn) == false)
				return;
				
			$(_self).bind(name, fn);
		};
	
		function init()
		{	
			var hasMenuName = /\bmenu:\s*(\S+)\b/.test(_domElement.className);
			
			_self.debug("_domElement.className: " + _domElement.className);
			_self.debug("hasMenuName: " + hasMenuName);
			
			if (hasMenuName == true) {
				var menuElementName = /\bmenu:\s*(\S+)\b/.exec(_domElement.className)[1];
				_self.debug("menuElementName: " + menuElementName);
				_menu = $("#" + menuElementName);
				
				//by default, just expands the menu in-place; if over-ridden, it positions the menu relative to hotspot
				var hasPositionOverride = /\bposition:\s*(\S+)\b/.test(_domElement.className);
				if (hasPositionOverride == true) {
					var posString = /\bposition:\s*(\S+)\b/.exec(_domElement.className)[1];
					_self.debug("posString: " + posString);
					if (posString.indexOf("left") != -1) {
						_positionLeft = "hotspot-left";
					}
					if (posString.indexOf("top") != -1) {
						_positionTop = "hotspot-top";
					}
					if (posString.indexOf("bottom") != -1) {
						_positionTop = "hotspot-bottom";
					}
				}
			}
			
			if (_menu != undefined) {
				_menuHeight = _menu.height();
				_menu.height("0px");
				
				_hotspot.click(function(){
					_self.toggleMenu();
				});
				_hotspot.mouseenter(function(){
					_self.doMouseEnter();
				});
				_hotspot.mouseleave(function(){
					_self.doMouseLeave();
				});
				_menu.mouseenter(function(){
					_self.doMouseEnter();
				});
				_menu.mouseleave(function(){
					_self.doMouseLeave();
				});
				_menu.find('a').click(function(){
					_self.doMouseLeave();	
				});
			}

		};
	
		// Initialization ------------------------------------------------------------------
		init();
	};

	// jQuery plugin implementation
	$.fn.topNavMenu = function(conf)
	{
		var opts = {};
		$.extend(opts, conf);
		
		this.each(function()
		{
			var $instance = new TopNavMenu($(this), opts);
		});
		return this; 
	};
})(jQuery);
/**
 * jquery.scrollable 1.0.4 - Scroll your HTML with eye candy.
 * 
 * ******** With modification for Sportsnet ********
 * 
 * Copyright (c) 2009 Tero Piirainen
 * http://flowplayer.org/tools/scrollable.html
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * http://www.opensource.org/licenses
 *
 * Launch  : March 2008
 * Date: 2009-06-08 10:42:59 +0000 (Mon, 08 Jun 2009)
 * Revision: 1898 
 */
(function($) {
		
	// static constructs
	$.tools = $.tools || {version: {}};
	
	$.tools.version.scrollable = '1.0.4';
				
	var current = null;		

	
	// constructor
	function Scrollable(root, conf) {

		// current instance
		var self = this;  
		if (!current) { current = self; }		
		
		// generic binding function
		function bind(name, fn) {
			$(self).bind(name, function(e, args)  {
				if (fn && fn.call(this, args.index) === false && args) {
					args.proceed = false;	
				}	
			});	
			
			return self;
		}
		
		function debug(str) {
			var showDebug = false;
			if (showDebug == true) {
				try {
					console.log(str);
				} 
				catch (e) {
					alert("debug: " + str);
				}
			}
		}
		
		// bind all callbacks from configuration
		$.each(conf, function(name, fn) {
			if ($.isFunction(fn)) { bind(name, fn); }
		});   
		
		// horizontal flag
		var horizontal = !conf.vertical;				
		
		// wrap (root elements for items)
		var wrap = $(conf.items, root),
			items = wrap.children()
			;
		
		// current index
		var index = 0;		
		
		function find(query, ctx) {
			return query.indexOf("#") != -1 ? $(query).eq(0) : ctx.siblings(query).eq(0);	
		}		
		
		// get handle to navigational elements
		// AlexGorbatchev: replaced find(..., root) with $(root).find(...)
		var navi = $(root).find(conf.navi),
			prev = $(root).find(conf.prev),
			next = $(root).find(conf.next),
			prevPage = $(root).find(conf.prevPage),
			nextPage = $(root).find(conf.nextPage)
			;
		
		// methods
		$.extend(self, {
			
			getIndex: function() {
				return index;	
			},
	
			getConf: function() {
				return conf;	
			},
			
			getSize: function() {
				var size = self.getItems().size();
				
				return conf.fitPages
					? size
					: Math.ceil(size / conf.pageSize) * conf.pageSize
					;
			},
	
			getPageSize: function() {
				return conf.pageSize;
			},
			
			getPageAmount: function() {
				return Math.ceil(this.getSize() / conf.pageSize);
			},
			
			getPageIndex: function() {
				return Math.ceil(index / conf.pageSize);	
			},

			getRoot: function() {
				return root;	
			},
			
			getItemWrap: function() {
				return wrap;	
			},
			
			getItems: function() {
				return items;	
			},
			
			getVisibleItems: function() {
				return self.getItems().slice(index, index + conf.pageSize);	
			},
			
			/* all seeking functions depend on this */		
			seekTo: function(i, time, fn) {
				
				// default speed
				time = time || conf.speed;
				
				// function given as second argument
				if ($.isFunction(time)) {
					fn = time;
					time = conf.speed;
				}
								
				if (i < 0) { i = 0; }				
				if (i > self.getSize() - conf.pageSize) { return self; } 				

				var item = self.getItems().eq(i);					
				if (!item.length) { return self; }				
				
				
				// onBeforeSeek
				var p = {index: i, proceed: true};
				$(self).trigger("onBeforeSeek", p);				
				if (!p.proceed) { return self; }
									
				
				if (horizontal) {
 					var left = -item.position().left;					
					wrap.animate({left: left}, time, conf.easing, fn ? function() { fn.call(self); } : null);
					
				} else {
					var top = -item.position().top;										
					wrap.animate({top: top}, time, conf.easing, fn ? function() { fn.call(self); } : null);							
				}	
				
				
				// navi status update
				if (navi.length) {
					var page = Math.ceil(i / conf.pageSize);
					
					if (conf.maxItemsInNavi > self.getPageAmount()) {
						var klass = conf.activeClass;
						page = Math.min(page, navi.children().length - 1);
						navi.children().removeClass(klass).eq(page).addClass(klass);
					} else {
						$(navi).find(".current").html(page + 1);
					}
				} 
				
				// prev buttons disabled flag
				if (i === 0) {
					prev.add(prevPage).addClass(conf.disabledClass);					
				} else {
					prev.add(prevPage).removeClass(conf.disabledClass);
				}
								
				// next buttons disabled flag
				if (i >= self.getSize() - conf.pageSize) {
					next.add(nextPage).addClass(conf.disabledClass);
				} else {
					next.add(nextPage).removeClass(conf.disabledClass);
				}				
				
				current = self;
				index = i;				
				
				// onSeek after index being updated
				$(self).trigger("onSeek", {index: i});				
				return self; 
			},			
			
				
			move: function(offset, time, fn) {
				var to = index + offset;
				var max = self.getSize() - conf.pageSize;
				
				// AlexGorbatchev: fixed so that looping works in all directions for even and uneven pages
				if (conf.loop == true)
				{
					if (to == self.getSize())
						to = 0;
					else if (to > max)
						to = max;	
					else if (to < 0 && to > - conf.pageSize)
						to = 0;
					else if (to < 0)
						to = max;
				}
				
				return this.seekTo(to, time, fn);
			},
			
			next: function(time, fn) {
				return this.move(conf.scrollByPage ? conf.pageSize : 1, time, fn);	
			},
			
			prev: function(time, fn) {
				return this.move(conf.scrollByPage ? -conf.pageSize : -1, time, fn);	
			},
			
			movePage: function(offset, time, fn) {
				return this.move(conf.pageSize * offset, time, fn);		
			},
			
			setPage: function(page, time, fn) {
				var size = conf.pageSize;
				var index = size * page;
				var lastPage = index + size >= this.getSize(); 
				if (lastPage) {
					index = this.getSize() - conf.pageSize;
				}
				return this.seekTo(index, time, fn);
			},
			
			prevPage: function(time, fn) {
				return this.setPage(this.getPageIndex() - 1, time, fn);
			},  
	
			nextPage: function(time, fn) {
				return this.setPage(this.getPageIndex() + 1, time, fn);
			}, 
			
			begin: function(time, fn) {
				return this.seekTo(0, time, fn);	
			},
			
			end: function(time, fn) {
				return this.seekTo(this.getSize() - conf.pageSize, time, fn);	
			},
			
			reload: function() {
				return load();	
			},
			
			click: function(index, time, fn) {
				
				var item = self.getItems().eq(index);
				var klass = conf.activeClass;			
				
				// check that index is sane
				if (index < 0 || index >= this.getSize()) { return self; }
					
				
				// special case with two items
				if (conf.pageSize == 2) {
					if (index == self.getIndex()) { index--; }
					self.getItems().removeClass(klass);
					item.addClass(klass);					
					return this.seekTo(index, time, fn);
				}
				

				if (!item.hasClass(klass)) {				
					self.getItems().removeClass(klass);
					item.addClass(klass);
					var delta = Math.floor(conf.pageSize / 2);
					var to = index - delta;

					// next to last item must work
					if (to > self.getSize() - conf.pageSize) { 
						to = self.getSize() - conf.pageSize; 
					}
					
					if (to !== index) {
						return this.seekTo(to, time, fn);		
					}				 
				}
				
				return self;
			},

			// callback functions
			onBeforeSeek: function(fn) {
				return bind("onBeforeSeek", fn); 		
			},
			
			onSeek: function(fn) {
				return bind("onSeek", fn); 		
			}			
			
		});
		
		// mousewheel
//		if ($.isFunction($.fn.mousewheel)) { 
//			root.bind("mousewheel.scrollable", function(e, delta)  {
//				// opera goes to opposite direction
//				var step = $.browser.opera ? 1 : -1;
//				
//				self.move(delta > 0 ? step : -step, 50);
//				return false;
//			});
//		}  
		
		// prev button
		prev.addClass(conf.disabledClass).click(function() { 
			self.prev(); 
		});
		
		// next button
		next.click(function() { 
			self.next(); 
		});
		
		// next page button
		nextPage.click(function() { 
			self.nextPage(); 
		});

		// next page button
		prevPage.addClass(conf.disabledClass).click(function() { 
			self.prevPage(); 
		});		

		debug("items.length: " + items.length);
		debug("conf.pageSize: " + conf.pageSize);
		//added test to hide prev/next buttons if there is just one page - Chris Bennett 9/23/09
		var hasMultiplePages = items.length > conf.pageSize;
		if (hasMultiplePages == false) {
			prev.hide();
			next.hide();
			prevPage.hide();
			nextPage.hide();
		}
		
		// keyboard
		if (conf.keyboard) {			

			// keyboard works on one instance at the time. thus we need to unbind first
			$(document).unbind("keydown.scrollable").bind("keydown.scrollable", function(evt) {
				
				var el = current;	
				if (!el || evt.altKey || evt.ctrlKey) { return; }
					
				if (horizontal && (evt.keyCode == 37 || evt.keyCode == 39)) {					
					el.move(evt.keyCode == 37 ? -1 : 1);
					return evt.preventDefault();
				}	
				
				if (!horizontal && (evt.keyCode == 38 || evt.keyCode == 40)) {
					el.move(evt.keyCode == 38 ? -1 : 1);
					return evt.preventDefault();
				}
				
				return true;
				
			});	 
		}

		// navi 			
		function createDottedNavi() {			
	
			// generate new entries
			if (navi.is(":empty") || navi.data("me") == self) {
				
				navi.empty();
				navi.data("me", self);
				
				for (var i = 0; i < self.getPageAmount(); i++) {		
					
					var item = $("<" + conf.naviItem + "/>").attr("href", i).click(function(e) {							
						var el = $(this);
						el.parent().children().removeClass(conf.activeClass);
						el.addClass(conf.activeClass);
						self.setPage(el.attr("href"));
						return e.preventDefault();
					});
					
					if (i === 0) { item.addClass(conf.activeClass); }
					navi.append(item);					
				}
				
			// assign onClick events to existing entries
			} else {
				
				// find a entries first -> syntaxically correct
				var els = navi.children(); 
				
				els.each(function(i)  {
					var item = $(this);
					item.attr("href", i);
					if (i === 0) { item.addClass(conf.activeClass); }
					
					item.click(function() {
						navi.find("." + conf.activeClass).removeClass(conf.activeClass);
						item.addClass(conf.activeClass);
						self.setPage(item.attr("href"));
					});
					
				});
			}
			
			
			// item.click()
			if (conf.clickable) {
				self.getItems().each(function(index, arg) {
					var el = $(this);
					if (!el.data("set")) {
						el.bind("click.scrollable", function() {
							self.click(index);		
						});
						el.data("set", true);
					}
				});				
			}
			
			
			// hover
			if (conf.hoverClass) {
				self.getItems().hover(function()  {
					$(this).addClass(conf.hoverClass);		
				}, function() {
					$(this).removeClass(conf.hoverClass);	
				});
			}			
			
			return self;
		};
		
		function createNumeredNavi()
		{
			navi.append('<span class="current">1</span>');
			navi.append('<span class="separator">' + conf.numberedNaviSeparator + '</span>');
			navi.append('<span class="total">' + self.getPageAmount() + '</span>');
		};
		
		function createRows()
		{
			var pageSize = conf.size * conf.rows,
				pageCount = Math.ceil(self.getSize() / pageSize)
				;

			for (var i = 0; i < pageCount; i++)
			{
				wrap.find('li').slice(i * pageSize, (i + 1) * pageSize).wrapAll('<div class="scrolling-panel-page"></div>');
			}
		};
		
		if (conf.maxItemsInNavi > self.getPageAmount())
			createDottedNavi();
		else
			createNumeredNavi();
		
		if (conf.rows > 1)
			createRows();
			
		// interval stuff
		var timer = null;

		function setTimer() {
			timer = setInterval(function()  {
					
				// see if interval has been disabled at runtime
				if (conf.interval === 0) { 
					clearInterval(timer); 
				}
				
				self.next();
				
			}, conf.interval);
		}	
		
		if (conf.interval > 0) {			
			
			root.hover(function() {			
				clearInterval(timer);		
			}, function() {		
				setTimer();	
			});
			
			setTimer();	
		}
		
	} 

		
	// jQuery plugin implementation
	// AlexGorbatchev: renamed to scrollingPanel 
	$.fn.scrollingPanel = function(conf) { 

		// AlexGorbatchev: we actually want to be able to recreate the element when called
		// already constructed --> return API
		// var el = this.eq(typeof conf == 'number' ? conf : 0).data("scrollable");
		// if (el) { return el; }		
		
		var opts = {
			
			// basics
			size: 5,
			scrollByPage: false,			// AlexGorbatchev : allows to scroll in full page sizes
			maxItemsInNavi: 4,				// AlexGorbatchev : converts navi to X/NN style if more pages than this value
			numberedNaviSeparator: ' / ',	// AlexGorbatchev : separator that goes between X and NN when displayed
			vertical: false,			
			clickable: true,
			loop: false,
			interval: 0,			
			speed: 400,
			keyboard: true,			
			
			// other
			activeClass:'active',
			disabledClass: 'disabled',
			hoverClass: null,			
			easing: 'swing',
			
			// navigational elements
			items: '.items',
			prev: '.prev',
			next: '.next',
			prevPage: '.prevPage',
			nextPage: '.nextPage',			
			navi: '.navi',
			naviItem: 'a',
			api: false,
			
			// callbacks
			onBeforeSeek: null,
			onSeek: null
			
		};
		
		
		// AlexGorbatchev: default sportsnet values
		$.extend(opts, {
			scrollByPage: true,
			rows: 1,
			items: 'ul',
			hoverClass: 'hover',
			next: '.navigation .next', 
			prev: '.navigation .prev',
			navi: '.navigation .pager',
			fitPages: false,
			loop: false,
			keyboard: false
		});
		
		$.extend(opts, conf);	
		
		// allows specifying size like '3x2'
		if (typeof(opts.size) == 'string' && /^\d+x\d+$/.test(opts.size))
		{
			var $parts = opts.size.split('x');
			opts.size = parseInt($parts[0]);
			opts.rows = parseInt($parts[1]);
		}
		
		opts.pageSize = opts.size * opts.rows;
		
		this.each(function()
		{
			el = new Scrollable($(this), opts);
			$(this).data("scrollable", el);	
		});
		
		return opts.api ? el: this; 
		
	};
			
	
})(jQuery);
(function($)
{	
	// constructor
	function MediaAndPhotos(root, conf)
	{	
		// Private fields ------------------------------------------------------------------
	
		var _root = $(root),
			_self = this,
			_mediaPanel = _root.find(".scrolling-panel.media"),
			_mediaPanelHtml
			;
	
		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			activateMediaSection: function(index)
			{
				var $url = conf.mediaSections[index][1],
					$aTags = _root.find('.header .sections a')
					;
				
				$aTags.removeClass('active')
				$($aTags[index]).addClass('active');
				
				_self.loadMedia($url);
			},
			
			loadMedia: function(url)
			{	
				var $minTimePassed = false,
					$timer = getTimer(),
					$minTime = 500
					;

				_mediaPanel.find('.loading').show();
				
				function process(json)
				{
					_mediaPanel.html(_mediaPanelHtml);
					_mediaPanel.find('.loading').hide();
					
					var $items = $(_self).triggerHandler("mediaLoaded", [ json ]),
						$container = _mediaPanel.find(".scroll-container"),
						$ul
						;
					
					$container.html('<ul></ul>');
					$ul = $container.find("ul");
					
					for (var $i = 0; $i < $items.length; $i++) 
					{
						var $item = $items[$i];
						
						$(
						'<li>'
							+ '<div class="text"><div class="ellipsis">' + $item.label + '</div></div>'
							+ '<div class="img" style="background-image: url(' + $item.thumb + ')" />'
							+ '<span class="video"><img src="/assets/img/top_story/btn_play.png" /></span>'
						+ '</li>'
						).appendTo($ul);
						
						$ul.find('li:last')
							.data('url', $item.url)
							.click(function()
							{
								window.location = $(this).data('url');
							});
					}

					_mediaPanel.scrollingPanel($.extend({ size: '3x2' }, conf));
					
					$ul.find('.text > .ellipsis').ellipsis();
				};
				
				$.ajax({
					type: "GET",
					url: url,
					dataType: "json",
					success: function(json){
						var $time = getTimer() - $timer;
						
						if ($time > $minTime) 
							process(json);
						else 
							setTimeout(function(){
								process(json);
							}, $minTime - $time);
					}//,
					//error: function(XMLHttpRequest, textStatus, errorThrown){
						// typically only one of textStatus or errorThrown will have info
					//	trace("textStatus: " + textStatus);
					//	trace("errorThrown: " + errorThrown);
					//}
				});
			},
			
			createItem: function(url, thumb, label)
			{
				return { url : url, thumb : thumb, label : label };
			}
		});
	
		// Private methods -----------------------------------------------------------------
		
		function getTimer()
		{
			return new Date().getTime();
		};
		
		// generic binding function
		function bind(name, fn)
		{
			if ($.isFunction(fn) == false)
				return;
				
			$(_self).bind(name, fn);	
		};
	
		function initLayout()
		{
			if ($.browser.msie6)
				_root.addClass('ie6');
			else if ($.browser.msie7)
				_root.addClass('ie7');
				
			var $photosPanel = _root.find(".scrolling-panel.photos");
			
			$photosPanel.scrollingPanel($.extend({ size: 1 }, conf));
			$photosPanel.find('li div p').addClass('ellipsis multiline').ellipsis();
			$photosPanel.find('li').click(function()
			{
				window.location = $(this).find('a')[0].href;
			})		
			
			var $sectionLinksContainer = _root.find(".header .sections"),
				$sections = []
				;
			
			//only show the section links if there's more than one section
			if (conf.mediaSections.length > 1) {
				for (var $i = 0; $i < conf.mediaSections.length; $i++) {
					var $item = conf.mediaSections[$i], $text = $item[0];
					
					$('<a href="#">' + $text + '</a>').appendTo($sectionLinksContainer);
					$('<span>|</span>').appendTo($sectionLinksContainer);
					
					$sectionLinksContainer.find('a:last').data('sectionIndex', $i).click(function(){
						_self.activateMediaSection($(this).data('sectionIndex'));
						return false;
					});
				}
			}
			
			// remove the last extra divider
			$sectionLinksContainer.find("span:last").remove();

			// add loader to the media panel
			_mediaPanel.append('<div class="loading">Loading</div>');

			// keep html those far
			_mediaPanelHtml = _mediaPanel.html();

			_mediaPanel.find('.loading').hide();
			
			// activate default first section
			_self.activateMediaSection(0);
		};
	
		// Initialization ------------------------------------------------------------------
		
		// bind all callbacks from configuration
		$.each(conf, bind);
		
		initLayout();
	};

	// jQuery plugin implementation
	$.fn.mediaAndPhotos = function(conf)
	{ 
		var opts = {
			scrollByPage: true,
			items: 'ul',   
			hoverClass: 'hover',
			next: '.navigation .next', 
			prev: '.navigation .prev',
			navi: '.navigation .pager',
			keyboard: false
		}; 
		
		$.extend(opts, conf);		
		
		this.each(function() 
		{
			var $instance = new MediaAndPhotos($(this), opts);
			$(this).data("mediaAndPhotos", $instance);
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function TopModule(root, conf)
	{	
		// Private fields -------------------------------------------------------------------

		var _root = $(root),
			_ul = _root.find('> ul'),
			_thumbsHolder = _root.find('> ul.main'),
			_thumbs = _thumbsHolder.find('div.image-clip img'),
			_thumbBtns,
			_container = _root.find('.top-story-container'),
			_brightcovePlayer,
			_brightcovePlayerNameRoot = 'TopStoryPlayer',
			_curBrightcovePlayerName,  //_brightcovePlayerNameRoot appended with random number on each create to eliminate issues with IE (multiple audio streams were playing when user clicked a new thumbnail in the top story module)
			_closeBtnHtml = '<div id="videoClose">close</div>',
			
			_self = this,
			_timer = 0,
			_itemCount = _ul.children().length,
			_itemIndex = 0,
			
			_canToggleOverlay = true,
			_overlayDelay = 0,
			_expendClass = 'expanded';
			_opts = {
				debug: false
			}
			;
			
		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			next: function() 
			{
				_itemIndex ++;
				
				if (_itemIndex >= _itemCount)
					_itemIndex = 0;
					
				this.activate(_itemIndex);
			},
			
			activate: function(index)
			{
				var $curActive = _container.find('.content.active');

				if ($curActive.hasClass('video') == true)
				{
					$curActive.find('> a').show();
					removeBrightcove();
				}
				
				conf.hideFunc($curActive.removeClass('active'));
				conf.showFunc(_container.find('.content:eq(' + index + ')').addClass('active'));

				_ul.find('li').removeClass('active');
				
				_ul.find('li:eq(' + index + ')').addClass('active');
				
				$curActive = _container.find('.content.active');
				if ($curActive.hasClass('video') == false)
				{
					positionTextFields();
				}
				
				updateOverlay($curActive);
				
				return $curActive;
			},
			
			initCloseButton: function(){
				_container.find(".video.active").prepend(_closeBtnHtml);
				$("#videoClose").click(function(){
					_self.closeVideo();
				});
			},
			
			clearCloseButton: function(){
				$("#videoClose").remove();
			},
			
			closeVideo: function(){
				_container.find('.content.active a').show();
				removeBrightcove();
				setTimer();
			},
			
			playVideo: function(a)
			{	
				//_self.initCloseButton();
				_container.addClass("video-playing");
				_thumbs.hide();
				_thumbBtns.hide();

				var $videoId = $(a).attr('href').replace('#', ''),
					$container = $(a)[0].parentNode
					;

				// replace content of the parent node with SWF
				$(a).hide();
				createBrightcove($container, $videoId);

				// not forgetting to stop the timer
				stopTimer();
			}
		});

		// Private methods -----------------------------------------------------------------
		function debug(str)
		{
			if (_opts.debug == true) {
				try {
					console.log(str);
				} 
				catch (e) {
					alert("debug: " + str);
				}
			}
		};

		// generic binding function
		function bind(name, fn)
		{
			if ($.isFunction(fn))
				$(_self).bind(name, fn);
		};
				
		function setTimer()
		{
			clearInterval(_timer);
			_timer = setInterval(function()
			{
				// see if interval has been disabled at runtime
				if (conf.interval == 0) 
					stopTimer(); 

				_self.next();
			}, conf.interval);
		};
		
		function stopTimer()
		{
			if (_timer == 0)
				return;
				
			clearInterval(_timer);
			_timer = 0;
		};

		// positionTextFields added by Gord 24/06/09
		function positionTextFields()
		{
			var $curContent = _container.find('.content.active'),
				$totalHeight = $curContent.height(),
				$curSummary = $curContent.find('.top-story-summary'),
				$curColumn = $curSummary.parent(),
				$headerHeight;

				
			if ($curContent.hasClass('five-cols')) {
				$headerHeight = $curContent.find('h3').outerHeight();
			}	else {
				$headerHeight = 0;
			}

			var	$staticHeight = $curColumn.outerHeight() - $curSummary.outerHeight() + $headerHeight;
				$lineHeight = Math.ceil(($curSummary.css('line-height').split('p'))[0]),
				$numRows = Math.floor(($totalHeight - $staticHeight) / $lineHeight),
				$summaryHeight = $numRows * $lineHeight
				;

			if ($curSummary.height() > $summaryHeight) {
				$curSummary.height($summaryHeight);
			}
		};
		
		function animateOverlay(expandable, targetAttribute, targetValue)
		{
			var $animationArgs = {};
			
			_canToggleOverlay = false;
			
			$animationArgs[targetAttribute] = targetValue;
			
			expandable.animate($animationArgs, { queue : false, duration : 150, complete: function()
			{
				_canToggleOverlay = true;

			}});
			
			stopTimer();
		};
		
		function resetOverlay(expandable, targetAttribute, targetValue)
		{
			expandable.css(targetAttribute, targetValue);
		};

		function toggleOverlay(expandable, expand, callback)
		{
			if (_canToggleOverlay == false)
				return;
				
			var $overlay = expandable.find('.overlay'),
				$container = expandable.parent('.content.five-cols'),
				$position = /\bposition-(\w+)-(\w+)\b/.exec(expandable[0].className),
				$verticalPosition = $position[1],
				$horizontalPosition = $position[2],
				$targetValue = expand ? 0 : $container.height() - expandable.data('__height'),
				$targetAttribute = { 'bottom' : 'top', 'top' : 'bottom' }[$verticalPosition]
				;
			
			expandable[(expand ? 'add' : 'remove') + 'Class'](_expendClass);
			callback(expandable, $targetAttribute, $targetValue);
			
			// for IE6 we have to also expand hight because it seems that bottom:0
			// isn't really sticking.
			if ($.browser.msie6)
			{
				var $container = expandable.parent('.content.five-cols');
				callback(
					expandable, 
					'height', 
					(expand ? $container.height() : expandable.data('__height')) - 2 // 2 pixels extra in IE6... not sure why
					);
			}

		};
		
		function updateOverlay(content)
		{
			$(content).find('.overlay.expandable').each(function()
			{
				var $expandable = $(this);

				if ($expandable.data('__height') != null)
					return;

				$expandable
					.data('__height', $expandable.height())
					//.mouseleave(close).mouseenter(open)
					//.find('h3')
						//.click(toggle)
					;
				$expandable
					.find('a.expand').click(toggle);

				function open()
				{
					toggleOverlay($expandable, true, animateOverlay);
					$expandable.data('toggle', closeNow);

					clearTimeout(_overlayDelay);
					_overlayDelay = 0;
					return false;
				};

				function closeNow()
				{
					toggleOverlay($expandable, false, animateOverlay);
					$expandable.data('toggle', open);
					_overlayDelay = 0;
					return false;
				};

				function close()
				{
					clearTimeout(_overlayDelay);
					_overlayDelay = setTimeout(closeNow, 250);
					return false;
				};

				function toggle()
				{
					toggleOverlay($expandable, !$expandable.hasClass(_expendClass), animateOverlay);
					//$expandable.data('toggle')();
					return false;
				};
				
				// reset initial coordinates so that animation works fine in most browsers
				toggleOverlay($expandable, true /*false /* keep closed */, resetOverlay);
			});
		};
		
		function initLayout()
		{
			// generate layout -----------------------------------------

			
			_ul.find('li.thumb').each(function(index)
			{
				_this = $(this);
				
				if (_this.find('.content').hasClass('video')) {
					_this.find('span.video').show();
				}
				
				_this.click(function()
				{
					var $content = _self.activate(index);
					
//					if ($content.hasClass('video'))
//						_self.playVideo($content.find('> a'));
					
					stopTimer();
					return false;
				});
				_this.show();
			});
			
			// move all content to the container
			_ul.find('li .content').appendTo(_container);
			
			_container.find('.content').hide();
			
			// activate first container
			_self.activate(_itemIndex);
			
			// hide the list if there's just one item
			if (_itemCount <= 1)
				_ul.hide();
			
			// set up image to swf functionality ------------------------
			
			_container.find('.content.video a').click(function()
			{
				_self.playVideo(this);
				return false;
			});
			
			_ul.find('.top-story-caption').ellipsis();
			
			_root.bind('onMediaComplete', function(e){
				setTimer();
			});
			
			_thumbBtns = _thumbsHolder.find('span.video:visible');
		};

		function createBrightcove(container, videoId)
		{
			var $params = {
					playerID : "53059221001",
					videoId : videoId,
					autoStart : "true",
					bgcolor : "#000000",
					wmode : "opaque",
					width : "645",
					height : "416", /* 350px for 4:3; 416px for 16:9 */
					isVid : "true",
					isUI : "true",
					cacheAMFURL : "http://services.brightcove.com/services/messagebroker/amf"
				};
			
			_brightcovePlayer = brightcove.createElement("object");
			_curBrightcovePlayerName = _brightcovePlayerNameRoot + (Math.round(Math.random() * 10000));
			_brightcovePlayer.id = _curBrightcovePlayerName;

			for (var $key in $params)
			{
			     $parameter = brightcove.createElement("param");
			     $parameter.name = $key;
			     $parameter.value = $params[$key];
			     _brightcovePlayer.appendChild($parameter);
			}

			brightcove.createExperience(_brightcovePlayer, container, true);
			
			debug("created brightcove player: " + _curBrightcovePlayerName);
		};
		
		function removeBrightcove()
		{
			if (_brightcovePlayer != null)
			{
				debug("removing brightcove player: " + _curBrightcovePlayerName);
				//_self.clearCloseButton();
				var curExp = brightcove.getExperience(_curBrightcovePlayerName);
				var curPlayer = curExp.getModule(APIModules.VIDEO_PLAYER);
				curPlayer.mute(); //this is to address the "ghost multi-streams" that were playing in IE only
				
				brightcove.removeExperience(_curBrightcovePlayerName);
				_brightcovePlayer = null;
				_container.removeClass("video-playing");
				_thumbs.show();
				_thumbBtns.show();
			}
		};
		// Initialization ------------------------------------------------------------------
		
		// bind all callbacks from configuration
		$.each(conf, bind);
		
		initLayout();
		
		if (conf.interval > 0 && _itemCount > 1) 
		{
			setTimer();	
		}
	};

	// jQuery plugin implementation
	$.fn.topModule = function(conf)
	{ 
		var opts = {
			interval : 0,		// Number of miliseconds to for auto rotation. 0 - no auto rotation
			hideFunc : function(element) { element.hide(); },
			showFunc : function(element) { element.fadeIn(); }
		}; 
		
		$.extend(opts, conf);
		
		this.each(function() 
		{
			var $instance = new TopModule($(this), opts);
			$(this).data("topModule", $instance);
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function Poll(root, conf)
	{	
		// Private fields ------------------------------------------------------------------
		var _root = $(root),
			_domElement = _root[0],
			_self = this,
			_userHasVoted,
			_resultContainer = _root.find('#poll-result-container'),
			_answerElem = _root.find('.poll-answers'),
			_opts = {
				debug: false
			}
			;
			$.extend(_opts, conf);
	
		// Public methods ------------------------------------------------------------------
//		$.extend(_self, {
//		});
	
		// Private methods -----------------------------------------------------------------
		function debug(str)
		{
			if (_opts.debug == true) {
				try {
					console.log(str);
				} 
				catch (e) {
					alert("debug: " + str);
				}
			}
		};
			
		// generic binding function
		
		function bind(name, fn)
		{
			if ($.isFunction(fn) == false)
				return;
				
			$(_self).bind(name, fn);
		};
		
		function showPollAnswers()
		{
			_resultContainer.hide();
			_answerElem.show();
		};
		
		function showPollResults(submitAnswer){
			//submitAnswer is false if the user clicks the "view results" link
			
            // make ajax request to vote and retrieve results
            var response_id = _answerElem.find('input[name=poll]:checked').val();
            if (!response_id || submitAnswer == false) response_id = '';
			debug("response_id: " + response_id);

            $.ajax({
                url: "/scrum/poll_vote.php",
                cache: false,
                data: "poll_id="+_opts.poll_id+"&response_id="+response_id,
                success: function(html) {
					_answerElem.hide();
                  // update poll-results
					_resultContainer.html(html);
					_resultContainer.fadeIn();
					_userHasVoted = getVoteStatus();
					debug("aft _userHasVoted: " + _userHasVoted);
					if (_userHasVoted == false) showAnswersLink();
                }
            });
			
			return false;
		};
		
		function showAnswersLink(){
			var linkHtml = '<div class="arrow" style="margin:7px 0 0 10px;"><a href="#" id="pollVoteNowLink">Vote Now</a></div>';
			_resultContainer.append(linkHtml);
			_root.find("#pollVoteNowLink").click(function(){
				showPollAnswers();
				return false;
			});
		};
		
		function enableButton(){
			$("#pollVoteButton", _root).removeClass("buttonInactive");
			$("#pollVoteButton", _root).click(showPollResults);
		};
		
		function getVoteStatus(){
			var hasVoted = false;
			
            var polls = $.cookie('polls');
            if (polls) {
				var pollsVoted = polls.split('|');
			
                $.each(pollsVoted, function(key, value) {
                    if (value == _opts.poll_id) {
						hasVoted = true;
					}
                });
            }
			return hasVoted;
		};
	
		function init()
		{
            // see if user has already voted
			_userHasVoted = getVoteStatus();
			
			debug("_userHasVoted: " + _userHasVoted);
			
            if (_userHasVoted == true) {
                showPollResults();
            } else {
                _answerElem.find("input").click(enableButton);
                $("#pollShowResultsLink", _root).click(function(){
					showPollResults(false);
					return false;
				});
                showPollAnswers();
            }
		};
	
		// Initialization ------------------------------------------------------------------
		init();
	};
	
	// jQuery plugin implementation
	$.fn.poll = function(conf)
	{
		var opts = { };
		$.extend(opts, conf);
		
		this.each(function()
		{
			var $instance = new Poll($(this), opts);
		});
		
		return this;
	};
})(jQuery);
(function($)
{	
	// constructor
	function UserInfoModule(root)
	{	
		// Private fields -------------------------------------------------------------------

		var _root = $('body'),
			_signIn = $('.sign-in-link'),
			_signInCancel = $('#sign-in-cancel'),
			_login = $('#login-btn'),
			_channelSelector = $('#channel-selector'),
			_channelWrapper = $('.channel-wrapper'),
			_channelTip = $('.channel-tip'),
			_channelChoicesToggle = $('.channel-choices-toggle'),
			_channelOptions = $('.channel-option'),
			_logout = $('#logout-link'),
			_settings = $('#settings-link'),
			_userName = $('#user-name'),
			_passwordLabel = _root.find('#password-label'),
			_password = _root.find('#password'),
			_overlayBlocker = _root.find('.overlay-blocker'),
			//_overlayChannelSelector = _root.find('.overlay-channel-selector'),
			//_overlayChannelButtons = $(_root.find('#channel-buttons')).find('a'),
			//_overlayChannelInfo = _root.find('#channel-info'),
			_userChannel = "Ontario",
			_leftChannelBar = _root.find('.region'),
			_self = this,
			_opts = {
				debug: false
			}

			;  

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			
			//check for channel cookie
			doCookieCheck: function (whichCookie)
			{
				var $myCookie = whichCookie;
				var c = $.cookies.get($myCookie);
				_self.debug("doCookieCheck for '"+whichCookie+"'; value: " + c);
				
				if (c != null) {
					_userChannel = c;
					$.cookies.del($myCookie);
					_self.doCookieSet($myCookie, c);
					return true;
				} else {
					//alert("doCookieCheck: cookie: "+c);
					return false;
				}
			},	
			
			//set user's channel cookie
			doCookieSet: function (whichCookie, whichValue)
			{
				var $tmp = window.location.href,
					$url = $tmp.split('/'),
					$loc = $url[2].split('.'),
					$dom = '.'+$loc[1]+'.'+$loc[2];
				 var cookieOptions = {
				    path: '/',
					domain: $dom,//'.pairsite.com', //'.sportsnet.ca',
				    hoursToLive: 90000,
				    secure: false
				  }
				var $cookie = whichCookie;
				var $value = whichValue;
				$.cookies.set($cookie, $value, cookieOptions);

			},
			
			//open channel selection overlay
			doChannelSelectOverlay: function () 
			{
				var $blockerHeight = $('body').height();
				
				//var $topnavXOffset = 6; //distance from _overlayChannelSelector to edge of top nav.
				var $rightEdge = _channelWrapper.offset().left +  _channelWrapper.outerWidth(); //+ $topnavXOffset;
				var $targetX = $rightEdge - _overlayChannelSelector.outerWidth();
				var $logoYOffset = 37;
				var $targetY = _channelWrapper.offset().top - $logoYOffset;


				_overlayChannelSelector.css({left: $targetX, top: $targetY});
				_overlayChannelSelector.fadeIn('slow');

				if ($blockerHeight > _overlayBlocker.height()) {
					_overlayBlocker.css({
						height: $blockerHeight
					});
				}
				_overlayBlocker.toggleClass('hidden');

			},
			
			//close channel selection overlay and set cookie from user input
			closeOverlay: function () 
			{
				_self.doCookieSet('sn_region', _userChannel);
				var content = _overlayChannelSelector.find('#select-content');
				var header = _overlayChannelSelector.find('#select-header');
				header.fadeOut('fast');
				content.children().slideUp('fast');
				content.animate({
					height: '0px',
					width: '200px',
					left: '770px',
					right: '1080px'}, 400, function() { _self.reloadPage(); });
			},
			//refresh page - used when user changes the channel choice.
			reloadPage: function () 
			{
				_overlayBlocker.slideUp();
				location.reload();
			},
			
			//set the text for the current channel.
			initUserChannel: function ()
			{
				var $klass = _userChannel.toLowerCase();
				$('#cur-channel').removeClass();
				$('#cur-channel').addClass($klass);
				$($('#channel-options').find('.'+$klass)).addClass('on');
				$('#cur-channel').text(_userChannel);
				
				_leftChannelBar.find('.on').removeClass('on');
				_leftChannelBar.find('#reg-'+_userChannel).addClass('on');
				_leftChannelBar.slideDown();
			},
			
			//show the user sign in form.
			showLogin: function()
			{
				$('.welcome').fadeOut('fast');
				$('.channel-wrapper').fadeOut('fast');
				$('.sign-in').fadeIn();
			},
			
			//submit sign-in info - TODO validation.
			doSignIn: function() 
			{
				$('.sign-in').fadeOut('fast');
				$('#user-display-name').text($('#user-name').val());
				$('.logged-in').fadeIn();
				$('.channel-wrapper').fadeIn();
			},
			
			//toggles the channel selection drop down.
			doOpenChannelSelect: function() 
			{
				$('.channel-choices-toggle').addClass('close');
				_channelWrapper.addClass('active');
			},
			doCloseChannelSelect: function() 
			{
				$('.channel-choices-toggle').removeClass('close');
				_channelWrapper.removeClass('active');
			},
			
			//cancels login and takes user back to greeting message.
			cancelSignIn: function() 
			{
				$('.sign-in').fadeOut('fast');
				$('.welcome').fadeIn();
				$('.channel-wrapper').fadeIn();
			},
			
			//user logs out and is returned to greeting message.
			doLogout: function() 
			{
				$('.logged-in').fadeOut('fast');
				$('.welcome').fadeIn();
			},
			debug: function(str)
			{
				if (_opts.debug == true) {
					try {
						console.log("str: " + str);
					} 
					catch (e) {
						//alert("str: " + str);
					}
				}
			}
		});

		// Private methods ----------------------------------------------------------------
		function initLayout()
		{	
			//_root.append(_overlayBlocker);
			//_root.append(_overlayChannelSelector);
			
			var _cookieCheck = _self.doCookieCheck('sn_region');
			
			if (_cookieCheck == false){
				// remove the bottom lines to disable regional selection
				//_leftChannelBar.hide('fast');
				//_self.doChannelSelectOverlay();
			} else {
				_self.initUserChannel();
			};
			
			_signIn.click(function(){
				_self.showLogin();
			}),
			
			_login.click(function() {
				_self.doSignIn();
			}),
			
			_signInCancel.click(function() {
				_self.cancelSignIn();
			}),
			_userName.focus(function() {
				_userName.val('');
			}),	
			_userName.blur(function() {
				if(_userName.val() == ''){
					_userName.val('Username');
				}
			}),
			_passwordLabel.focus(function(){
				_passwordLabel.addClass('hidden');
				_password.removeClass('hidden');
				_password.focus();
			}),
			_password.blur(function(){
				if(_password.val() == "") {
					_password.addClass('hidden');
					_passwordLabel.removeClass('hidden');
				}
			}),

			//_channelTip.hoverIntent(_self.doShowTip, _self.doHideTip); 
			
			_channelOptions.click(function() {
				
				if ($(this).hasClass('on') == false) {
					var txt = this.innerHTML;
					var $color = $(this).css('color');
					
					$('#cur-channel').text(this.innerHTML);
					$('#cur-channel').css({
						color: $color
					});
					
					_userChannel = txt;
					_self.doCookieSet('sn_region', _userChannel);
					for (var i = 0; i < _channelOptions.length; i++) {
						var curOption = _channelOptions.eq(i);
						if (curOption.text() == this.innerHTML) {
							curOption.addClass('active');
						}
						else {
							curOption.removeClass('active');
						}
					}
					_self.doCloseChannelSelect();
					_self.reloadPage();
				}	
			}),
			
			_channelChoicesToggle.click(function() {
				if(_channelChoicesToggle.hasClass('close') == true) {
					_self.doCloseChannelSelect();
				} else {
					_self.doOpenChannelSelect();
				}
			}),

			_channelWrapper.hoverIntent(function()	{ 
  				//do nothing
 
 			}, function() {	
				if(_channelWrapper.hasClass('active') == true) {
					_self.doCloseChannelSelect();
				}
			}),	
			
			_logout.click(function() {
				_self.doLogout();
			}),
			/*
			_overlayChannelButtons.click(function(evt) {
				var id = $(this).attr('id');
				var str = id.split('-');
				var ch = str[1];
				_userChannel = ch;
				_self.closeOverlay()
			}),
			
			_overlayChannelButtons.hoverIntent(function () {
				var id = $(this).attr('id');
				var str = id.split('-');
				var ch = str[1];
				var info = _overlayChannelInfo.find('#info-'+ch);
				info.fadeIn('fast');
			}, function() {
				var id = $(this).attr('id');
				var str = id.split('-');
				var ch = str[1];
				var info = _overlayChannelInfo.find('#info-'+ch);
				info.fadeOut('fast');
			}),
			*/
			_leftChannelBar.find('a').each(function(){
				$(this).click(function() {
					if ($(this).hasClass('on') == false) {
						var id = $(this).attr('id');
						var str = id.split('-');
						var ch = str[1];
						_userChannel = ch;
						_self.doCookieSet('sn_region', _userChannel);
						_self.reloadPage();
					}
				});
			})
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
		

	};

	// jQuery plugin implementation
	$.fn.userInfoModule = function()
	{ 
		this.each(function() 
		{
			var $instance = new UserInfoModule($(this));
			$(this).data("userInfoModule", $instance);
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function GameDay(root, conf)
	{	
		// Private fields ------------------------------------------------------------------
	
		var _root = $(root),
			_self = this,
			_isStacked = _root.hasClass("stacked"),
			_gamesCount = _root.find(".game").length,
			_container = _root.find('.game-day-container'),
			_footer = _root.find('.game-day-footer'),
			_currentGameIndex = 0,
			_fullHeight,
			_stackedHeight,
			_prevA,
			_nextA,
			_toggleA
			;

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			showGame: function(index, dontAnimate)
			{
				var $old = _root.find(".game.active"),
					$new = _root.find(".game:eq(" + index + ")").addClass("active")
					;
					
				if (dontAnimate != true)
				{
					conf.hideFunc($old);
					conf.showFunc($new);
				}
				else
				{
					$old.hide();
					$new.show();
				}

				updateSportFromGame($new[0]);
				updateFooterFromGame($new[0]);
				
				// ellipsis can only be applied to visible elements
				if ($new.data('eli') != true)
				{
					$new.find('.details .link-list a:only-child')
						.addClass('ellipsis')
						.ellipsis()
						;
					$new.data('eli', true);
				}
			},
			
			nextGame: function()
			{
				if (_currentGameIndex + 1 < _gamesCount)
				{
					_self.showGame(++_currentGameIndex);
					updatePrevNextButtons();
				}
				
				return false;
			},
			
			prevGame: function()
			{
				if (_currentGameIndex - 1 >= 0)
				{
					_self.showGame(--_currentGameIndex);
					updatePrevNextButtons();
				}

				return false;
			},
			
			toggleGame: function()
			{
				var $game = $(this).parents('.game');

				// apply ellipsis to all items here
				if ($game.data('eli') != true)
				{
					$game.find('.details .link-list a:only-child')
						.addClass('ellipsis')
						.ellipsis()
						;
					$game.data('eli', true);
				}

				updateSportFromGame($game[0]);
				updateFooterFromGame($game[0]);
				
				if ($game.hasClass('closed'))
				{
					_root.find('.game:not(.closed)').height(_stackedHeight).addClass('closed');
					$game.height(_fullHeight).removeClass('closed');
				}
				else
				{
					$game.height(_stackedHeight);
					$game.addClass('closed');
					_footer.find('.footer-message').hide();
				}

				stackGames();

				return false;
			}
		});
	
		// Private methods -----------------------------------------------------------------
		
		function updateSportFromGame(game)
		{
			var $sport = /sport-(\w+)/.exec(game.className)[0];
			var $newClass = 'sport-image ' + $sport;
			var $image = _root.find('.sport-image')[0];
			
			if ($image.className != $newClass)
			{
				$($image).hide();
				$image.className = $newClass;
				$($image).fadeIn('slow');
			}
		};
		
		function updateFooterFromGame(game)
		{
			var $class = '.footer-message';
			var $msg = $(game).find($class);
			var $html = $msg.html();
			var $footer = _footer.find($class);
			
			if ($html != null && $html != '' && !_isStacked)
			{
				$footer.show();
				$footer.html($html);
			}
			else
			{
				$footer.hide();
			}
		}
		
		function updatePrevNextButtons()
		{
			var $disabled = "disabled";
			
			_root.find(".buttons a").removeClass($disabled);
			
			if (_currentGameIndex == 0)
				_prevA.addClass($disabled);

			if (_currentGameIndex + 1 >= _gamesCount)
				_nextA.addClass($disabled);
		};
		
		// generic binding function
		function bind(name, fn)
		{
			if ($.isFunction(fn) == false)
				return;
				
			$(_self).bind(name, fn);	
		};
	
		function stackGames()
		{
			var top = 0;
			
			_root.find('.game').each(function()
			{
				$(this).css('top', top);
				top += $(this).height();
			});
			
			_footer.css('top', top + _container[0].offsetTop);
			_root.css('height', _footer[0].offsetTop + _footer.height());
		}
		
		function initLayout()
		{
			if ($.browser.msie6)
				_root.addClass('ie6');
			else if ($.browser.msie7)
				_root.addClass('ie7');
			
			if (_isStacked == false)
			{
				_root.find(".game").hide();
				
				$('<div class="buttons">'
					+ '<a href="#" class="prev"></a> '
					+ '<a href="#" class="next"></a>'
				+ '</div>').appendTo(_root);
			}
			else
			{
				_fullHeight = _root.find('.game').height()
				_root.find(".game").addClass('stacked closed');
				_stackedHeight = _root.find('.game.stacked').height()

				$('<div class="buttons">'
					+ '<a href="#" class="toggle"></a> '
				+ '</div>').appendTo(_root.find('.game'));
				
				stackGames();
			}
				
			_self.showGame(0, true /* don't animate */);
			
			_prevA = _root.find(".buttons a.prev");
			_nextA = _root.find(".buttons a.next");
			_toggleA = _root.find(".buttons a.toggle");
			
			_prevA.click(_self.prevGame);
			_nextA.click(_self.nextGame);
			_toggleA.click(_self.toggleGame);
			
			_root.find(".game .info .teams .team").each(function()
			{
				var $team = $(this).find('span a').text().toLowerCase(),
					$score = $(this).find('em')
					;
					
				if ($score.text().length >= 3)
					$score.addClass('smaller');
			});
			
			updatePrevNextButtons();
		};
	
		// Initialization ------------------------------------------------------------------
		
		// bind all callbacks from configuration
		$.each(conf, bind);
		
		initLayout();
	};

	// jQuery plugin implementation
	$.fn.gameDay = function(conf)
	{ 
		var opts = {
			hideFunc : function(element) { element.hide(); },
			showFunc : function(element) { element.show(); }
		}; 
		
		$.extend(opts, conf);		
		
		this.each(function() 
		{
			var $instance = new GameDay($(this), opts);
			$(this).data("gameDay", $instance);
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function Tabs(root, conf)
	{	
		// Private fields ------------------------------------------------------------------

		var _root = $(root),
		    _ul = $(root).find('> ul'),
			_container = _root.find('.tabs-container'),
			_self = this,
			_lastTabIndex,
			_opts = {
				defaultIndex: 0,
				colWidth: null 
			}
			;
		$.extend(_opts, conf);

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			activate: function(index)
			{
				var $active = 'active',
					$eq = ':eq(' + index + ')'
					;
					
				conf.hideFunc(_ul.find('> li.' + $active).removeClass($active));
				conf.showFunc(_ul.find('> li' + $eq).addClass($active));

				_container.find('div.' + $active).removeClass($active);
				_container.find('div.activeLast').removeClass("activeLast");
				_container.find('div' + $eq).addClass($active);
				
				if (index == _lastTabIndex) {
					_container.find('div' + $eq).addClass("activeLast");
				}
			}
		});

		// Private methods -----------------------------------------------------------------

		// generic binding function
		function bind(name, fn)
		{
			if ($.isFunction(fn) == false)
				return;
				
			$(_self).bind(name, function(e, args)
			{
				if (fn && fn.call(this, args.index) === false && args)
				{
					args.proceed = false;	
				}	
			});	
		};
		
		function initLayout()
		{
			_ul.find('> li').hide();
			var cHeaders = _ul.find('> li > ' + conf.header);
			_lastTabIndex = cHeaders.length-1;
			
			var tabTable = $('<table class="tabTable" cellpadding="10" cellspacing="0" width="100%" border="1"></table>').appendTo(_container);
			var tabBody = $('<tbody></tbody>').appendTo(tabTable);
			var tabRow = $('<tr></tr>').appendTo(tabBody);
			var targetWidth = _opts.colWidth == null ? _container.outerWidth() / cHeaders.length : _opts.colWidth;
			// converts all H5 tags to the tab elements
			cHeaders.each(function(index)
			{
				$('<td width="'+targetWidth+'"><div><a href="#">' + $(this).text() + '</a></div></td>').appendTo(tabRow);
				$(this).remove();
				
				_container.find('a:eq(' + index + ')').click(function()
				{
					_self.activate(index);
					return false;
				})
			});
			
			_container.find('div:first').addClass('first');
			_container.find('div:last').addClass('last');
			
			_self.activate(_opts.defaultIndex);
			
			_root.show();
		};

		// Initialization ------------------------------------------------------------------
		
		// bind all callbacks from configuration
		$.each(conf, bind);
		
		initLayout();
	};

	// jQuery plugin implementation
	$.fn.tabs = function(conf)
	{ 
		var opts = {
			header : 'h5',
			hideFunc : function(element) { element.hide(); },
			showFunc : function(element) { element.fadeIn(); }
		}; 
		
		$.extend(opts, conf);		
		
		this.each(function() 
		{
			var $instance = new Tabs($(this), opts);
			$(this).data("tab", $instance);
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function PlayerStats(root, values)
	{	
		// Private fields ------------------------------------------------------------------
	
		var _root = $(root),
			_self = this,
			_sport = /sport-(\w+)/.exec(_root[0].className)[1],
			_data = SPORTSNET_PLAYER_STATS[_sport],
			_comparePosition,
			_comparePlayerId,
			_positionsContainer,
			_measuresContainer,
			_dimensionsContainer,
			_statsContainer,
			_selectedPosition,
			_selectedMeasure,
			_compareContainer,
			
			_changeHtml = '<span class="change">(<a href="#">change</a>)</span>',
			_clearHtml = '<div style="clear:both"></div>'
			;
	
		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			selectPosition: function(sender)
			{
				if (_root.hasClass('position-selected'))
					return;
				
				var $radio = $(sender).parent().find('input:radio'),
					$position = $radio.val(),
					$data = findPosition($position)
					;

				if ($data == null)
					return false;

				_self.deselectPosition(null);
				_self.deselectMeasure(null);

				// deselectPosition will clear this, put it back
				$radio.attr('checked', 'true');
				
				_selectedPosition = $position;
				_root.addClass('position-selected');
				$(sender).parents('.radio').addClass('selected');
				
				// clear all dimensions
				_dimensionsContainer.html('');
				// create measures and stats
				createMeasure($data.measures);
				createStats($data.stats);

				bindEvents();
			},
			
			deselectPosition: function(sender)
			{
				_selectedPosition = null;
				_root.removeClass('position-selected');
				_root.removeClass('no-stats');
				_root.removeClass('no-dimensions');
				_positionsContainer
					.find('.radio').removeClass('selected')
					.find('input:radio').attr('checked', '')
					;
				_self.deselectMeasure(null);
				_self.activateButton(false);
				_measuresContainer.html('');
				_statsContainer.html('');
				_statsContainer.removeClass('opened');
			},
			
			selectMeasure: function(sender)
			{
				if (_root.hasClass('measure-selected'))
					return;
					
				var $radio = $(sender).parent().find('input:radio'),
					$measure = $radio.val(),
					$data = findPosition(_selectedPosition)
					;

				_self.deselectMeasure(null);
				
				// deselectMeasure clears all checks, so put it back
				$radio.attr('checked', 'true');
				
				_selectedMeasure = $measure;
				_root.addClass('measure-selected');
				$(sender).parents('.radio').addClass('selected');
				
				// only create dimension once
				if (_dimensionsContainer.html() == '')
					createDimensions($data.dimensions);
				
				bindEvents();
			},
			
			deselectMeasure: function(sender)
			{
				_selectedMeasure = null;
				_root.removeClass('measure-selected');
				_measuresContainer
					.find('.radio').removeClass('selected')
					.find('input:radio').attr('checked', '')
					;
				_measuresContainer.find('.radio').removeClass('selected');
				_dimensionsContainer.html('');
			},

			selectDimension: function(sender)
			{
				$(sender).parents('.items').find('.radio').each(function()
				{
					var $select = $(this).find('select'),
						$radio = $(this).find('input:radio')
						;
						
					if ($radio[0].checked == false && $select.length > 0)
						$select.attr('selectedIndex', 0);
				});
			},
			
			deselectDimension: function(sender)
			{
				_root.removeClass('prefilled-dimensions');
			},
			
			toggleStats: function(sender)
			{
				var $max = 5,
					$count = _statsContainer.find('input:checkbox[checked="true"]').length,
					$left = $max - Math.min($max, $count)
					;

				if ($count > $max && sender.checked == true)
					sender.checked = false;
					
				_statsContainer.find('.message .counter').html($left);
				
				_statsContainer
					.find('.radio input:checkbox[checked!="true"]')
					.parents('.radio')
						[($left == 0 ? 'add' : 'remove') + 'Class']('dim')
				;
			},
			
			toggleStatsSection: function(sender)
			{
				_statsContainer.toggleClass('opened');
				_root.removeClass('prefilled-stats');
			},
			
			setSelected: function(values)
			{
				function s(v) { return 'input[value="' + v + '"]'; };
				function check(sender) { sender.checked = true; };
				function open(container, callback, value)
				{
					if (value)
						return callback(container.find(s(value))[0]) != false;
					
					return false;
				};

				var $data,
					$position,
					$labels,
					$name
					;
				
				// handle compare values
				if (values.compare && values.compare.left != '' && values.compare.right != '')
				{
					var $players = SPORTSNET_PLAYERS[_sport],
						$leftData = findInArray($players, [0], values.compare.left),
						$rightData = findInArray($players, [0], values.compare.right)
						;
						
					_self.activateCompareTab();
					_self.setCompareValue(_compareContainer.find('input[name="left"]')[0], $leftData);
					_self.setCompareValue(_compareContainer.find('input[name="right"]')[0], $rightData);
					
					$position = $leftData[2];
				}
				else if (open(_positionsContainer, _self.selectPosition, values.position))
				{
					$position = values.position;
				}
				else
				{
					return;
				}

				$data = findPosition($position);
				open(_measuresContainer, _self.selectMeasure, values.measure);
				
				if (values.dimensions && values.dimensions.length > 0 && $data.dimensions)
				{
					var $dimensions = [];

					$labels = [];

					for (var $i = 0; $i < $data.dimensions.length; $i++)
						$dimensions = $dimensions.concat($data.dimensions[$i]);

					for (var $i = 0; $i < values.dimensions.length; $i++)
					{
						$name = values.dimensions[$i];
						
						if ($name == null || $name == '')
							continue;

						var $parts = $name.split(','),
							$label
							;
							
						$name = $parts[0];
						$label = findInArray($dimensions, 'name', $name).label;
						
						open(_dimensionsContainer, check, $name);
						
						if ($parts.length > 1)
						{
							var $team = $parts[1];
							
							_dimensionsContainer.find('select[name="' + field('dimension' + $i, $name) + '"]').val($team);
							
							// special case for 'Vs. TEAM NAME'
							if ($name == 'vs_team')
								$label = 'Vs. ' + findInArray(SPORTSNET_TEAMS[_sport], 0, $team)[2];
						}

						$labels.push($label);
					}

					if ($labels.length == 0)
						$labels.push('Defaults');
					
					_root.addClass('prefilled-dimensions');
					_dimensionsContainer.find('.title').after(''
						+ '<div class="prefilled">'
							+ $labels.join(', ')
							+ _changeHtml
						+ '</div>'
					);
				}

				// prefill 'Add stats' checkboxes
				if (values.stats && values.stats.length > 0)
				{
					$labels = [];
					
					for (var $i = 0; $i < values.stats.length; $i++)
					{
						$name = values.stats[$i];
						if ($name == null || $name == '')
							continue;
							
						$labels.push(findInArray($data.stats, 'name', $name).label);
						_statsContainer.find(s($name)).attr('checked', 'true');
						open(_statsContainer, _self.toggleStats, $name);
					}

					_root.addClass('prefilled-stats');
					_statsContainer.append(''
						+ '<div class="prefilled">'
							+ '<span class="label">Include:</span> '
							+ $labels.join(', ')
						+ '</div>'
					);
					
					// add a bit of extra space if more than 3 items were selected
					if ($labels.length > 3)
						_root.find('.buttonHolder').addClass('extra-space');
				}
				
				_self.activateButton(true);
			},
			
			getCompareHiddenField: function(name)
			{
				return _root.find('input[name="' + field('compare', name) + '"]');
			},
			
			setCompareValue: function(input, data)
			{
				if (data == null)
					return;
					
				var $player = data[1],
					$position = data[2],
					$id = data[0]
					;
				
				$(input).parent('.input').addClass('selected');
				$(input).siblings('.value').html($player);
				_self.getCompareHiddenField(input.name).val($id);
				
				// if left compare value was set, have to manipulate the right input field
				if (input.name == 'left')
				{
					_comparePlayerId = data[0];
					_comparePosition = $position;
					
					_compareContainer.find('.comment').html('Select another player');
					_compareContainer.find('.right input').attr('disabled', false);
				}
				
				if (input.name == 'right')
				{
					_self.activateButton(true);
				}
			},
			
			clearCompareValue: function(input)
			{
				var $parent = $(input).parent('.input');
				
				$parent.removeClass('selected');
				$parent.find('.value').html('');
				$(input).val('');
				$(input).hint();
				_root.find('.box').hide();
				_self.getCompareHiddenField(input.name).val('');
				_statsContainer.hide();
				_self.activateButton(false);
				
				if ($parent.hasClass('left'))
				{
					_comparePosition = null;
					_comparePlayerId = null;
					_compareContainer.find('.comment').html('');
					_compareContainer.find('.right input').attr('disabled', true);
					_self.clearCompareValue(_compareContainer.find('input[name="right"]'));
					_self.deselectPosition();
				}
				
				if ($parent.hasClass('right'))
				{
				}
			},
			
			activateCompareTab: function()
			{
				if (_self.activateTab(_root.find('.compare-tab a')) == false)
					return;

				createCompare();
				_compareContainer.show();
				_self.deselectPosition(null);
				_root.addClass('no-position no-measures');				
				_root.find('.box').hide();
				_root.data('no-position-by-compare', true);
				_root.data('no-measures-by-compare', true);
			},
			
			activateCustomTab: function()
			{
				if (_self.activateTab(_root.find('.custom-tab a')) == false)
					return;
				
				// removes no-position and no-measure from the _root if 
				// they were set by activating compare tab.
				function revertVisibility(name)
				{
					var $n = 'no-' + name + '-by-compare';
					
					if (_root.data($n) == true)
					{
						_root.removeClass('no-' + name);
						_root.data($n, null);
					}
				};
				
				revertVisibility('position');
				revertVisibility('measures');
				
				_root.find('.box').show();
				_root.find('input[name="' + field('compare', 'left') + '"]').val('');
				_root.find('input[name="' + field('compare', 'right') + '"]').val('');
				_self.deselectPosition(null);
				_compareContainer.html('');
				_compareContainer.hide();
				_comparePosition = null;
				_comparePlayerId = null;
				
				// have to select default if it's present
				if (findPosition('default') != null)
					_self.selectPosition(_positionsContainer.find('input[value="default"]'));
			},
			
			activateTab: function(a)
			{
				var $div = $(a).parent('div');
				
				if ($div.hasClass('on'))
					return false;
					
				$(a).parents('.tabs').find('.on').removeClass('on');
				$div.addClass('on');
				
				return true;
			},
			
			activateButton: function(activate)
			{
				_root.find('.buttonHolder .button')[(activate ? 'remove' : 'add') + 'Class']('buttonInactive');
			}
		});
	
		// Private methods -----------------------------------------------------------------
		
		function getWidth(target)
		{
			return target.width()
				+ parseInt(target.css('padding-left'))
				+ parseInt(target.css('padding-right'))
				+ parseInt(target.css('margin-left'))
				+ parseInt(target.css('margin-right'))
				;
		};
		
		function setSelected(target, selected)
		{
			$(target)[(selected ? 'add' : 'remove') + 'Class']('selected');
		};
		
		function findInArray(array, fieldname, value)
		{
			for (var $i = 0; $i < array.length; $i++)
				if (array[$i][fieldname] == value)
					return array[$i];
					
			return null;
		};
		
		function findPosition(name)
		{
			return findInArray(_data, 'name', name);
		};
		
		function field(name, param)
		{
			return 'player_stats[' + name + '][' + (param == null ? '' : param)+ ']';
		};
		
		function sortByField(array, field)
		{
			return array.sort(function(a, b)
			{
				a = a[field];
				b = b[field];
				
				if (a > b)
					return 1;
				else if (a < b)
					return -1;
				else
					return 0;
			});
		};
		
		/**
		 * Adds <div style='clear: both' /> after Nth .radio element in the container.
		 */
		function setColumns(container, columns)
		{
			columns =  columns || 3;
			$(container).find('.radio:nth-child(' + columns + 'n)').after('<div style="clear: both"></div>');
		};
		
		function createCompare()
		{
			if (_compareContainer.html() != '')
				return;
			
			var $html = ''
				+ '<div class="input left float sn-input">'
					+ '<input type="text" class="sn-input" name="left" title="Type player\'s name" />'
					+ '<div class="value float"></div>'
					+ _changeHtml
				+ '</div>'
				+ '<div class="vs float">vs.</div>'
				+ '<div class="input right float sn-input">'
					+ '<input type="text" class="sn-input" name="right" title="Player 2" disabled="true" />'
					+ '<div class="comment"></div>'
					+ '<div class="value float"></div>'
					+ _changeHtml
				+ '</div>'
				+ _clearHtml
			;
			
			_compareContainer.html($html);
				
			_compareContainer.find('.change a').click(function()
			{
				_self.clearCompareValue($(this).parents('.input').find('input:textbox'));
				return false;
			});
			
			_compareContainer.find('input:textbox')
				.hint()
				
				.autocomplete(SPORTSNET_PLAYERS[_sport], {
					minChars: 0,
					width: 200,
					matchContains: true,
					autoFill: false,
					formatItem: function(row, i, max) 
					{
						// make sure we show players of the same position in the drop down on the right
						if (_comparePosition != null && row[2] != _comparePosition)
							return false;

						// make sure we don't show the same player in the right drop down
						if (_comparePlayerId != null && row[0] == _comparePlayerId)
							return false;
							
						return row[1];
					},
					formatMatch: function(row, i, max) 
					{
						return row[1];
					},
					formatResult: function(row) 
					{
						return row[1];
					}
				})
				
				.bind('result', function(e, data)
				{
					_self.setCompareValue(this, data);
				})
			;
		};
		
		function createPositions()
		{
			var $html = ''
				+ '<div class="title">Position:</div>'
				+ '<div class="items">'
				;

			for (var $i = 0; $i < _data.length; $i++)
			{
				var $position = _data[$i],
					$value = $position.name,
					$id = 'sport-position-' + $value 
					;
				
				$html += ''
					+ '<div class="radio position">'
						+ '<input type="radio" id="' + $id + '" name="' + field('position') + '" value="' + $value + '" />'
						+ '<div class="label-box">'
							+ '<label for="' + $id + '">' + $position.label + '</label>'
						+ '</div>'
					+ '</div>'
					;
			}
			
			$html += ''
				+ '</div>'
				+ _changeHtml
				+ _clearHtml
				;

			_positionsContainer.html($html);
			
			// check if there's just one position in current sport and act accordingly
			if (_data.length == 1 && _data[0].name == 'default')
			{
				_positionsContainer.hide();
				_root.addClass('no-position');
				_self.selectPosition(_positionsContainer.find('input:radio')[0]);
			}
		};

		function vsTeam(name, selected)
		{
			var $teams = sortByField(SPORTSNET_TEAMS[_sport], 2),
				$html = ''
					+ '<select size="1" name="' + name + '">'
						+ '<option value=""></option>'
				;
				
			for (var $i = 0; $i < $teams.length; $i++)
				$html += '<option value="' + $teams[$i][0] + '">' + $teams[$i][2] + '</option>';
			
			$html += '</select>'
			
			return $html;
		};
		
		function createMeasure(measures)
		{
			var $html = ''
				+ '<div class="title">Sort by:</div>'
				+ '<div class="items">'
				;

			for (var $i = 0; $i < measures.length; $i++)
			{
				var $measure = measures[$i],
					$value = $measure.name,
					$id = 'sport-measure-' + $value
					;
				
				$html += ''
					+ '<div class="radio measure">'
						+ '<input type="radio" id="' + $id + '" name="' + field('measure') + '" value="' + $value + '" />'
						+ '<div class="label-box">'
							+ '<label for="' + $id + '">' + $measure.label + '</label>'
						+ '</div>'
					+ '</div>'
					;
			}
			
			$html += ''
				+ '</div>'
				+ _changeHtml
				+ _clearHtml
				;
			
			var $hasPositions = _positionsContainer.is(':visible');
			
			_root.removeClass('prefilled-measure');
			_measuresContainer.html($html);
			setColumns(_measuresContainer, $hasPositions ? 2 : 3);

			if ($hasPositions)
				_measuresContainer.find('.items').css('margin-left', getWidth(_positionsContainer));
		};
		
		function createStats(stats)
		{
			if (stats == null || stats.length == 0)
			{
				_root.addClass('no-stats');
				return;
			}
						
			var $html = ''
				+ '<a href="#" class="more">Add stats</a>'
				+ '<div class="message">Choose up to 5 additional stats (<span class="counter">5</span> left)</div>'
				+ '<div class="items">'
				;
				
			for (var $i = 0; $i < stats.length; $i++)
			{
				var $item = stats[$i],
					$value = $item.name,
					$id = 'sport-stats-' + $value 
					;
				
				$html += ''
					+ '<div class="radio stats">'
						+ '<input type="checkbox" id="' + $id + '" name="' + field('stats', '') + '" value="' + $value + '" />'
						+ '<div class="label-box">'
							+ '<label for="' + $id + '">' + $item.label + '</label>'
						+ '</div>'
					+ '</div>'
					;
			}
			
			$html += ''
				+ '</div>'
				+ '<div style="clear: both" class="toggled-clear"></div>'
				;
			
			_root.removeClass('prefilled-stats');
			_statsContainer.html($html);
			setColumns(_statsContainer);
		};
		
		function createDimensions(dimensions)
		{
			if (dimensions == null || dimensions.length == 0)
			{
				_root.addClass('no-dimensions');
				return;
			}
			
			var $html = ''
				+ '<div class="title">Only show:</div>'
				+ '<div class="items-group">'
				;
				
			for (var $dimensionIndex = 0; $dimensionIndex < dimensions.length; $dimensionIndex ++)
			{
				var $dimensions = dimensions[$dimensionIndex];
				
				$html += '<div class="items">';
				
				for (var $i = 0; $i < $dimensions.length; $i++)
				{
					var $dimension = $dimensions[$i],
						$value = $dimension.name,
						$id = 'sport-dimension-' + $dimensionIndex + '-' + $value,
						$vs = ($value == 'vs_team')
						;
				
					$html += ''
						+ '<div class="radio dimension ' + ($vs ? 'vs' : '') + '">'
							+ '<input type="radio" id="' + $id + '" name="' + field('dimension' + $dimensionIndex) + '" value="' + $value + '" />'
							+ '<div class="label-box">'
								+ '<label for="' + $id + '">' + $dimension.label + '</label>'
								+ ($vs ? vsTeam(field('dimension' + $dimensionIndex, 'vs_team')) : '')
							+ '</div>'
						+ '</div>'
						;
				}
				
				$html += ''
				 		+ _clearHtml
					+ '</div>'
					;
			}
			
			$html += '' 
					+ _clearHtml
				+ '</div>'
				;
			
			_root.removeClass('prefilled-dimensions');
			_dimensionsContainer.html($html);
			_dimensionsContainer.find('.items:first').addClass('first');
			_dimensionsContainer.find('.items:last').addClass('last');
			
			setColumns(_dimensionsContainer);
		};
		
		function initLayout()
		{
			if ($.browser.msie6)
				_root.addClass('ie6');
			else if ($.browser.msie7)
				_root.addClass('ie7');
							
			_root.html();
			_root.html(''
				+ '<div class="tabs">'
					+ (SPORTSNET_TEAM_STATS_TARGET ? '<div class="arrow" style="float:right;"><a href="'+SPORTSNET_TEAM_STATS_TARGET+'" class="today-link">Team Stats</a></div>' : '')
					+ '<div class="tab-section custom-tab on"><a href="#">Custom Stat Search</a></div>'
					+ '<div class="tab-section compare-tab"><a href="#">Compare With</a></div>'
				+ '</div>'
				+ _clearHtml
				+ '<div class="compare"></div>'
				+ '<form method="post" name="statsForm" id="statsForm" action="' + SPORTSNET_PLAYER_STATS_TARGET + '">'
					+ '<input type="hidden" name="' + field('compare', 'left') + '" />'
					+ '<input type="hidden" name="' + field('compare', 'right') + '" />'
					+ '<div class="box">'
						+ '<div class="section position"></div>'
						+ '<div class="section measures"></div>'
						+ '<div class="section dimensions"></div>'
						+ _clearHtml
					+ '</div>'
					+ '<div class="section stats"></div>'
					+ '<div class="buttonHolder">'
						+ '<a href="#" class="button buttonInactive"><span>Get Stats Now</span></a>'
					+ '</div>'
				+ '</form>'
				);
				
			// add non-functional bits for tab visuals
			_root.find('.tabs > div > a')
				.before('<span class="left"></span>')
				.after('<span class="right"></span>')
				;

			_compareContainer = _root.find('.compare');
			_positionsContainer = _root.find('.position');
			_measuresContainer = _root.find('.measures');
			_dimensionsContainer = _root.find('.dimensions');
			_statsContainer = _root.find('.stats');
			
			_compareContainer.hide();
			createPositions();
			_self.setSelected(values);
			
			bindEvents();
		};
		
		// rebinds all radio buttons, checkboxes and '(change)' links
		function bindEvents()
		{
			_positionsContainer.find('input:radio').unbind().click(function()
			{
				_self.selectPosition(this);
				_self.activateButton(true);
			});
			
			_positionsContainer.find('.change a').unbind().click(function()
			{
				_self.deselectPosition(this);
				return false;
			});

			_measuresContainer.find('input:radio').unbind().click(function()
			{
				_self.selectMeasure(this);
			});

			_measuresContainer.find('.change a').unbind().click(function()
			{
				_self.deselectMeasure(this);
				return false;
			});
			
			_dimensionsContainer.find('input:radio').unbind().click(function()
			{
				_self.selectDimension(this);
			});

			_dimensionsContainer.find('.prefilled .change a').unbind().click(function()
			{
				_self.deselectDimension(this);
				return false;
			});
						
			_statsContainer.find('input:checkbox').unbind().click(function()
			{
				_self.toggleStats(this);
			});
			
			_statsContainer.find('a').unbind().click(function()
			{
				_self.toggleStatsSection(this);
				return false;
			});
			
			_root.find('.compare-tab a').unbind().click(function()
			{
				_self.activateCompareTab();
				return false;
			});

			_root.find('.custom-tab a').unbind().click(function()
			{
				_self.activateCustomTab();
				return false;
			});

			_root.find('a.button').click(function()
			{
				if ($(this).hasClass('buttonInactive') == false)
					$("#statsForm").submit();
					
				return false;
			});
			
			// make sure that all selects activate their respective radios
			_dimensionsContainer.find('select').unbind().change(function()
			{
				$(this).parents('.radio').find('input:radio').attr('checked', true);
			});
		};
		
		// Initialization ------------------------------------------------------------------

		initLayout();
	};

	// jQuery plugin implementation
	$.fn.playerStats = function(values)
	{ 
		this.each(function() 
		{
			var $instance = new PlayerStats($(this), values);
			$(this).data('playerStats', $instance);
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function DateManager(root, conf)
	{	
		// Private fields -------------------------------------------------------------------

		var _root = $(root),
			_next = _root.find('.next'),
			_prev = _root.find('.prev'),
			_input = _root.find('input'),
			_curDate = _input.val(),
			_changeDateButtons = [],
			_cookieName = "sn_date",
			_cookieValue = null;
			_self = this
			;
			
		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			changeDate: function (_date, _increment) {
				var newDateObj = new Date(_date.getFullYear(), _date.getMonth(), (_date.getDate() + _increment));
				return newDateObj;
			},
			onOpenDatePick: function () {
				_changeDateButtons.each(function(){
					this.style.display = "none";
				});
			},
			onCloseDatePick: function () {
				_changeDateButtons.each(function(){
					this.style.display = "block";
				});
				//_changeDateButtons.show();
			}
		});

		// Private methods -----------------------------------------------------------------

		// generic binding function
		function bind(name, fn)
		{
			if ($.isFunction(fn))
				$(_self).bind(name, fn);
		};
				
		function initLayout(){
			if (conf.highlightWeek == true)
				$('#datepicker-wrapper').addClass('weeks');

			// generate layout -----------------------------------------
			//console.log("curDate: "+curDate)
			$('#embedded-datepicker').datepick($.extend({
				mandatory: true,
				showDefault: true,
				numberOfMonths: 3,
				showCurrentAtPos: 2,
				stepMonths: 3,
				showOtherMonths: true,
				showOn: 'both',
				buttonImageOnly: true,
				buttonImage: '/assets/img/date_picker/calendar.gif',
				dateFormat: 'MM d, yy',
				changeMonth: false,
				changeYear: false,
				showAnim: 'slideDown',
				duration: 100,
				paddingTop: 5,
				paddingLeft: 0,
				onClose: function(){
					_self.onCloseDatePick();
				},
				onOpen: function(){
					_self.onOpenDatePick();
				}
			}, conf));
			
			_changeDateButtons = $('.change-date');
			_changeDateButtons.click(function(){
				var input = $.datepick._getInst($("#embedded-datepicker")[0]);
				var curDisplayDate = $.datepick._getDate(input);
				var newDate;
				if ($(this).hasClass('next')) {
					newDate = _self.changeDate(curDisplayDate, (conf.highlightWeek == true ? 7 : 1));
				}
				else {
					newDate = _self.changeDate(curDisplayDate, (conf.highlightWeek == true ? -7 : -1));
				}
				$.datepick._setDate(input, newDate);
				$('#embedded-datepicker').trigger('change');
				return false;
			});
			_changeDateButtons.hover(
				function(){
					$(this).addClass("hover");
				},
				function(){
					$(this).removeClass("hover");
				}
			);
			
			$('#embedded-datepicker').change(function(){
				$('#dateInput').val($.datepick.formatDate('yymmdd', $.datepick._getDate($.datepick._getInst($("#embedded-datepicker")[0]))));
				$('#datepickerForm').submit();
			});
			
			$(window).resize(function(){
				$.datepick._hideDatepick();
			});
		}

		// Initialization ------------------------------------------------------------------
		
		initLayout();
	};

	// jQuery plugin implementation
	$.fn.dateManager = function(conf)
	{
		// update dates from array to match what we expect
		if ($.isArray(conf.selectedDates))
		{
			var $dates = conf.selectedDates;
			
			for (var $i = 0; $i < $dates.length; $i++)
			{
				var $date = new Date($dates[$i] * 1000);
				$date.setHours(0);
				$dates[$i] = $date.getTime(); 
			}
		}
		
		this.each(function()
		{
			var $instance = new DateManager($(this), conf);
			$(this).data("dateManager", $instance);
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function TeamFeatureStory(root)
	{	
		// Private fields ------------------------------------------------------------------
		var _root = $(root),
			_domElement = _root[0],
			_self = this,
			_opts = {
				debug: false
			}
			;
	
		// Public methods ------------------------------------------------------------------
//		$.extend(_self, {
//		});
	
		// Private methods -----------------------------------------------------------------
		function debug(str)
		{
			if (_opts.debug == true) {
				try {
					trace(str);
				} 
				catch (e) {
					alert("debug: " + str);
				}
			}
		};
		
		function scaleSummary()
		{
			var availHeight = $(_root.parent()).parent().outerHeight();
			availHeight -= _root.outerHeight();
			debug("availHeight: " + availHeight);
			var summaryElem = _root.find('.summary:first');
			
			summaryElem.css({height:"auto"});
			debug("summaryElem.height(): " + summaryElem.height());
			if (summaryElem.height() > availHeight) {
				summaryElem.css({height:"0px"});
			
				var lineHeight = Math.ceil((summaryElem.css('line-height').split('p'))[0]);
				var numRows = Math.floor(availHeight / lineHeight);
				var summaryHeight = numRows * lineHeight;
				
				summaryElem.height(summaryHeight);
			}
			
			try {
				sportsnetPage.registerInit({
					_expression: ".ellipsis",
					_functionRef: "ellipsis",
					_rank: "DISPLAY"
				});
			}
			catch (e) {
				summaryElem.ellipsis();
			}
		};
	
		function init()
		{	
			scaleSummary();
		};
	
		// Initialization ------------------------------------------------------------------
		init();
	};
	
	// jQuery plugin implementation
	$.fn.teamFeatureStory = function()
	{
		this.each(function()
		{
			var $instance = new TeamFeatureStory($(this));
		});
		
		return this;
	};
})(jQuery);
(function($)
{	
	// constructor
	function Gallery(root, conf)
	{	
		// Private fields ------------------------------------------------------------------

		var _root = $(root),
			_self = this,
			_thumbs,
			_featureContainer,
			_selectedIndex,
			_playIntervalId = 0,
			_playButton,
			_scroller
			;

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			showImage: function(index, keepAutoPlaying)
			{
				var $thumb = $(_thumbs[index]),
					$a = $thumb.find('a'),
					$src = $a.data('src')
					;
				
				_featureContainer.html('<img src="' + $src + '" class="feature img">');
				
				// fade feature image in if not in IE6
				if ($.browser.msie6 == false)
					conf.showFunc(_featureContainer.find('.feature').hide());
				
				// update 'N of X' label
				_root.find('.controls .position').html((index + 1) + ' of ' + _thumbs.length);
				
				// update text labels
				_root.find('.middle > .text').html($thumb.find('.text').html());
				_root.find('.bottom > .meta').html($thumb.find('.meta').html());
				
				// place selection on the correct thumb
				_thumbs.find('.selection').remove();
				$(_thumbs[index]).append('<div class="selection"></div>');
				
				var $expectedPageIndex = Math.floor(index / _scroller.getPageSize());
				
				if (_scroller.getPageIndex() != $expectedPageIndex)
					_scroller.setPage($expectedPageIndex)
				
				_selectedIndex = index;
				
				if (keepAutoPlaying != true && _playIntervalId > 0)
					_self.pause();
			},
			
			prevImage: function()
			{
				if (--_selectedIndex < 0)
					_selectedIndex = _thumbs.length - 1;
					
				_self.showImage(_selectedIndex)
//				_self.updateAds();
			},
			
			nextImage: function(keepAutoPlaying)
			{
				// if next image would be looped and we are autoplaying, then pause
				if (keepAutoPlaying == true && _selectedIndex >= _thumbs.length)
				{
					_self.pause();
					++_selectedIndex;
				}
				else if (++_selectedIndex >= _thumbs.length)
				{
					_selectedIndex = 0;
					keepAutoPlaying = false;
				}
				
				_self.showImage(_selectedIndex, keepAutoPlaying);
//				_self.updateAds();
			},
			
			play: function()
			{
				_self.pause();
				_playIntervalId = setInterval(function() { _self.nextImage(true /* keep autoplaying */) }, conf.playbackDelay);
				_playButton.addClass('pause');
				_self.nextImage(true);
			},
			
			pause: function()
			{
				_playButton.removeClass('pause');
				clearInterval(_playIntervalId);
				_playIntervalId = 0;
			},
			
			playPause: function()
			{
				if (_playIntervalId > 0)
					_self.pause();
				else
					_self.play();
			},
			updateAds: function()
			{
				var $bbAds = $('.right-col-ads').find('.ad'),
					$curBbAd = $bbAds.not('.hidden'),
					$hidBbAds = $bbAds.filter('.hidden'),
					$nextBbAd = $hidBbAds[Math.floor(Math.random() * $hidBbAds.length)];				
					$lbAds = $('.ads-topnav').find('.ad'),
					$curLbAd = $lbAds.not('.hidden'),
					$hidLbAds = $lbAds.filter('.hidden'),
					$nextLbAd = $hidLbAds[Math.floor(Math.random() * $hidLbAds.length)];	
					$ftAds = $('.ads').find('.ad'),
					$curFtAd = $ftAds.not('.hidden'),
					$hidFtAds = $ftAds.filter('.hidden'),
					$nextFtAd = $hidFtAds[Math.floor(Math.random() * $hidFtAds.length)];	
				
				$($curBbAd).addClass('hidden');				
				$($nextBbAd).removeClass('hidden');
				$($curLbAd).addClass('hidden');
				$($nextLbAd).removeClass('hidden');				
				$($curFtAd).addClass('hidden');
				$($nextFtAd).removeClass('hidden');				
			}
		});

		// Private methods -----------------------------------------------------------------
		
		function initLayout()
		{
			if ($.browser.msie6)
				_root.addClass('ie6');
			else if ($.browser.msie7)
				_root.addClass('ie7');
			
			_featureContainer = _root.find('.feature-container');
			
			// set up scrolling panel
			_scroller = _root.find('.scrolling-panel').scrollingPanel({ size: '4x3' }).data('scrollable');
			
			_thumbs = _root.find('.scroll-container ul li');
			
			_thumbs.find('a')
				.each(function(index)
				{
					var $img = $(this).find('img')[0];
					$(this)
						.wrap('<div class="thumb img" style="background-image: url(' + $img.alt + ')">')
						.data('src', $img.src)
						.data('index', index)
						.html('')
					;
				})
				.unbind()
				.click(function()
				{
					_self.showImage($(this).data('index'));
//					_self.updateAds();
					return false;
				})
			;
			
			var $controls = _root.find('.top .controls');
			
			$controls.find('.prev').click(function()
			{
				_self.prevImage();
				return false;
			});

			$controls.find('.next').click(function()
			{
				_self.nextImage();
				return false;
			});
			
			_playButton = $controls.find('.play').click(function()
			{
				_self.playPause();
				return false;
			});
			
			// calculate height of the middle section
			_root.find('.middle').css('height',
				_root.find('.sidebar').height() - 
				_root.find('.bottom').height() - 
				_root.find('.top').height()
				- 10 // some spacing
			);
			
			// show first image
			_self.showImage(conf.index || 0);
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
	};

	// jQuery plugin implementation
	$.fn.gallery = function(conf)
	{ 
		var opts = {
			hideFunc : function(element) { element.hide(); },
			showFunc : function(element) { element.fadeIn(); },
			playbackDelay : 5000
		}; 
		
		$.extend(opts, conf);		
		
		this.each(function() 
		{
			var $instance = new Gallery($(this), opts);
			$(this).data("gallery", $instance);	
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function GalleryFeature(root, conf)
	{	
		// Private fields ------------------------------------------------------------------

		var _root = $(root),
			_self = this
			;

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
		});

		// Private methods -----------------------------------------------------------------
		
		function initLayout()
		{
			if ($.browser.msie6)
				_root.addClass('ie6');
			else if ($.browser.msie7)
				_root.addClass('ie7');
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
	};

	// jQuery plugin implementation
	$.fn.galleryFeature = function(conf)
	{ 
		var opts = {}; 
		$.extend(opts, conf);		
		
		this.each(function() 
		{
			var $instance = new GalleryFeature($(this), opts);
			$(this).data("galleryFeature", $instance);	
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function GalleryRecent(root, conf)
	{	
		// Private fields ------------------------------------------------------------------

		var _root = $(root),
			_self = this
			;

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
		});

		// Private methods -----------------------------------------------------------------
		
		function initLayout()
		{
			if ($.browser.msie6)
				_root.addClass('ie6');
			else if ($.browser.msie7)
				_root.addClass('ie7');
				
			_root.find('.scrolling-panel').scrollingPanel({ size: 2 });
			
			_root.find('.thumb').each(function()
			{
				$(this).hover(function() {											// Hover function added 
									   		$(this).addClass('hover');				// to override IE6 behaviour.
									   }, function() {								//	
										   	$(this).removeClass('hover');			//	Gord 09/08/2009
									   });
				
				var $url = $(this).find('a').attr('href');
				$(this).find('.img').click(function()
				{
					window.location = $url;
					return false;
				});
			});
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
	};

	// jQuery plugin implementation
	$.fn.galleryRecent = function(conf)
	{ 
		var opts = {}; 
		$.extend(opts, conf);		
		
		this.each(function() 
		{
			var $instance = new GalleryRecent($(this), opts);
			$(this).data("galleryRecent", $instance);	
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function GalleryList(root, conf)
	{	
		// Private fields ------------------------------------------------------------------

		var _root = $(root),
			_self = this
			;

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
		});

		// Private methods -----------------------------------------------------------------
		
		function initLayout()
		{
			if ($.browser.msie6)
				_root.addClass('ie6');
			else if ($.browser.msie7)
				_root.addClass('ie7');
							
			_root.find('.thumb').each(function()
			{
				var $url = $(this).find('.meta a').attr('href');
				$(this).find('.img').click(function()
				{
					window.location = $url;
					return false;
				});
				$(this).hover(
					function(){
						$(this).addClass("hover");
					},
					function(){
						$(this).removeClass("hover");
					}
				);
			});
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
	};

	// jQuery plugin implementation
	$.fn.galleryList = function(conf)
	{ 
		var opts = {}; 
		$.extend(opts, conf);		
		
		this.each(function() 
		{
			var $instance = new GalleryList($(this), opts);
			$(this).data("galleryRecent", $instance);	
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function MyHeadlinesLineUp(root)
	{	
		// Private fields -------------------------------------------------------------------

		var _root = $('body'),
			_curLeague = $('#league-selector').val(),
			_myLineUpCookie = "sn_myHeadlinesLineUp",
			_myRegionCookie = "sn_region",
		    _addString = "Add  <img src='/assets/img/my_headlines_lineup/plus_icon.gif' />",
			_removeString = "Remove  <img src='/assets/img/my_headlines_lineup/minus_icon.gif' />",
			_self = this,
			_myLineUp = new Array(),
			_myEmptyLogos = $('#my-lineup-logos').find('.empty');
			_cookieCheck = null,
			_imgPath = "/assets/img/team_logos/scores/59x59/"
			_opts = {
				debug: false
			}
			;  

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			
			//check for channel cookie
			doCookieCheck: function (whichCookie)
			{
				var $myCookie = whichCookie;
				var c = $.cookies.get($myCookie);
				if (c != null) {
					_myLineUp = c.split(',');
					return true;
				} else {
					//alert("doCookieCheck: cookie: "+c);
					return false;
				}
			},	
			
			//set user's channel cookie
			doCookieSet: function (whichCookie, whichValue)
			{
				var $tmp = window.location.href,
					$url = $tmp.split('/'),
					$loc = $url[2].split('.'),
					$dom = '.'+$loc[1]+'.'+$loc[2];
				 var cookieOptions = {
				    path: '/',
					domain: $dom,//'.pairsite.com', //'.sportsnet.ca',
				    hoursToLive: 90000,
				    secure: false
				  }
				var $cookie = whichCookie;
				var $value = whichValue;
				$.cookies.set($cookie, $value, cookieOptions);
				_self.lineupInfoSaved();
			},

			lineupInfoSaved: function ()
			{
				$('p#my-lineup-status').animate({opacity:'toggle'}, 150, function(){
																				  $('p#my-lineup-status').html('<span style="padding: 3px 5px; display: block; background-color: rgb(255, 255, 136)"><b>Your changes have been saved.</b></span>').animate({opacity:'toggle'}, 100);
				});
				//$('p#my-lineup-status').html('<span style="padding: 3px 5px; display: block;"><b>Your changes have been saved.</b></span>').css({'background-color': 'rgb(255, 255, 136)'}).animate({opacity:'toggle'}, 100);
				//$('p#my-lineup-status').css({'background-color': 'rgb(255, 255, 136)'});
				setTimeout(function(){
									$('p#my-lineup-status').animate({opacity:'toggle'}, 150, function(){$('p#my-lineup-status').html('You can follow up to 6 teams.').animate({opacity:'toggle'}, 100);});
									//$('p#my-lineup-status').animate({opacity:'toggle'}, 100).html('You can follow up to 6 teams.').css({'background-color': none});
									},650);
			},
			
			activate: function(obj)
			{
				var $el = obj,
				    $wrap = $el.parents('tr'),
					$img = $wrap.find('.team-logo');
					
				$el.find('a').html(_addString);
				$wrap.css({'background-color' : '#EBEBEB'});
				if ($.browser.msie6 == true){
					$img.css({filter: "alpha(opacity = 100)"});
					$($img.find('img')).css({filter: "alpha(opacity = 100)"});
				} else {
					$img.fadeTo('fast',1);
				}
				$el.toggleClass('selected');
				_self.removeFromLineUp($el.attr('id'));
			},
			
			deactivate: function(obj) 
			{
				var $el = obj,
				    $wrap = $el.parents('tr'),
					$img = $wrap.find('.team-logo');
					
				$el.find('a').html(_removeString);
				$wrap.css({'background-color' : '#FFFFFF'});
				if ($.browser.msie6 == true){
					$img.css({filter: "alpha(opacity = 50)"});
					$($img.find('img')).css({filter: "alpha(opacity = 50)"});
				} else {
					$img.fadeTo('fast',0.5);
				}
				
				$el.toggleClass('selected');

			},
			
			addToLineUp: function(id)
			{
				clearTimeout();
				var str = id.split('_'),
					$league = str[0],
					$team = str[1],
					$cVal = $league+'|'+$team;
					
					_myLineUp.push($cVal);
					_self.doCookieSet(_myLineUpCookie, _myLineUp);
					_self.updateLineUp($league, $team);
				
			},
			
			removeFromLineUp: function(id)
			{
				clearTimeout();
				var str = id.split('_'),
					$league = str[0],
					$team = str[1];
					$cVal = $league+'|'+$team,
					curNode = $('#my-lineup-logos').find('#my_'+id),
					curImg = $(curNode).find('.transparentPng');
					

					_myLineUp = $.grep(_myLineUp,function(value){
						return value != $cVal;
					});
					if (_myLineUp.length == 0) {
						$.cookies.del(_myLineUpCookie);
						$('p#my-lineup-status').html('<b>You are not following any teams.</b>');//alert("Maximum teams reached! At least one team must be removed before you can follow another.  " + $('#my-lineup-logos').find('.empty').length);
					}
					else {
						$('p#my-lineup-status').html('You can follow up to 6 teams.');//alert("Maximum teams reached! At least one team must be removed before you can follow another.  " + $('#my-lineup-logos').find('.empty').length);
						_self.doCookieSet(_myLineUpCookie, _myLineUp);
					}
					curImg.fadeOut('normal', function() {
						$(curImg).attr('src', '');
						$(curNode).find('a').hide();
						$(curNode).addClass('empty');
						$(curNode).removeAttr('id');
						$(curNode).removeClass("hover");
						$('#my-lineup-logos').append($(curNode));
					});
					$('#my-lineup-logos').sortable('refresh');
			},
			
			initLineUp: function()
			{
				for (var i=0; i<_myLineUp.length; i++) {
					_self.debug("_myLineUp[i]: "+ _myLineUp[i]);
					_self.debug("_myEmptyLogos[i]: "+ _myEmptyLogos[i]);
					
					var str = _myLineUp[i].split('|'),
						curLeague = str[0],
						curTeam = str[1],
						curSport = _self.getSport(curLeague),
						curNode = _myEmptyLogos[i],
						curImg = $(curNode).find('.transparentPng'),
						id = curLeague + '_' + curTeam,
						curId = 'my_' + curLeague + '_' + curTeam;
					if ($.browser.msie6 == true) {
						curImg.attr('src', _imgPath + curSport + '/' + curLeague + '/' + curTeam + '.gif');
					} else {
						curImg.attr('src', _imgPath + curSport + '/' + curLeague + '/' + curTeam + '.png');
					};
					curImg.addClass('logo');
					curImg.fadeIn('fast');
					$(curNode).toggleClass('empty');
					$(curNode).attr('id', curId); 
					_self.deactivate($('#'+id));
				}
				_self.initSortable();
			},
			
			updateLineUp: function(league, team) {
				var curNode = $('#my-lineup-logos').find('.empty')[0],
					curImg = $(curNode).find('.transparentPng'),
					curLeague = league,
					curTeam = team,
					curSport = _self.getSport(curLeague),
					curId = 'my_' + curLeague + '_' + curTeam;
					
				if ($.browser.msie6 == true) {
					curImg.attr('src', _imgPath + curSport + '/' + curLeague + '/' + curTeam + '.gif');
				} else {
					curImg.attr('src', _imgPath + curSport + '/' + curLeague + '/' + curTeam + '.png');
				};
				curImg.addClass('logo');
				curImg.fadeIn('fast');
				$(curNode).toggleClass('empty');
				$(curNode).attr('id', curId); 
				$('p#my-lineup-status').html('You can follow up to 6 teams.');//alert("Maximum teams reached! At least one team must be removed before you can follow another.  " + $('#my-lineup-logos').find('.empty').length);
			},
			
			initSortable: function() {
				
				$('#my-lineup-logos').sortable({ 
											   	items: "li:not('.empty')",
												tolerance: 'pointer',
												cursorAt: 'top',
												revert: '100',
												cancel: '.empty',
												start: function(event, ui) {
																		ui.item.unbind('mouseenter mouseleave');
																		ui.item.removeClass('hover');
																		ui.item.find('a').hide();
																		//TODO - disable hover state
																	},
												update: function() {
																		//TODO - activate hover state
																		
																		var $cookie = $('#my-lineup-logos').sortable('toArray');
																		for(var i = 0; i<$cookie.length; i++) {
																			var curNode = $cookie[i],
																				str = curNode.split('_');
																				
																			$cookie[i] = str[1] + "|" + str[2];	
																		}
																		_self.doCookieSet( _myLineUpCookie, $cookie);
																	},
												stop: function(event, ui) {
																		ui.item.hover(function() {
																				if($(this).hasClass('empty') == false) {
																					$(this).find('a').toggle();
																					$(this).addClass("hover");
																				} else {
																					$(this).addClass("emptyHover");
																				}
															
																			}, function() {
																				if ($(this).hasClass('empty') == false) {
																					$(this).find('a').toggle();
																					$(this).removeClass("hover");
																				} else {
																					$(this).removeClass("emptyHover");
																				}
																		});
																		//ui.item.addClass('hover');
																		//ui.item.find('a').show();
																	}					
											});
				$('#my-lineup-logos').disableSelection();							
			},
			killSortable: function() {
				$('#my-lineup-logos').sortable('destroy');
			},
			
			getSport: function(league) 
			{
					var sport = null;
					
					switch(league){
						case "nhl":
							sport = "hockey";
							break;
						case "mlb":
							sport = "baseball";
							break;
						case "nfl": 
							sport = "football";
							break;
						case "cfl":
							sport = "football";
							break;
						default:
							sport = "basketball";		
							break;
							
					}
					return sport;
			},
			
			reloadPage: function () 
			{
				location.reload();
			},

			debug: function(str)
			{
				if (_opts.debug == true) {
					try {
						trace(str);
					} 
					catch (e) {
						alert(str);
					}
				}
			}
		});

		// Private methods ----------------------------------------------------------------
		function initLayout()
		{	

			$("#"+_curLeague).toggleClass('hidden');

			_cookieCheck = _self.doCookieCheck('sn_myHeadlinesLineUp');
			
			if (_cookieCheck == true){
				_self.initLineUp();	
			} else {
				_myLineUp = window.sn_HeadlinesLineUp.split(",");
				_self.doCookieSet(_myLineUpCookie, _myLineUp);
				_self.initLineUp();
			};
		
			$('.select-team').click(function(){
				var $this = $(this);
				if ($this.hasClass('selected')) {
					_self.activate($this);
				} else {
					if($('#my-lineup-logos').find('.empty').length > 0){
						//_self.debug("$('#my-lineup-logos').find('.empty').length: "+$('#my-lineup-logos').find('.empty').length);
						_self.deactivate($this);
						_self.addToLineUp($this.attr('id'));
					} else {
						$('p#my-lineup-status').html('You can follow up to 6 teams. <b>To add another, remove a team first.</b>');
						alert("You can follow up to 6 teams. To add another, remove a team first.");
					}
				};
				
				return false;
			});
			
																			
											
			
			$('.my-lineup-logo').hover(function() {
					if($(this).hasClass('empty') == false) {
						$(this).find('a').toggle();
						$(this).addClass("hover");
					} else {
						$(this).addClass("emptyHover");
					}

				}, function() {
					if ($(this).hasClass('empty') == false) {
						$(this).find('a').toggle();
						$(this).removeClass("hover");
					} else {
						$(this).removeClass("emptyHover");
					}
			});
			
			$('.my-lineup-logo a').click(function() {
				_self.debug("my-lineup-logo a').click");
				var $par = $(this).parent()
				if ($par.hasClass('empty') == false) {
					$par.find('a').toggle();
					$par.removeClass("hover");
				} else {
					$par.removeClass("emptyHover");
				}

				var $this = $(this),
				  	$parent = $this.parent(),
					str = $parent.attr('id'),
					$id = str.split('my_');
					
				_self.debug("$id: "+$id);
				
				_self.activate($('#'+$id[1]));
				$this.toggle();
				
				return false;
			});

												  
			$('#league-selector').change(function() {
				var $oldLeague = _curLeague;
				_curLeague = $('#league-selector').val();
					$("#"+$oldLeague).toggleClass('hidden');
					$("#"+_curLeague).toggleClass('hidden');							   
			});

		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
		

	};

	// jQuery plugin implementation
	$.fn.myHeadlinesLineUp = function()
	{ 
		this.each(function() 
		{
			var $instance = new MyHeadlinesLineUp($(this));
			$(this).data("myHeadlinesLineUp", $instance);
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function MyHeadlinesModule(root)
	{	
		// Private fields -------------------------------------------------------------------

		var _root = $('body'),
			_cookieCheck = null,
			_myLineUpCookie = "sn_myHeadlinesLineUp",
			_myPrefCookie = "sn_myHeadlinesPref",
			_myRegionCookie = "sn_region",
			_myRegion = null,
			_myPref = null,
			_myLineUp = new Array(),
			_myTeamTabs = $('.headlines-teams-listing').find('li'),
			_myHeadlinesWrapper = $('div.headlines-teams-news-listing .news-wrapper'),
			_myTeampageLinks = $('div.headlines-teams-news-listing .customize-headlines-holder'),
			_imgPath = "/assets/img/team_logos/scores/38x38/",
			_self = this,
			_opts = {
				debug: false
			};  

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			
			//check for channel cookie
			doCookieCheck: function (whichCookie)
			{
				var $myCookie = whichCookie;
				var c = $.cookies.get($myCookie);
				if (c != null) {
					if($myCookie = _myLineUpCookie){
						_myLineUp = c.split(',');
					} else if ($myCookie = _myPrefCookie){
						_myPref = c;	
					}
					return true;
				
				} else {
					return false;
				}
			},	
			
			//set user's channel cookie
			doCookieSet: function (whichCookie, whichValue)
			{
				var $tmp = window.location.href,
					$url = $tmp.split('/'),
					$loc = $url[2].split('.'),
					$dom = '.'+$loc[1]+'.'+$loc[2];
				 var cookieOptions = {
				    path: '/',
					domain: $dom,//'.pairsite.com', //'.sportsnet.ca',
				    hoursToLive: 90000,
				    secure: false
				  }
				var $cookie = whichCookie;
				var $value = whichValue;
				$.cookies.set($cookie, $value, cookieOptions);

			},
			
			initPrefCookieSet: function ()
			{
				var $prefTabLink = $('.tabs-container').find('a');
				
				$($prefTabLink).click(function() {
						var $this = $(this),
							$parent = $($this).parent('div');
							
						if($parent.hasClass('active')) {
							if($parent.hasClass('first')) {
								_myPref = "recent";				  
							} else {
								_myPref = "my_headlines";	
							}
							_self.doCookieSet(_myPrefCookie, _myPref);					  
						}
					});
				
				
			},
			
			activate: function(obj)
			{		
				var $el = obj,
					$old = $('.headlines-teams-listing').find('.selected-team'),
					$id = $el.attr('id');
				
				_self.debug("$old: " + $old.html());
				
				$old.removeClass('selected-team');	
				$el.addClass('selected-team');
				
				_myHeadlinesWrapper.each(function() {
					if($(this).hasClass('hidden') == false){
						$(this).toggleClass('hidden');
					};
				});
				_myTeampageLinks.each(function() {
					if($(this).hasClass('hidden') == false){
						$(this).toggleClass('hidden');
					};
				});
				
				$('#'+$id+'_headlines').removeClass('hidden');
				$('#'+$id+'_pagelink').removeClass('hidden');
			},
			
			initLineUp: function()
			{	
				for (var i=0; i<_myLineUp.length; i++) {
					var str = _myLineUp[i].split('|'),
						curLeague = str[0],
						curTeam = str[1],
						curSport = _self.getSport(curLeague),
						curNode = _myTeamTabs[i],
						curHeadlines = _myHeadlinesWrapper[i],
						curTeamlink = _myTeampageLinks[i],
						curImg = $(curNode).find('.my-module-logo'),
						curId = curLeague + '_' + curTeam;

					if ($.browser.msie6 == true) {
						curImg.attr('src', _imgPath + curSport + '/' + curLeague + '/' + curTeam + '.gif');
					} else {
						curImg.attr('src', _imgPath + curSport + '/' + curLeague + '/' + curTeam + '.png');
					};
					curImg.fadeIn('fast');
					$(curHeadlines).attr('id', curId+'_headlines');
					$(curTeamlink).attr('id', curId+'_pagelink');
					$(curNode).attr('id', curId);
					$(curNode).css('cursor', 'pointer');
					$(curNode).click(function() {
						_self.activate($(this));
					});
				}
			},
			
			getSport: function(league) 
			{
					var sport = null;
					
					switch(league){
						case "nhl":
							sport = "hockey";
							break;
						case "mlb":
							sport = "baseball";
							break;
						case "nfl": 
							sport = "football";
							break;
						case "cfl":
							sport = "football";
							break;
						default:
							sport = "basketball";		
							break;
							
					}
					return sport;
			},
			
			reloadPage: function () 
			{
				location.reload();
			},

			debug: function(str)
			{
				if (_opts.debug == true) {
					try {
						trace(str);
					} 
					catch (e) {
						alert(str);
					}
				}
			}
		});

		// Private methods ----------------------------------------------------------------
		function initLayout()
		{	
			_prefCookieCheck = _self.doCookieCheck('sn_myHeadlinesPref');
			_lineupCookieCheck = _self.doCookieCheck('sn_myHeadlinesLineUp');
			_self.debug("_lineupCookieCheck: " + _lineupCookieCheck);
			_self.debug("_prefCookieCheck: " + _prefCookieCheck);
			
			if (_lineupCookieCheck == true){
				_self.initLineUp();	
			} else {
				_myLineUp = window.sn_HeadlinesLineUp.split(",");
				_self.initLineUp();
			};

			if (_prefCookieCheck == true){
				_self.initPrefCookieSet();	
			} else {
				_myPref = "recent";
				_self.initPrefCookieSet();
			};
			
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
		

	};

	// jQuery plugin implementation
	$.fn.myHeadlinesModule = function()
	{ 
		this.each(function() 
		{
			var $instance = new MyHeadlinesModule($(this));
			$(this).data("myHeadlinesModule", $instance);
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function Scores(root, conf)
	{	
		// Private fields ------------------------------------------------------------------

		var _root = $(root),
			_self = this,
			_index = 0,
			_gameId = -1,
			_intervalId = 0
			;

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
		});

		// Private methods -----------------------------------------------------------------
		
		function initLayout()
		{
			if ($.browser.msie6)
				_root.addClass('ie6');
			else if ($.browser.msie7)
				_root.addClass('ie7');
			
			_gameId = /gameid-(\d+)/.exec(_root[0].className)[1];
			
			_intervalId = setInterval(function()
			{
				$.get(
					conf.updateUrl + '?id=' + _gameId + '&s=' + Math.random() + '&i=' + _index,
					{ i : _index },
					function(html)
					{
						_root.html(html);
						
						// clear querying interval when the game is marked final
						if (_root.find('.mini-scoreboard-header .periods').hasClass('final'))
						{
							clearInterval(_intervalId);
						}
						
						_index++;
					}
				);
			},
			opts.refresh
			);
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
	};

	// jQuery plugin implementation
	$.fn.scores = function(conf)
	{ 
		var opts = {
			refresh : 5000,
			updateUrl : '/ui_components/stats_modules/scores_render.php'
		};
		
		$.extend(opts, conf);		
		
		this.each(function() 
		{
			var $instance = new Scores($(this), opts);
			$(this).data("scores", $instance);	
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function ShowHideDetails(root, conf)
	{	
		// Private fields -------------------------------------------------------------------
		var _root = $(root),
			_trigger = _root.find('.details-link'),
			_target = _root.parent().find(".showhide-details-content"),
			_self = this,
			_opts = {
				debug: false,
				openString: _trigger.text(), //defaults
				closeString: _trigger.attr('name'),
				onOpen: null, //callbacks - passed directly to animation functions
				onClose: null
			};
		$.extend(_opts, conf);
			
		// Public methods ------------------------------------------------------------------


		// Private methods ----------------------------------------------------------------
		function initLayout()
		{	
			_trigger.click(function() {
				if ($(this).hasClass('opened')) {
					_target.slideUp(200, _opts.onClose);
					$(this).toggleClass('opened');
					
						$(this).text(_opts.openString);
					
						
					
				}
				else {
					_target.slideDown(200, _opts.onOpen);
					$(this).toggleClass('opened');
					if(_trigger.attr('name') != undefined && _trigger.attr('name') != "") {
						$(this).text(_opts.closeString);
					} else {
						$(this).text(_opts.openString);
					}
				}
				return false;
			});
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
		

	};

	// jQuery plugin implementation
	$.fn.showHideDetails = function(conf)
	{ 
		var opts = {};
		$.extend(opts, conf);
		
		this.each(function() 
		{
			var $instance = new ShowHideDetails($(this), opts);
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function TrackerPoll(root, conf)
	{	
		// Private fields -------------------------------------------------------------------
		var _root = $(root),
			_optionTrigger = _root.find('.poll-option'),
			_viewTrigger = _root.find('.poll-view-results'),
			_voteTrigger = _root.find('.poll-vote-now'),
			_choicesTarget = _root.find('.poll-choices'),
			_resultsTarget = _root.find(".poll-results"), 
			_resultsTargetText = _root.find(".poll-results span"), 
			_self = this;

	
		// Public methods ------------------------------------------------------------------


		// Private methods ----------------------------------------------------------------
		function initLayout()
		{	
			var fadeSpeed = 50;

			_optionTrigger.click(function() {
                $.ajax({
                    url: "/scrum/poll_vote.php",
                    cache: false,
                    data: "mode=tracker&response_id="+$(this).attr('href').substr(1),
                    success: function(html) {
                        _resultsTarget.html(html);

                        if ($.browser.msie6) { //fade messes up in ie6
                            _choicesTarget.hide();
                            _resultsTarget.show();
                        } else {
                            _choicesTarget.fadeOut(fadeSpeed, function(){
                                _resultsTarget.fadeIn(fadeSpeed);
                            });
                        }
                    }
                });

				return false;
			});
			
			_viewTrigger.click(function() {
                $.ajax({
                    url: "/scrum/poll_vote.php",
                    cache: false,
                    data: "mode=tracker&poll_id="+$(this).attr('href').substr(1),
                    success: function(html) {
                        _resultsTargetText.html(html);

                        if ($.browser.msie6) { //fade messes up in ie6
                            _choicesTarget.hide();
                            _resultsTarget.show();
                        } else {
                            _choicesTarget.fadeOut(fadeSpeed, function(){
                                _resultsTarget.fadeIn(fadeSpeed);
                            });
                        }
                    }
                });
				return false;
			});
			
			_voteTrigger.click(function() {
				if ($.browser.msie6) { //fade messes up in ie6
					_resultsTarget.hide();
					_choicesTarget.show();
				}
				else {
					_resultsTarget.fadeOut(fadeSpeed, function(){
						_choicesTarget.fadeIn(fadeSpeed);
					});
				}
				return false;
			});
			
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
		

	};

	// jQuery plugin implementation
	$.fn.trackerPoll = function()
	{ 
		var opts = {};
		$.extend(opts);
		
		this.each(function() 
		{
			var $instance = new TrackerPoll($(this));
		});
		
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function TabNav(root)
	{	
		// Private fields ------------------------------------------------------------------
		var _root = $(root),
			_self = this,
			_navTabs,
			_tabBottoms,
			_tabContentElems,
			_idx = 0,
			_old
			;
			
		// Public methods ------------------------------------------------------------------
		$.extend(_self, {
			onTabClick: function(tabElem) {
				var $tabElem = $(tabElem),
					_old = _idx;
					
				_idx = _navTabs.index($tabElem);
				
				_navTabs.eq(_old).toggleClass('on');
				_navTabs.eq(_idx).toggleClass('on');
				
				_tabBottoms.eq(_old).toggleClass('on');
				_tabBottoms.eq(_idx).toggleClass('on');
				
				_tabContentElems.eq(_old).toggleClass('hidden');
				_tabContentElems.eq(_idx).toggleClass('hidden');
				
				return false;
			}
		});
	
		// Private methods ------------------------------------------------------------------
		function init()
		{	
			//var $idx = 0;
			_navTabs = _root.find('td.tab-nav-option').click(function(){
				_self.onTabClick(this);
			});
			_navTabs.find("a").click(function(){
				_self.onTabClick($(this).closest("td.tab-nav-option"));
				return false;
			});
			_tabBottoms = _root.find('td.bottom-row');
			_tabContentElems = $('ul.tabs-featured');
		};
	
		// Initialization ------------------------------------------------------------------
		init();
	};
	
	// jQuery plugin implementation
	$.fn.tabNav = function()
	{
		
		this.each(function()
		{
			var $instance = new TabNav($(this));
		});
		
		return this;
	};
})(jQuery);
(function($)
{	
	// constructor
	function FollowTeamLink(root, conf)
	{	
		// Private fields -------------------------------------------------------------------
		var _root = $(root),
			_element = _root[0],
			_label = _root.find(".follow-team-label"),
			_self = this,
			_addLabel = "Follow this team",
			_addHelp = "Click to add this team to \"My Headlines\" line-up.",
			_removeLabel = "Stop following this team",
			_removeHelp = "Click to remove this team from \"My Headlines\" line-up.",
			_editLabel = "Edit \"My Headlines\" teams",
			_editHelp = "You are already following 6 teams. Click to go to \"My Headlines\" page and edit your line-up.",
			_myHeadlinesURL = "/myheadlines/",
			_cookieOptions = {
				    path: '/',
				    hoursToLive: 90000,
				    secure: false
				  },
			_opts = {
				debug: false,
				lineupId: null
			};
			$.extend(_opts, conf);

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			reloadPage: function () 
			{
				location.reload();
			},
			getMyLineUp: function () 
			{
				var cookieVal = $.cookie("sn_myHeadlinesLineUp");
				var lineUp = cookieVal != null ? cookieVal : window.sn_HeadlinesLineUp;
				lineUp = lineUp.split(",");
				return lineUp;
			},
			updateDisplay: function ()
			{
				//if the my headlines module is on the page, reload - otherwise, just update the link
				var moduleIsPresent = $("div.my-teams-headlines").length > 0;
				_self.debug("moduleIsPresent: " + moduleIsPresent);
				if (moduleIsPresent) {
					_self.reloadPage();
				}
				else {
					_self.updateLink();
				}
			},
			removeTeam: function () 
			{
				_self.debug("removeTeam---");
				_self.debug("b4: " + $.cookie("sn_myHeadlinesLineUp"));
				_myLineUp = $.grep(_myLineUp, function(value){
					return value != _opts.lineupId;
				});
				$.cookies.set("sn_myHeadlinesLineUp", _myLineUp, _cookieOptions);
				_self.debug("aft: " + $.cookie("sn_myHeadlinesLineUp"));
				
				_self.updateDisplay();
			},
			addTeam: function () 
			{
				_self.debug("addTeam---");
				_self.debug("b4: " + $.cookie("sn_myHeadlinesLineUp"));
				_myLineUp.push(_opts.lineupId);
				
				$.cookies.set("sn_myHeadlinesLineUp", _myLineUp, _cookieOptions);
				
				_self.debug("aft: " + $.cookie("sn_myHeadlinesLineUp"));
				
				_self.updateDisplay();
			},
			updateLink: function () 
			{
				_root.unbind(); //remove any existing event handlers
				
				var teamIsInLineup = $.inArray(_opts.lineupId, _myLineUp) != -1;
				if (teamIsInLineup) {
					_label.html(_removeLabel);
					_root.attr('title', _removeHelp);
					_root.click(function(){
						_self.removeTeam();
						return false;
					});
				}
				else {
					var hasSpace = _myLineUp.length < 6;
					if (hasSpace) {
						_label.html(_addLabel);
						_root.attr('title', _addHelp);
						_root.click(function(){
							_self.addTeam();
							return false;
						});
					}
					else {
						_label.html(_editLabel);
						_root.attr('title', _editHelp);
						_root.attr('href', _myHeadlinesURL);
					}
				}
			},
			debug: function(str)
			{
				if (_opts.debug == true) {
					try {
						trace(str);
					} 
					catch (e) {
						alert(str);
					}
				}
			}
		});

		// Private methods ----------------------------------------------------------------
		function initLayout()
		{
			_myLineUp = _self.getMyLineUp();
			_self.updateLink();
			_root.show();
			
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
		

	};

	// jQuery plugin implementation
	$.fn.followTeamLink = function(opts)
	{ 
		this.each(function() 
		{
			new FollowTeamLink($(this), opts);
		});
	};
})(jQuery);
(function($)
{	
	// constructor
	function NewsArchiveFilter(root, conf)
	{	

		// Private fields -------------------------------------------------------------------

		var _page = $('body'),
			_root = $(root),
			_feedOptions = _root.find('a'),
			_contentHolder = _page.find('.content-listing'),
			$tmp = $(_root.find('.news-archive-sports a')).attr("id"),
			$t = $tmp.split("|"),
			_leagueName = $t[1],
			_curStories = new Array(),
			_filteredStories = new Array(),
			_self = this,
			_opts = {
				debug: false
			}; 
			 
		$.extend(_opts, conf);
		
		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			
			getFeed: function(type, feed)
			{
				var $feed = feed + "/xml/index.xml",
					$sport = _self.getSport(_leagueName);

				if (type == "team")
				{
					$feed = "news_"+feed + "/xml/index.xml";
				};
				if ($sport == "football") {
					var $path = $sport + "/" + _leagueName + "/"; 
				}
				else {
					var $path = $sport + "/";
				};	
				$.ajax({
					type: "GET",
					url: $path + $feed,
					dataType: "xml",
					success: function(xml){
						_self.killStories();
						_self.buildStories(xml);
					},
					error: function(){
						_self.doXMLError();
					}
				});
			},

			getSport: function(league) 
			{
					var sport = null;
					
					switch(league){
						case "nhl":
							sport = "hockey";
							break;
						case "mlb":
							sport = "baseball";
							break;
						case "nfl": 
							sport = "football";
							break;
						case "cfl":
							sport = "football";
							break;
						default:
							sport = "basketball";		
							break;
					}
					return sport;
			},
			
			buildStories: function(xml)
			{
				var $xmlObj = $(xml),
					_storyArray = $xmlObj.find('item'),
					_sectionDate = null;

				for(var i=0; i < _storyArray.length; i++)
				{
					var curStory = _storyArray[i],
						curDate = $($(curStory).find('citation')).attr('date'),
						curURL = $(curStory).attr('url'),
						curComment = $(curStory).attr('comments'),
						curCommentURL = $(curStory).attr('commentsURL'),
						curVideo = $(curStory).attr('hasVideo'),
						curHeadline = $($(curStory).find('headline')).text(),
						curSummary = $($(curStory).find('summary')).text()
						id = i;

					if(curDate == _sectionDate)
					{
						_self.createArticle(curURL, curComment, curCommentURL, curVideo, curHeadline, curSummary, id);
					} else {
						_sectionDate = curDate;
						_self.createDateSection(_sectionDate);
						_self.createArticle(curURL, curComment, curCommentURL, curVideo, curHeadline, curSummary, id);
					};
				}
				_contentHolder.children('li:last').addClass('last');
				_self.showStories();	
			},
			
			createDateSection: function(date)
			{
				var $tmp = date.split(" "),
					$month = $tmp[0],
					d = $tmp[1],
					dt = d.split(","),
					$day = dt[0],
					$year = $tmp[2],
					$section = "<li class='date-section'><div class='press-date'><span class='month'>"+$month+"</span><span class='day'>"+$day+"</span><span class='year'>"+$year+"</span></div><div class='press-items'><ul class='press-link-list'></ul></div></li>";
				
				_contentHolder.append($section); 
			},
			
			createArticle: function(url, comments, commentsURL, hasVideo, headline, summary, id)
			{
				var $section = _contentHolder.find('li.date-section:last');
					$articleWrapper = $section.find('ul.press-link-list'),
					$url = url,
					$comments = comments,
					$commentsURL = commentsURL,
					$hasVideo = hasVideo,
					$head = headline,
					$sum = summary,
					$id = id,
					$content = "<li id='"+$id+"'><a href='"+$url+"'>"+$head+"</a><span class='comment-balloon'><a href='"+$commentsURL+"'>"+$comments+"</a></span><span class='comment-video'><a href='"+$url+"'><img src='/assets/img/comment_video.gif'></a></span><p class='list-desc ellipsis multiline'>"+$sum+"</p></li>";
					
				$articleWrapper.append($content);
				if($comments <= 0 || $comments == undefined){
					$("li#"+$id+" span.comment-balloon").hide();
				}	
				if($hasVideo == "false" || $hasVideo == undefined){
					$("li#"+$id+" span.comment-video").hide();
				}
			},
			
			killStories: function()
			{
				_contentHolder.empty();
			},
			
			hideStories: function()
			{
				_contentHolder.hide();
				_contentHolder.parent().find('.error-content').hide();
				_contentHolder.parent().find('.updating-content').show();
			},
			
			showStories: function()
			{
				_contentHolder.parent().find('.updating-content').hide();
				_contentHolder.fadeIn();
			},
			
			doXMLError: function()
			{
				_contentHolder.parent().find('.updating-content').hide();
				_contentHolder.parent().find('.error-content').show();
			},
			
			debug: function(str)
			{
				if (_opts.debug == true) {
					try {
						trace(str);
					} 
					catch (e) {
						alert(str);
					}
				}
			}
		});

		// Private methods ----------------------------------------------------------------
		function initLayout()
		{	
			_contentHolder.parent().prepend('<div class="updating-content">Updating Content</div>');		
			_contentHolder.parent().prepend('<div class="error-content">The news feed you have chosen is currently unavailable.  Please select a different feed, or try again later.</div>');		
			_contentHolder.parent().find('.updating-content').hide();
			_contentHolder.parent().find('.error-content').hide();
			_self.hideStories();
			_self.getFeed("league", _leagueName);
			
			_feedOptions.click(function() 
			{
				var $this = $(this),
					$id = $this.attr('id'),
					tmp = $id.split('|'),
					$league = tmp[0],
					$feed = tmp[1];

				setTimeout(function(){
					_page.find('.default').text($this.text());	
					_self.hideStories();
					_self.getFeed($league, $feed);}, 750);
													
				return false;
			})
		};

		// Initialization ------------------------------------------------------------------
		
		initLayout();
	};

	// jQuery plugin implementation
	$.fn.newsArchiveFilter = function(conf)
	{ 
		var opts = {};
		$.extend(opts, conf);
		
		this.each(function() 
		{
			var $instance = new NewsArchiveFilter($(this), opts);
		});
		return this; 
	};
})(jQuery);
(function($)
{	
	// constructor
	function DataLayoutManager(root)
	{	
		// Private fields ------------------------------------------------------------------
		var _root = $(root),
			_domElement = _root[0],
			_containerDiv,
			_contentDiv,
			_bodyDiv,
			_rightColDiv,
			_self = this,
			_opts = {
				debug: false
			}
			;
	
		// Public methods ------------------------------------------------------------------
		$.extend(_self, {
			contentIsTooWide: function()
			{
				var myWidth = _root.width();
				var tableWidth = _root.find("table.stats").width();
				debug("myWidth: " + myWidth);
				debug("tableWidth: " + tableWidth);
				
				var isTooWide = tableWidth > myWidth;
				debug("isTooWide: " + isTooWide);
				return isTooWide;
			},
			initRightColumn: function()
			{
				_rightColDiv = _contentDiv.find("div.column.span-5.last");
				_rightColDiv.absolutize();
			},
			placeRightColumn: function()
			{
				var targetLeft = _containerDiv.offset().left + _containerDiv.width() + 1; //1 accounts for the border (not 2 since we want to overlap the right edge border)
				debug(" targetLeft: " + targetLeft);
				_rightColDiv.css({
					'left': targetLeft+"px",
					'border-top': "1px solid #999999",
					'border-right': "1px solid #999999",
					'border-bottom': "1px solid #999999",
					'background-color': "#FFFFFF",
					'padding-top': "15px"
				});
			},
			expandBody: function()
			{
				_bodyDiv = _contentDiv.find("div.column.span-10:first");
				//make the main div span all columns
				_bodyDiv.removeClass("span-10");
				_bodyDiv.addClass("span-15 last");
				//make all the children span all columns
				_bodyDiv.find("div.column.span-10").each(function(){
					_this = $(this);
					_this.removeClass("span-10");
					_this.addClass("span-15");
				});
			}
		});
	
		// Private methods -----------------------------------------------------------------
		function debug(str)
		{
			if (_opts.debug == true) {
				try {
					trace(str);
				} 
				catch (e) {
					alert(str);
				}
			}
		};
			
		// generic binding function
		function bind(name, fn)
		{
			if ($.isFunction(fn) == false)
				return;
				
			$(_self).bind(name, fn);
		};
	
		function init()
		{	
			if (_self.contentIsTooWide()) {
				_containerDiv = $("body > div.container:first");
				_contentDiv = $("div.container > #content");
				
				_self.initRightColumn();
				_self.placeRightColumn();
				_self.expandBody();
					
				$(window).resize(function(){
					_self.placeRightColumn();
				});
			}
		};
	
		// Initialization ------------------------------------------------------------------
		init();
	};
	
	// jQuery plugin implementation
	$.fn.dataLayoutManager = function()
	{
		this.each(function()
		{
			var $instance = new DataLayoutManager($(this));
		});
		
		return this;
	};
	
    jQuery.fn.absolutize = function(rebase){
		return this.each(function() {
			var el = $(this);
			var pos = el.position();
			el.css({ position: "absolute",
			marginLeft: 0, marginTop: 0,
			top: pos.top, left: pos.left });
			if (rebase)
				el.remove().appendTo("body");
		});
    };
	
})(jQuery);
//strings
function stripTags(string){
	return string.replace(/<\/?[^>]+>/gi, '');
}

//twitter module
function retweetThis() {
	var tweetElem = $("ul.twitter");
	var twitterUrl = tweetElem.find("li.feeds p.name a").attr("href");
	var src = "@" + (twitterUrl.substr(twitterUrl.indexOf("twitter.com/") + 12).split("/")[0]) + " ";
	//var src = "@" + stripTags(tweetElem.find("span#twitterSource").html()) + " ";
	var tweet = stripTags(tweetElem.find("p#twitterTweet").html());
	var tURL = "http://twitter.com/home?status=" + encodeURIComponent(src + tweet);
	var w = window.open(tURL, "twitterWindow");
	return false;
}
/** Drag and Drop **/
var DEFAULT_RANKING_FIELD = '<span class="instructions">Drag and Drop</span>';
$(document).ready(function(){
	$(".rank .block").each( function (i) {
		$(this).html($(this).html().toString().replace(/<a /gi, '<a target="_blank" '));
	});
	$(".rank .block").draggable({
		cursorAt: { top: '1', left:  '2' }, 
		cursor: 'none', 
		helper: function() { return $(this).find(".meta").clone().removeClass("meta").addClass("label").css("font-weight", "bold").css("font-size", "12px").css("padding", "5px").css("width", $(this).css("width")).css("z-index", "10000").css("white-space", "nowrap"); }
	}); 
	$(".rank .drop").draggable({
		cursorAt: { top: '1', left:  '2' }, 
		cursor: 'none', 
		helper: function() { return $(this).find(".label").clone().css("font-weight", "bold").css("font-size", "12px").css("padding", "5px").css("width", $(this).css("width")).css("z-index", "10000").css("white-space", "nowrap"); }
	}); 
	$(".drop").droppable({
		accept: function(draggable) { return (($(draggable).is('.block')) && ($(this).closest(".rank").attr("id") == $(draggable).closest(".rank").attr("id"))) || (($(draggable).is('.drop')) && ($(this).closest(".rank").attr("id") == $(draggable).closest(".rank").attr("id"))); }, 
		activeClass: 'dropactive',
		hoverClass: 'drophover',
		drop: function(ev, ui) {
			if ($(ui.draggable).find(".meta").length > 0) {
				/* drag from .rank .block (insert into) */
				$(this).closest(".rank-answers").each(
						function (i) { 
								$(this).find(".drop").each( function (i) {
										if ($(this).find(".label").length > 0 && $(this).find(".label").attr("id") == $(ui.draggable).find(".meta").attr("id")) {
											$(this).html(DEFAULT_RANKING_FIELD);
										}
								});
						});
				
				$(this).empty();
				$(this).append($(ui.draggable).find(".meta").clone().removeClass("meta").addClass("label").css("cursor", "pointer"));
			} else {
				/* drag from .rank .drop (move up and down) */
				var mouse_item = $(ui.draggable).find(".label").clone();
				var current_item = $(this).find(".label").clone();
				$(this).closest(".rank-answers").each(
						function (i) { 
								$(this).find(".drop").each( function (i) {
										if ($(this).find(".label").length > 0 && $(this).find(".label").attr("id") == $(mouse_item).attr("id")) {
											if ($(current_item).length == 0) {
												$(this).html(DEFAULT_RANKING_FIELD);
											} else {
												$(this).empty();
												$(this).append(current_item);
											}
										}
								});
						});
				
				$(this).empty();
				$(this).append(mouse_item);
			}
		}
	});
	$(".rank .block").dblclick(function () {
		var url = $(this).find(".img").attr("value");
		var nameTag = $(this).find(".meta").html();
		
		if (url) {
			var imgTag = "<img src='" + url + "' alt='" + name + "' />";
			$("#screener").remove();
			$("<div id='screener' onclick='$(this).html(\"\"); $(this).remove();'><div class='sidead leftad'></div><div class='screenshot'>" + imgTag + "<div class='screenname'>" + nameTag + "</div></div><div class='sidead rightad'></div><div class='screenbg'/></div>").appendTo("body");
			$("#screener .screenbg").css("z-index", "99").css("opacity", "0.75").css("background-color", "#000000");
			$("#screener").css("overflow", "auto");
			$("#screener .screenshot").css("z-index", "100").css("position", "relative").css("overflow", "hidden").css("display", "inline");
			$("#screener .sidead").css("z-index", "100").css("position", "relative").css("overflow", "hidden").css("display", "inline");
			
			var imgPreloader = new Image();
			imgPreloader.onload = function() {
				var margin = 4;
				var nameheight = 20;
				var w = window.innerWidth || self.innerWidth || (document.documentElement && document.documentElement.clientWidth) || document.body.clientWidth;
				var h = window.innerHeight || self.innerHeight || (document.documentElement && document.documentElement.clientHeight) || document.body.clientHeight;
				var imageWidth = (imgPreloader.width < w?(w - imgPreloader.width) / 2:0);
				var imageHeight = (imgPreloader.height < h?(h - imgPreloader.height) / 2:0);
				var bestwidthpx = Math.max(w, imgPreloader.width + margin * 2);
				var bestheightpx = Math.max(h, imgPreloader.height + margin * 2 + nameheight + margin * 2);
				var adwidthpx = '160';
				var adheightpx = '600';
				
				fixPositionFixed(fixWidthHeight($("#screener"), bestwidthpx, bestheightpx), true);
				fixPositionFixed(fixWidthHeight($("#screener .screenbg"), bestwidthpx , bestheightpx), false);
				$("#screener .screenshot").css("margin", imageHeight + "px" + " 0px 0px " + imageWidth + "px").css("display", "block");
				$("#screener .screenname").css("height", nameheight + "px").css("background-color", "#FFFFFF").css("padding", margin + "px").css("font-weight", "bold").css("width", imgPreloader.width + "px").css("text-align", "center");
				$("#screener .screenshot img").css("border", margin + "px solid #FFFFFF");
				
				fixPositionFixed($("#screener .sidead").css("width", adwidthpx + "px").css("height", adheightpx + "px").css("float", "left"), false);
				$("#screener .leftad").css("top", imageHeight + "px").css("left", (imageWidth - adwidthpx - margin) + "px").css("text-align", "right");
				$("#screener .rightad").css("top", imageHeight + "px").css("left", (imageWidth + (imgPreloader.width + margin * 2) + margin) + "px").css("text-align", "left");
				
				function fixWidthHeight(obj, w, h) {
					if ($.browser.msie && parseInt(jQuery.browser.version) < 7) {
						return $(obj).css("width", w + "px").css("height", h + "px");
					} else {
						return $(obj).css("width", "100%").css("height", "100%");
					}
				}
				function fixPositionFixed(obj, addClass) {
					if ($.browser.msie && parseInt(jQuery.browser.version) < 7) {
						if (addClass) {
							return $(obj).css("position", "absolute").addClass("positionfixed");
						} else {
							return $(obj).css("position", "absolute").css("top", "0");
						}
					} else {
						return $(obj).css("position", "fixed").css("top", "0");
					}
				}
				
				imgPreloader.onload=function(){};	//	clear onLoad, as IE will flip out w/animated gifs
				return false;
			};
			
			imgPreloader.src = url;
			
			var adcreative = $(this).closest(".rank").find(".adcreative");
			if ($(adcreative)) {
				$("#screener .sidead").html($(adcreative).html());
			}
        }
	});
	$(".rank_vote_button").click(function() { $(this).parent().children('.drop').html(DEFAULT_RANKING_FIELD); });
});


/** Rank AJAX **/
(function($) {
	// constructor
	function Rank(root, conf) {	
		// Private fields ------------------------------------------------------------------
		var RANK_ACTIVATED = "rank_activated";
		var _root = $(root),
			_domElement = _root[0],
			_self = this,
			_userHasVoted,
			_resultContainer = _root.find('.rank-result-container'),
			_answerElem = _root.find('.rank-answers'),
			_opts = {
				debug: false
			}
			;
			$.extend(_opts, conf);
		
		// Private methods -----------------------------------------------------------------
		function debug(str)
		{
			if (_opts.debug == true) {
				try {
					console.log(str);
				} 
				catch (e) {
					alert("debug: " + str);
				}
			}
		};
		
		// generic binding function
		
		function bind(name, fn)
		{
			if ($.isFunction(fn) == false)
				return;
			$(_self).bind(name, fn);
		};
		
		function showRankAnswers()
		{
			_resultContainer.hide();
			_answerElem.show();
		};
		
		function showRankResults(submitAnswer){
			backendsumbit(new Array());
			
			return false;
		};
		
		function enableButton(){
			$(".rankVoteButton", _root).removeClass("buttonInactive");
			$(".rankVoteButton", _root).click(function(){
					var must_filled_bit = (1<<0 | 1<<1 | 1<<2);
					var check_filled_bit = 0x0;
					var response_data = new Array();
					var data_string = new Array();
					$(this).closest(".rank-answers").each(
							function (i) { 
									$(this).find(".drop").each( function (i) {
											response_data[i] = (isNaN($(this).children(".label").attr("id"))?0:$(this).children(".label").attr("id"));
											if (response_data[i] > 0) {
												check_filled_bit |= 1<<i;
											}
									});
							});
							
					if ((check_filled_bit & must_filled_bit) == must_filled_bit) {
						data_string.push("response_id=" + response_data.join(","));
						backendsumbit(data_string);
					} else {
						// update poll-results
						_resultContainer.html("Please fill in the Top 3");
						_resultContainer.fadeIn();
					}
					
					return false;
			});
			
			$(".rankClearButton", _root).click(function() { 
					$(this).closest(".rank-answers").each(
							function (i) { 
									$(this).find(".drop").each( function (i) {
											$(this).html(DEFAULT_RANKING_FIELD);
									});
							});
					return false;
			});
		};
		
		function backendsumbit(data_string) {
            $.ajax({
				url: "/scrum/rank_vote.php",
				type: "POST",
				cache: false,
				data: "rank_id=" + _opts.rank_id + "&" + data_string.join("&") + "&rand=" + Math.floor(Math.random()*10000000),
                success: function(html) {
					// update poll-results
					_resultContainer.html(html);
					_resultContainer.fadeIn();
					_userHasVoted = getVoteStatus();
					debug("aft _userHasVoted: " + _userHasVoted);
					if (_userHasVoted == false) showAnswersLink();
                }
            });
		}
		
		function getVoteStatus(){
			var ranks = $.cookie('ranks');
			if (ranks) {
				$(ranks.split('|')).each(function(i) {
					if ($(this) == _opts.rank_id) {
						return true;
					}
				});
			}
			return false;
		};
		
		function init()
		{
			if (!$(_root).hasClass(RANK_ACTIVATED) && ('rank_' + _opts.rank_id) == $(_root).attr("id")) {
				$(_root).addClass(RANK_ACTIVATED);
				// see if user has already voted
				_userHasVoted = getVoteStatus();
				
				debug("_userHasVoted: " + _userHasVoted);
				
				if (_userHasVoted == true) {
					showRankResults();
				} else {
					enableButton();
					showRankAnswers();
				}
			}
		};
		
		// Initialization ------------------------------------------------------------------
		init();
	};
	
	// jQuery plugin implementation
	$.fn.rank = function(conf)
	{
		var opts = { };
		$.extend(opts, conf);
		
		this.each(function()
		{
			var $instance = new Rank($(this), opts);
		});
		
		return this;
	};
})(jQuery);

/**
 * @preserve Galleria v 1.2.2 2011-02-25
 * http://galleria.aino.se
 *
 * Copyright (c) 2011, Aino
 * Licensed under the MIT license.
 */

/*global jQuery, navigator, Galleria, Image */

(function( $ ) {

// some references
var undef,
    window = this,
    doc    = window.document,
    $doc   = $( doc ),

// internal constants
    DEBUG = false,
    NAV   = navigator.userAgent.toLowerCase(),
    HASH  = window.location.hash.replace(/#\//, ''),
    CLICK = function() {
        // use this to make touch devices snappier
        return Galleria.TOUCH ? 'touchstart' : 'click';
    },
    IE    = (function() {

        var v = 3,
            div = doc.createElement( 'div' ),
            all = div.getElementsByTagName( 'i' );

        do {
            div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->';
        } while ( all[0] );

        return v > 4 ? v : undef;

    }() ),
    DOM   = function() {
        return {
            html:  doc.documentElement,
            body:  doc.body,
            head:  doc.getElementsByTagName('head')[0],
            title: doc.title
        };
    },

    // list of Galleria events
    _eventlist = 'data ready thumbnail loadstart loadfinish image play pause progress ' + 
              'fullscreen_enter fullscreen_exit idle_enter idle_exit rescale ' +
              'lightbox_open lightbox_close lightbox_image',

    _events = (function() {

        var evs = [];

        $.each( _eventlist.split(' '), function( i, ev ) {
            evs.push( ev );

            // legacy events
            if ( /_/.test( ev ) ) {
                evs.push( ev.replace( /_/g, '' ) );
            }
        });

        return evs;

    }()),

    // legacy options
    // allows the old my_setting syntax and converts it to camel case

    _legacyOptions = function( options ) {

        var n;

        if ( typeof options !== 'object' ) {

            // return whatever it was...
            return options;
        }

        $.each( options, function( key, value ) {
            if ( /^[a-z]+_/.test( key ) ) {
                n = '';
                $.each( key.split('_'), function( i, k ) {
                    n += i > 0 ? k.substr( 0, 1 ).toUpperCase() + k.substr( 1 ) : k;
                });
                options[ n ] = value;
                delete options[ key ];
            }
        });

        return options;
    },

    _patchEvent = function( type ) {

        // allow 'image' instead of Galleria.IMAGE
        if ( $.inArray( type, _events ) > -1 ) {
            return Galleria[ type.toUpperCase() ];
        }

        return type;
    },

    // the internal timeouts object
    // provides helper methods for controlling timeouts
    _timeouts = {

        trunk: {},

        add: function( id, fn, delay, loop ) {
            loop = loop || false;
            this.clear( id );
            if ( loop ) {
                var old = fn;
                fn = function() {
                    old();
                    _timeouts.add( id, fn, delay );
                };
            }
            this.trunk[ id ] = window.setTimeout( fn, delay );
        },

        clear: function( id ) {

            var del = function( i ) {
                window.clearTimeout( this.trunk[ i ] );
                delete this.trunk[ i ];
            }, i;

            if ( !!id && id in this.trunk ) {
                del.call( _timeouts, id );

            } else if ( typeof id === 'undefined' ) {
                for ( i in this.trunk ) {
                    if ( this.trunk.hasOwnProperty( i ) ) {
                        del.call( _timeouts, i );
                    }
                }
            }
        }
    },

    // the internal gallery holder
    _galleries = [],

    // the Utils singleton
    Utils = (function() {

        return {

            array : function( obj ) {
                return Array.prototype.slice.call(obj);
            },

            create : function( className, nodeName ) {
                nodeName = nodeName || 'div';
                var elem = doc.createElement( nodeName );
                elem.className = className;
                return elem;
            },

            forceStyles : function( elem, styles ) {
                elem = $(elem);
                if ( elem.attr( 'style' ) ) {
                    elem.data( 'styles', elem.attr( 'style' ) ).removeAttr( 'style' );
                }
                elem.css( styles );
            },

            revertStyles : function() {
                $.each( Utils.array( arguments ), function( i, elem ) {

                    elem = $( elem ).removeAttr( 'style' );

                    if ( elem.data( 'styles' ) ) {
                        elem.attr( 'style', elem.data('styles') ).data( 'styles', null );
                    }
                });
            },

            moveOut : function( elem ) {
                Utils.forceStyles( elem, {
                    position: 'absolute',
                    left: -10000
                });
            },

            moveIn : function() {
                Utils.revertStyles.apply( Utils, Utils.array( arguments ) );
            },

            hide : function( elem, speed, callback ) {
                elem = $(elem);

                // save the value if not exist
                if (! elem.data('opacity') ) {
                    elem.data('opacity', elem.css('opacity') );
                }

                // always hide
                var style = { opacity: 0 };

                if (speed) {
                    elem.stop().animate( style, speed, callback );
                } else {
                    elem.css( style );
                }
            },

            show : function( elem, speed, callback ) {
                elem = $(elem);

                // bring back saved opacity
                var saved = parseFloat( elem.data('opacity') ) || 1,
                    style = { opacity: saved };

                // reset save if opacity === 1
                if (saved === 1) {
                    elem.data('opacity', null);
                }

                // animate or toggle
                if (speed) {
                    elem.stop().animate( style, speed, callback );
                } else {
                    elem.css( style );
                }
            },

            addTimer : function() {
                _timeouts.add.apply( _timeouts, Utils.array( arguments ) );
                return this;
            },

            clearTimer : function() {
                _timeouts.clear.apply( _timeouts, Utils.array( arguments ) );
                return this;
            },

            wait : function(options) {
                options = $.extend({
                    until : function() { return false; },
                    success : function() {},
                    error : function() { Galleria.raise('Could not complete wait function.'); },
                    timeout: 3000
                }, options);

                var start = Utils.timestamp(),
                    elapsed,
                    now,
                    fn = function() {
                        now = Utils.timestamp();
                        elapsed = now - start;
                        if ( options.until( elapsed ) ) {
                            options.success();
                            return false;
                        }

                        if (now >= start + options.timeout) {
                            options.error();
                            return false;
                        }
                        window.setTimeout(fn, 2);
                    };

                window.setTimeout(fn, 2);
            },

            toggleQuality : function( img, force ) {

                if ( ( IE !== 7 && IE !== 8 ) || !img ) {
                    return;
                }

                if ( typeof force === 'undefined' ) {
                    force = img.style.msInterpolationMode === 'nearest-neighbor';
                }

                img.style.msInterpolationMode = force ? 'bicubic' : 'nearest-neighbor';
            },

            insertStyleTag : function( styles ) {
                var style = doc.createElement( 'style' );
                DOM().head.appendChild( style );

                if ( style.styleSheet ) { // IE
                    style.styleSheet.cssText = styles;
                } else {
                    var cssText = doc.createTextNode( styles );
                    style.appendChild( cssText );
                }
            },

            // a loadscript method that works for local scripts
            loadScript: function( url, callback ) {
                var done = false,
                    script = $('<scr'+'ipt>').attr({
                        src: url,
                        async: true
                    }).get(0);

               // Attach handlers for all browsers
               script.onload = script.onreadystatechange = function() {
                   if ( !done && (!this.readyState ||
                       this.readyState === 'loaded' || this.readyState === 'complete') ) {

                       done = true;

                       // Handle memory leak in IE
                       script.onload = script.onreadystatechange = null;

                       if (typeof callback === 'function') {
                           callback.call( this, this );
                       }
                   }
               };

               DOM().head.appendChild( script );
            },

            // parse anything into a number
            parseValue: function( val ) {
                if (typeof val === 'number') {
                    return val;
                } else if (typeof val === 'string') {
                    var arr = val.match(/\-?\d/g);
                    return arr && arr.constructor === Array ? parseInt( arr.join(''), 10 ) : 0;
                } else {
                    return 0;
                }
            },

            // timestamp abstraction
            timestamp: function() {
                return new Date().getTime();
            },

            // this is pretty crap, but works for now
            // it will add a callback, but it can't guarantee that the styles can be fetched
            // using getComputedStyle further checking needed, possibly a dummy element
            loadCSS : function( href, id, callback ) {

                var link,
                    ready = false,
                    length;

                // look for manual css
                $('link[rel=stylesheet]').each(function() {
                    if ( new RegExp( href ).test( this.href ) ) {
                        link = this;
                        return false;
                    }
                });

                if ( typeof id === 'function' ) {
                    callback = id;
                    id = undef;
                }

                callback = callback || function() {}; // dirty

                // if already present, return
                if ( link ) {
                    callback.call( link, link );
                    return link;
                }

                // save the length of stylesheets to check against
                length = doc.styleSheets.length;

                // add timestamp if DEBUG is true
                if ( DEBUG ) {
                    href += '?' + Utils.timestamp();
                }

                // check for existing id
                if( $('#'+id).length ) {
                    $('#'+id).attr('href', href);
                    length--;
                    ready = true;
                } else {
                    link = $( '<link>' ).attr({
                        rel: 'stylesheet',
                        href: href,
                        id: id
                    }).get(0);

                    window.setTimeout(function() {
                        var styles = $('link[rel="stylesheet"], style');
                        if ( styles.length ) {
                            styles.get(0).parentNode.insertBefore( link, styles[0] );
                        } else {
                            DOM().head.appendChild( link );
                        }

                        if ( IE ) {
                            link.attachEvent( 'onreadystatechange', function(e) {
                                if( link.readyState === 'complete' ) {
                                    ready = true;
                                }
                            });
                        } else {
                            // what to do here? returning for now.
                            ready = true;
                        }
                    }, 10);
                }

                if ( typeof callback === 'function' ) {

                    Utils.wait({
                        until: function() {
                            return ready && doc.styleSheets.length > length;
                        },
                        success: function() {
                            Utils.addTimer( 'css', function() {
                                callback.call( link, link );
                            }, 100);
                        },
                        error: function() {
                            Galleria.raise( 'Theme CSS could not load' );
                        },
                        timeout: 1000
                    });
                }
                return link;
            }
        };
    }()),

    // the transitions holder
    _transitions = {

        fade: function(params, complete) {
            $(params.next).css('opacity', 0).show().animate({
                opacity: 1
            }, params.speed, complete);

            if (params.prev) {
                $(params.prev).css('opacity', 1).show().animate({
                    opacity: 0
                }, params.speed);
            }
        },

        flash: function(params, complete) {
            $(params.next).css('opacity', 0);
            if (params.prev) {
                $(params.prev).animate({
                    opacity: 0
                }, (params.speed / 2), function() {
                    $(params.next).animate({
                        opacity: 1
                    }, params.speed, complete);
                });
            } else {
                $(params.next).animate({
                    opacity: 1
                }, params.speed, complete);
            }
        },

        pulse: function(params, complete) {
            if (params.prev) {
                $(params.prev).hide();
            }
            $(params.next).css('opacity', 0).animate({
                opacity:1
            }, params.speed, complete);
        },

        slide: function(params, complete) {
            var image  = $(params.next).parent(),
                images = this.$('images'), // ??
                width  = this._stageWidth,
                easing = this.getOptions( 'easing' );

            image.css({
                left: width * ( params.rewind ? -1 : 1 )
            });
            images.animate({
                left: width * ( params.rewind ? 1 : -1 )
            }, {
                duration: params.speed,
                queue: false,
                easing: easing,
                complete: function() {
                    images.css('left', 0);
                    image.css('left', 0);
                    complete();
                }
            });
        },

        fadeslide: function(params, complete) {

            var x = 0,
                easing = this.getOptions('easing'),
                distance = this.getStageWidth();

            if (params.prev) {
                x = Utils.parseValue( $(params.prev).css('left') );
                $(params.prev).css({
                    opacity: 1,
                    left: x
                }).animate({
                    opacity: 0,
                    left: x + ( distance * ( params.rewind ? 1 : -1 ) )
                },{
                    duration: params.speed,
                    queue: false,
                    easing: easing
                });
            }

            x = Utils.parseValue( $(params.next).css('left') );

            $(params.next).css({
                left: x + ( distance * ( params.rewind ? -1 : 1 ) ),
                opacity: 0
            }).animate({
                opacity: 1,
                left: x
            }, {
                duration: params.speed,
                complete: complete,
                queue: false,
                easing: easing
            });
        }
    };

/**
    The main Galleria class

    @class
    @constructor

    @example var gallery = new Galleria();

    @author http://aino.se

    @requires jQuery

*/

var Galleria = function() {

    var self = this;

    // the theme used
    this._theme = undef;

    // internal options
    this._options = {};

    // flag for controlling play/pause
    this._playing = false;

    // internal interval for slideshow
    this._playtime = 5000;

    // internal variable for the currently active image
    this._active = null;

    // the internal queue, arrayified
    this._queue = { length: 0 };

    // the internal data array
    this._data = [];

    // the internal dom collection
    this._dom = {};

    // the internal thumbnails array
    this._thumbnails = [];

    // internal init flag
    this._initialized = false;

    // global stagewidth/height
    this._stageWidth = 0;
    this._stageHeight = 0;

    // target holder
    this._target = undef;

    // instance id
    this._id = Math.random();

    // add some elements
    var divs =  'container stage images image-nav image-nav-left image-nav-right ' +
                'info info-text info-title info-description info-author ' +
                'thumbnails thumbnails-list thumbnails-container thumb-nav-left thumb-nav-right ' +
                'loader counter tooltip',
        spans = 'current total';

    $.each( divs.split(' '), function( i, elemId ) {
        self._dom[ elemId ] = Utils.create( 'galleria-' + elemId );
    });

    $.each( spans.split(' '), function( i, elemId ) {
        self._dom[ elemId ] = Utils.create( 'galleria-' + elemId, 'span' );
    });

    // the internal keyboard object
    // keeps reference of the keybinds and provides helper methods for binding keys
    var keyboard = this._keyboard = {

        keys : {
            'UP': 38,
            'DOWN': 40,
            'LEFT': 37,
            'RIGHT': 39,
            'RETURN': 13,
            'ESCAPE': 27,
            'BACKSPACE': 8,
            'SPACE': 32
        },

        map : {},

        bound: false,

        press: function(e) {
            var key = e.keyCode || e.which;
            if ( key in keyboard.map && typeof keyboard.map[key] === 'function' ) {
                keyboard.map[key].call(self, e);
            }
        },

        attach: function(map) {

            var key, up;

            for( key in map ) {
                if ( map.hasOwnProperty( key ) ) {
                    up = key.toUpperCase();
                    if ( up in keyboard.keys ) {
                        keyboard.map[ keyboard.keys[up] ] = map[key];
                    }
                }
            }
            if ( !keyboard.bound ) {
                keyboard.bound = true;
                $doc.bind('keydown', keyboard.press);
            }
        },

        detach: function() {
            keyboard.bound = false;
            $doc.unbind('keydown', keyboard.press);
        }
    };

    // internal controls for keeping track of active / inactive images
    var controls = this._controls = {

        0: undef,

        1: undef,

        active : 0,

        swap : function() {
            controls.active = controls.active ? 0 : 1;
        },

        getActive : function() {
            return controls[ controls.active ];
        },

        getNext : function() {
            return controls[ 1 - controls.active ];
        }
    };

    // internal carousel object
    var carousel = this._carousel = {

        // shortcuts
        next: self.$('thumb-nav-right'),
        prev: self.$('thumb-nav-left'),

        // cache the width
        width: 0,

        // track the current position
        current: 0,

        // cache max value
        max: 0,

        // save all hooks for each width in an array
        hooks: [],

        // update the carousel
        // you can run this method anytime, f.ex on window.resize
        update: function() {
            var w = 316,
                h = 315,
                hooks = [0];

            $.each( self._thumbnails, function( i, thumb ) {
                if ( thumb.ready ) {
                    //w += thumb.outerWidth || $( thumb.container ).outerWidth( true );
                    hooks[ i+1 ] = w;
                    //h = Math.max( h, thumb.outerHeight || $( thumb.container).outerHeight( true ) );
                }
            });

            self.$( 'thumbnails' ).css({
                width: w,
                height: h
            });

            carousel.max = w;
            carousel.hooks = hooks;
            carousel.width = self.$( 'thumbnails-list' ).width();
            carousel.setClasses();

            self.$( 'thumbnails-container' ).toggleClass( 'galleria-carousel', w > carousel.width );

            // todo: fix so the carousel moves to the left
        },

        bindControls: function() {

            var i;

            carousel.next.bind( CLICK(), function(e) {
                e.preventDefault();

                if ( self._options.carouselSteps === 'auto' ) {

                    for ( i = carousel.current; i < carousel.hooks.length; i++ ) {
                        if ( carousel.hooks[i] - carousel.hooks[ carousel.current ] > carousel.width ) {
                            carousel.set(i - 2);
                            break;
                        }
                    }

                } else {
                    carousel.set( carousel.current + self._options.carouselSteps);
                }
            });

            carousel.prev.bind( CLICK(), function(e) {
                e.preventDefault();

                if ( self._options.carouselSteps === 'auto' ) {

                    for ( i = carousel.current; i >= 0; i-- ) {
                        if ( carousel.hooks[ carousel.current ] - carousel.hooks[i] > carousel.width ) {
                            carousel.set( i + 2 );
                            break;
                        } else if ( i === 0 ) {
                            carousel.set( 0 );
                            break;
                        }
                    }
                } else {
                    carousel.set( carousel.current - self._options.carouselSteps );
                }
            });
        },

        // calculate and set positions
        set: function( i ) {
            i = Math.max( i, 0 );
            while ( carousel.hooks[i - 1] + carousel.width >= carousel.max && i >= 0 ) {
                i--;
            }
            carousel.current = i;
            carousel.animate();
        },

        // get the last position
        getLast: function(i) {
            return ( i || carousel.current ) - 1;
        },

        // follow the active image
        follow: function(i) {

            //don't follow if position fits
            if ( i === 0 || i === carousel.hooks.length - 2 ) {
                carousel.set( i );
                return;
            }

            // calculate last position
            var last = carousel.current;
            while( carousel.hooks[last] - carousel.hooks[ carousel.current ] <
                   carousel.width && last <= carousel.hooks.length ) {
                last ++;
            }

            // set position
            if ( i - 1 < carousel.current ) {
                carousel.set( i - 1 );
            } else if ( i + 2 > last) {
                carousel.set( i - last + carousel.current + 2 );
            }
        },

        // helper for setting disabled classes
        setClasses: function() {
            carousel.prev.toggleClass( 'disabled', !carousel.current );
            carousel.next.toggleClass( 'disabled', carousel.hooks[ carousel.current ] + carousel.width >= carousel.max );
        },

        // the animation method
        animate: function(to) {
            carousel.setClasses();
            var num = carousel.hooks[ carousel.current ] * -1;

            if ( isNaN( num ) ) {
                return;
            }

            self.$( 'thumbnails' ).animate({
                left: num
            },{
                duration: self._options.carouselSpeed,
                easing: self._options.easing,
                queue: false
            });
        }
    };

    // tooltip control
    // added in 1.2
    var tooltip = this._tooltip = {

        initialized : false,

        open: false,

        init: function() {

            tooltip.initialized = true;

            var css = '.galleria-tooltip{padding:3px 8px;max-width:50%;background:#ffe;color:#000;z-index:3;position:absolute;font-size:11px;line-height:1.3' +
                      'opacity:0;box-shadow:0 0 2px rgba(0,0,0,.4);-moz-box-shadow:0 0 2px rgba(0,0,0,.4);-webkit-box-shadow:0 0 2px rgba(0,0,0,.4);}';

            Utils.insertStyleTag(css);

            self.$( 'tooltip' ).css('opacity', 0.8);
            Utils.hide( self.get('tooltip') );

        },

        // move handler
        move: function( e ) {
            var mouseX = self.getMousePosition(e).x,
                mouseY = self.getMousePosition(e).y,
                $elem = self.$( 'tooltip' ),
                x = mouseX,
                y = mouseY,
                height = $elem.outerHeight( true ) + 1,
                width = $elem.outerWidth( true ),
                limitY = height + 15;

            var maxX = self.$( 'container').width() - width - 2,
                maxY = self.$( 'container').height() - height - 2;

            if ( !isNaN(x) && !isNaN(y) ) {

                x += 10;
                y -= 30;

                x = Math.max( 0, Math.min( maxX, x ) );
                y = Math.max( 0, Math.min( maxY, y ) );

                if( mouseY < limitY ) {
                    y = limitY;
                }

                $elem.css({ left: x, top: y });
            }
        },

        // bind elements to the tooltip
        // you can bind multiple elementIDs using { elemID : function } or { elemID : string }
        // you can also bind single DOM elements using bind(elem, string)
        bind: function( elem, value ) {

            if (! tooltip.initialized ) {
                tooltip.init();
            }

            var hover = function( elem, value) {

                tooltip.define( elem, value );

                $( elem ).hover(function() {

                    Utils.clearTimer('switch_tooltip');
                    self.$('container').unbind( 'mousemove', tooltip.move ).bind( 'mousemove', tooltip.move ).trigger( 'mousemove' );
                    tooltip.show( elem );

                    Galleria.utils.addTimer( 'tooltip', function() {
                        self.$( 'tooltip' ).stop().show();
                        Utils.show( self.get( 'tooltip' ), 400 );
                        tooltip.open = true;

                    }, tooltip.open ? 0 : 500);

                }, function() {

                    self.$( 'container' ).unbind( 'mousemove', tooltip.move );
                    Utils.clearTimer( 'tooltip' );

                    self.$( 'tooltip' ).stop();

                    Utils.hide( self.get( 'tooltip' ), 200, function() {

                        self.$( 'tooltip' ).hide();

                        Utils.addTimer('switch_tooltip', function() {
                            tooltip.open = false;
                        }, 1000);
                    });
                });
            };

            if ( typeof value === 'string' ) {
                hover( ( elem in self._dom ? self.get( elem ) : elem ), value );
            } else {
                // asume elemID here
                $.each( elem, function( elemID, val ) {
                    hover( self.get(elemID), val );
                });
            }
        },

        show: function( elem ) {

            elem = $( elem in self._dom ? self.get(elem) : elem );

            var text = elem.data( 'tt' ),
                mouseup = function( e ) {

                    // attach a tiny settimeout to make sure the new tooltip is filled
                    window.setTimeout( (function( ev ) {
                        return function() {
                            tooltip.move( ev );
                        };
                    }( e )), 10);

                    elem.unbind( 'mouseup', mouseup );

                };

            text = typeof text === 'function' ? text() : text;

            if ( ! text ) {
                return;
            }

            self.$( 'tooltip' ).html( text.replace(/\s/, '&nbsp;') );

            // trigger mousemove on mouseup in case of click
            elem.bind( 'mouseup', mouseup );
        },

        define: function( elem, value ) {

            // we store functions, not strings
            if (typeof value !== 'function') {
                var s = value;
                value = function() {
                    return s;
                };
            }

            elem = $( elem in self._dom ? self.get(elem) : elem ).data('tt', value);

            tooltip.show( elem );

        }
    };

    // internal fullscreen control
    // added in 1.195
    // still kind of experimental
    var fullscreen = this._fullscreen = {
        scrolled: 0,
        active: false,
        enter: function(callback) {

            fullscreen.active = true;

            // hide the image until rescale is complete
            Utils.hide( self.getActiveImage() );

            self.$( 'container' ).addClass( 'fullscreen' );

            fullscreen.scrolled = $(window).scrollTop();

            // begin styleforce
            Utils.forceStyles(self.get('container'), {
                position: 'fixed',
                top: 0,
                left: 0,
                width: '100%',
                height: '100%',
                zIndex: 10000
            });

            var htmlbody = {
                height: '100%',
                overflow: 'hidden',
                margin:0,
                padding:0
            };

            Utils.forceStyles( DOM().html, htmlbody );
            Utils.forceStyles( DOM().body, htmlbody );

            // attach some keys
            self.attachKeyboard({
                escape: self.exitFullscreen,
                right: self.next,
                left: self.prev
            });

            // init the first rescale and attach callbacks
            self.rescale(function() {

                Utils.addTimer('fullscreen_enter', function() {
                    // show the image after 50 ms
                    Utils.show( self.getActiveImage() );

                    if (typeof callback === 'function') {
                        callback.call( self );
                    }

                }, 100);

                self.trigger( Galleria.FULLSCREEN_ENTER );
            });

            // bind the scaling to the resize event
            $(window).resize( function() {
                fullscreen.scale();
            } );
        },

        scale : function() {
            self.rescale();
        },

        exit: function(callback) {

            fullscreen.active = false;

            Utils.hide( self.getActiveImage() );

            self.$('container').removeClass( 'fullscreen' );

            // revert all styles
            Utils.revertStyles( self.get('container'), DOM().html, DOM().body );

            // scroll back
            window.scrollTo(0, fullscreen.scrolled);

            // detach all keyboard events (is this good?)
            self.detachKeyboard();

            self.rescale(function() {
                Utils.addTimer('fullscreen_exit', function() {

                    // show the image after 50 ms
                    Utils.show( self.getActiveImage() );

                    if ( typeof callback === 'function' ) {
                        callback.call( self );
                    }

                }, 50);

                self.trigger( Galleria.FULLSCREEN_EXIT );
            });

            $(window).unbind('resize', fullscreen.scale);
        }
    };

    // the internal idle object for controlling idle states
    var idle = this._idle = {

        trunk: [],

        bound: false,

        add: function(elem, to) {
            if (!elem) {
                return;
            }
            if (!idle.bound) {
                idle.addEvent();
            }
            elem = $(elem);

            var from = {},
                style;

            for ( style in to ) {
                if ( to.hasOwnProperty( style ) ) {
                    from[ style ] = elem.css( style );
                }
            }
            elem.data('idle', {
                from: from,
                to: to,
                complete: true,
                busy: false
            });
            idle.addTimer();
            idle.trunk.push(elem);
        },

        remove: function(elem) {

            elem = jQuery(elem);

            $.each(idle.trunk, function(i, el) {
                if ( el.length && !el.not(elem).length ) {
                    self._idle.show(elem);
                    self._idle.trunk.splice(i, 1);
                }
            });

            if (!idle.trunk.length) {
                idle.removeEvent();
                Utils.clearTimer('idle');
            }
        },

        addEvent : function() {
            idle.bound = true;
            self.$('container').bind('mousemove click', idle.showAll );
        },

        removeEvent : function() {
            idle.bound = false;
            self.$('container').unbind('mousemove click', idle.showAll );
        },

        addTimer : function() {
            Utils.addTimer('idle', function() {
                self._idle.hide();
            }, self._options.idleTime );
        },

        hide : function() {
            self.trigger( Galleria.IDLE_ENTER );

            $.each( idle.trunk, function(i, elem) {

                var data = elem.data('idle');

                if (! data) {
                    return;
                }

                elem.data('idle').complete = false;

                elem.stop().animate(data.to, {
                    duration: self._options.idleSpeed,
                    queue: false,
                    easing: 'swing'
                });
            });
        },

        showAll : function() {

            Utils.clearTimer('idle');

            $.each(self._idle.trunk, function( i, elem ) {
                self._idle.show( elem );
            });
        },

        show: function(elem) {

            var data = elem.data('idle');

            if (!data.busy && !data.complete) {

                data.busy = true;

                self.trigger( Galleria.IDLE_EXIT );

                Utils.clearTimer( 'idle' );

                elem.stop().animate(data.from, {
                    duration: self._options.idleSpeed/2,
                    queue: false,
                    easing: 'swing',
                    complete: function() {
                        $(this).data('idle').busy = false;
                        $(this).data('idle').complete = true;
                    }
                });
            }
            idle.addTimer();
        }
    };

    // internal lightbox object
    // creates a predesigned lightbox for simple popups of images in galleria
    var lightbox = this._lightbox = {

        width : 0,

        height : 0,

        initialized : false,

        active : null,

        image : null,

        elems : {},

        init : function() {

            // trigger the event
            self.trigger( Galleria.LIGHTBOX_OPEN );

            if ( lightbox.initialized ) {
                return;
            }
            lightbox.initialized = true;

            // create some elements to work with
            var elems = 'overlay box content shadow title info close prevholder prev nextholder next counter image',
                el = {},
                op = self._options,
                css = '',
                abs = 'position:absolute;',
                prefix = 'lightbox-',
                cssMap = {
                    overlay:    'position:fixed;display:none;opacity:'+op.overlayOpacity+';filter:alpha(opacity='+(op.overlayOpacity*100)+
                                ');top:0;left:0;width:100%;height:100%;background:'+op.overlayBackground+';z-index:99990',
                    box:        'position:fixed;display:none;width:400px;height:400px;top:50%;left:50%;margin-top:-200px;margin-left:-200px;z-index:99991',
                    shadow:     abs+'background:#000;width:100%;height:100%;',
                    content:    abs+'background-color:#fff;top:10px;left:10px;right:10px;bottom:10px;overflow:hidden',
                    info:       abs+'bottom:10px;left:10px;right:10px;color:#444;font:11px/13px arial,sans-serif;height:13px',
                    close:      abs+'top:10px;right:10px;height:20px;width:20px;background:#fff;text-align:center;cursor:pointer;color:#444;font:16px/22px arial,sans-serif;z-index:99999',
                    image:      abs+'top:10px;left:10px;right:10px;bottom:30px;overflow:hidden;display:block;',
                    prevholder: abs+'width:50%;top:0;bottom:40px;cursor:pointer;',
                    nextholder: abs+'width:50%;top:0;bottom:40px;right:-1px;cursor:pointer;',
                    prev:       abs+'top:50%;margin-top:-20px;height:40px;width:30px;background:#fff;left:20px;display:none;line-height:40px;text-align:center;color:#000',
                    next:       abs+'top:50%;margin-top:-20px;height:40px;width:30px;background:#fff;right:20px;left:auto;display:none;line-height:40px;text-align:center;color:#000',
                    title:      'float:left',
                    counter:    'float:right;margin-left:8px;'
                },
                hover = function(elem) {
                    return elem.hover(
                        function() { $(this).css( 'color', '#bbb' ); },
                        function() { $(this).css( 'color', '#444' ); }
                    );
                },
                appends = {};

            // IE8 fix for IE's transparent background event "feature"
            if ( IE === 8 ) {
                cssMap.nextholder += 'background:#000;filter:alpha(opacity=0);';
                cssMap.prevholder += 'background:#000;filter:alpha(opacity=0);';
            }

            // create and insert CSS
            $.each(cssMap, function( key, value ) {
                css += '.galleria-'+prefix+key+'{'+value+'}';
            });

            Utils.insertStyleTag( css );

            // create the elements
            $.each(elems.split(' '), function( i, elemId ) {
                self.addElement( 'lightbox-' + elemId );
                el[ elemId ] = lightbox.elems[ elemId ] = self.get( 'lightbox-' + elemId );
            });

            // initiate the image
            lightbox.image = new Galleria.Picture();

            // append the elements
            $.each({
                    box: 'shadow content close prevholder nextholder',
                    info: 'title counter',
                    content: 'info image',
                    prevholder: 'prev',
                    nextholder: 'next'
                }, function( key, val ) {
                    var arr = [];
                    $.each( val.split(' '), function( i, prop ) {
                        arr.push( prefix + prop );
                    });
                    appends[ prefix+key ] = arr;
            });

            self.append( appends );

            $( el.image ).append( lightbox.image.container );

            $( DOM().body ).append( el.overlay, el.box );

            // add the prev/next nav and bind some controls

            hover( $( el.close ).bind( CLICK(), lightbox.hide ).html('&#215;') );

            $.each( ['Prev','Next'], function(i, dir) {

                var $d = $( el[ dir.toLowerCase() ] ).html( /v/.test( dir ) ? '&#8249;&nbsp;' : '&nbsp;&#8250;' ),
                    $e = $( el[ dir.toLowerCase()+'holder'] );

                $e.bind( CLICK(), function() {
                    lightbox[ 'show' + dir ]();
                });

                // IE7 will simply show the nav
                if ( IE < 8 ) {
                    $d.show();
                    return;
                }

                $e.hover( function() {
                    $d.show();
                }, function(e) {
                    $d.stop().fadeOut( 200 );
                });

            });
            $( el.overlay ).bind( CLICK(), lightbox.hide );

        },

        rescale: function(event) {

            // calculate
             var width = Math.min( $(window).width()-40, lightbox.width ),
                height = Math.min( $(window).height()-60, lightbox.height ),
                ratio = Math.min( width / lightbox.width, height / lightbox.height ),
                destWidth = ( lightbox.width * ratio ) + 40,
                destHeight = ( lightbox.height * ratio ) + 60,
                to = {
                    width: destWidth,
                    height: destHeight,
                    marginTop: Math.ceil( destHeight / 2 ) *- 1,
                    marginLeft: Math.ceil( destWidth / 2 ) *- 1
                };

            // if rescale event, don't animate
            if ( event ) {
                $( lightbox.elems.box ).css( to );
            } else {
                $( lightbox.elems.box ).animate(
                    to,
                    self._options.lightboxTransitionSpeed,
                    self._options.easing,
                    function() {
                        var image = lightbox.image,
                            speed = self._options.lightboxFadeSpeed;

                        self.trigger({
                            type: Galleria.LIGHTBOX_IMAGE,
                            imageTarget: image.image
                        });

                        image.show();
                        Utils.show( image.image, speed );
                        Utils.show( lightbox.elems.info, speed );
                    }
                );
            }
        },

        hide: function() {

            // remove the image
            lightbox.image.image = null;

            $(window).unbind('resize', lightbox.rescale);

            $( lightbox.elems.box ).hide();

            Utils.hide( lightbox.elems.info );

            Utils.hide( lightbox.elems.overlay, 200, function() {
                $( this ).hide().css( 'opacity', self._options.overlayOpacity );
                self.trigger( Galleria.LIGHTBOX_CLOSE );
            });
        },

        showNext: function() {
            lightbox.show( self.getNext( lightbox.active ) );
        },

        showPrev: function() {
            lightbox.show( self.getPrev( lightbox.active ) );
        },

        show: function(index) {

            lightbox.active = index = typeof index === 'number' ? index : self.getIndex();

            if ( !lightbox.initialized ) {
                lightbox.init();
            }

            $(window).unbind('resize', lightbox.rescale );

            var data = self.getData(index),
                total = self.getDataLength();

            Utils.hide( lightbox.elems.info );

            lightbox.image.load( data.image, function( image ) {

                lightbox.width = image.original.width;
                lightbox.height = image.original.height;

                $( image.image ).css({
                    width: '100.5%',
                    height: '100.5%',
                    top: 0,
                    zIndex: 99998,
                    opacity: 0
                });

                lightbox.elems.title.innerHTML = data.title;
                lightbox.elems.counter.innerHTML = (index + 1) + ' / ' + total;
                $(window).resize( lightbox.rescale );
                lightbox.rescale();
            });

            $( lightbox.elems.overlay ).show();
            $( lightbox.elems.box ).show();
        }
    };

    return this;
};

// end Galleria constructor

Galleria.prototype = {

    // bring back the constructor reference

    constructor: Galleria,

    /**
        Use this function to initialize the gallery and start loading.
        Should only be called once per instance.

        @param {HTMLElement} target The target element
        @param {Object} options The gallery options

        @returns Instance
    */

    init: function( target, options ) {

        var self = this;

        options = _legacyOptions( options );

        // save the instance
        _galleries.push( this );

        // save the original ingredients
        this._original = {
            target: target,
            options: options,
            data: null
        };

        // save the target here
        this._target = this._dom.target = target.nodeName ? target : $( target ).get(0);

        // raise error if no target is detected
        if ( !this._target ) {
             Galleria.raise('Target not found.');
             return;
        }

        // apply options
        this._options = {
            name: "",
            ATHLETE_DETAIL: {}, //passed in by Athlete instance when galleria is created
            autoplay: false,
            carousel: true,
            carouselFollow: true,
            carouselSpeed: 400,
            carouselSteps: 'auto',
            clicknext: false,
            dataConfig : function( elem ) { trace('elem: ' + elem); return {}; },
            dataSelector: 'img',
           // dataSource: {}, //this._target,
            debug: undef,
            easing: 'galleria',
            extend: function(options) {},
            height: 'auto',
            idleTime: 3000,
            idleSpeed: 200,
            imageCrop: false,
            imageMargin: 0,
            imagePan: false,
            imagePanSmoothness: 12,
            imagePosition: '50%',
            keepSource: false,
            lightboxFadeSpeed: 200,
            lightboxTransition_speed: 500,
            linkSourceTmages: true,
            maxScaleRatio: undef,
            minScaleRatio: undef,
            overlayOpacity: 0.85,
            overlayBackground: '#0b0b0b',
            pauseOnInteraction: true,
            popupLinks: false,
            preload: 2,
            queue: true,
            show: 0,
            showInfo: true,
            showCounter: true,
            showImagenav: true,
            thumbCrop: true,
            thumbEventType: CLICK(),
            thumbFit: true,
            thumbMargin: 0,
            thumbQuality: 'auto',
            thumbnails: true,
            transition: 'fade',
            transitionInitial: undef,
            transitionSpeed: 400,
            width: 'auto'
        };

        // apply debug
        if ( options && options.debug === true ) {
            DEBUG = true;
        }

        // hide all content
        $( this._target ).children().hide();

        // now we just have to wait for the theme...
        // is 5 seconds enough?
        if ( typeof Galleria.theme === 'object' ) {
            this._init();
        } else {
            Utils.wait({
                until: function() {
                    return typeof Galleria.theme === 'object';
                },
                success: function() {
                    self._init.call( self );
                },
                error: function() {
                    Galleria.raise( 'No theme found.', true );
                },
                timeout: 5000
            });
        }
    },

    // this method should only be called once per instance
    // for manipulation of data, use the .load method

    _init: function() {
        var self = this;
        if ( this._initialized ) {
            Galleria.raise( 'Init failed: Gallery instance already initialized.' );
            return this;
        }

        this._initialized = true;

        if ( !Galleria.theme ) {
            Galleria.raise( 'Init failed: No theme found.' );
            return this;
        }

        // merge the theme & caller options
        $.extend( true, this._options, Galleria.theme.defaults, this._original.options );
		
        // bind the gallery to run when data is ready
        this.bind( Galleria.DATA, function() {

            // save the new data
            this._original.data = this._data;

            // lets show the counter here
            this.get('total').innerHTML = this.getDataLength();

            // cache the container
            var $container = this.$( 'container' );

            // the gallery is ready, let's just wait for the css
            var num = { width: 0, height: 0 };
            var testElem =  Utils.create('galleria-image');

            // check container and thumbnail height
            Utils.wait({
                until: function() {

                    // keep trying to get the value
                    $.each(['width', 'height'], function( i, m ) {

                        // first check if options is set

                        if ( self._options[ m ] && typeof self._options[ m ] === 'number' ) {
                            num[ m ] = self._options[ m ];
                        } else {

                            // else extract the measures from different sources and grab the highest value
                            num[m] = Math.max(
                                Utils.parseValue( $container.css( m ) ),         // 1. the container css
                                Utils.parseValue( self.$( 'target' ).css( m ) ), // 2. the target css
                                $container[ m ](),                               // 3. the container jQuery method
                                self.$( 'target' )[ m ]()                        // 4. the container jQuery method
                            );
                        }
                    });

                    var thumbHeight = function() {
                        return true;
                    };

                    // make sure thumbnails have a height as well
                    if ( self._options.thumbnails ) {
                        self.$('thumbnails').append( testElem );
                        thumbHeight = function() {
                            return !!$( testElem ).height();
                        };
                    }
                    return thumbHeight() && num.width && num.height > 10;

                },
                success: function() {

                    // remove the testElem
                    $( testElem ).remove();

                    // apply the new measures
                    $container.width( num.width );
                    $container.height( num.height );

                    // for some strange reason, webkit needs a single setTimeout to play ball
                    if ( Galleria.WEBKIT ) {
                        window.setTimeout( function() {
                            self._run();
                        }, 1);
                    } else {
                        
                        self._run();
                    }
                },
                error: function() {
                    // Height was probably not set, raise a hard error
                    Galleria.raise('Width & Height not found.', true);
                },
                timeout: 2000
            });
        });

        // postrun some stuff after the gallery is ready
        // make sure it only runs once
        var one = false;

        this.bind( Galleria.READY, (function(one) {

            return function() {

                // show counter
                Utils.show( this.get('counter') );

                // bind carousel nav
                if ( this._options.carousel ) {
                    this._carousel.bindControls();
                }

                // start autoplay
                if ( this._options.autoplay ) {

                    this.pause();

                    if ( typeof this._options.autoplay === 'number' ) {
                        this._playtime = this._options.autoplay;
                    }

                    this.trigger( Galleria.PLAY );
                    this._playing = true;
                }

                // if second load, just do the show and return
                if ( one ) {
                    if ( typeof this._options.show === 'number' ) {
                        this.show( this._options.show );
                    }
                    return;
                }

                one = true;

                // bind clicknext
                if ( this._options.clicknext ) {
                    $.each( this._data, function( i, data ) {
                        delete data.link;
                    });
                    this.$( 'stage' ).css({ cursor : 'pointer' }).bind( CLICK(), function(e) {
                        self.next();
                    });
                }

                // initialize the History plugin
                if ( Galleria.History ) {

                    // bind the show method
                    Galleria.History.change(function(e) {

                        // grab history ID
                        var val = parseInt( e.value.replace( /\//, '' ), 10 );

                        // if ID is NaN, the user pressed back from the first image
                        // return to previous address
                        if (isNaN(val)) {
                            window.history.go(-1);

                        // else show the image
                        } else {
                            self.show( val, undef, true );
                        }
                    });
                }

                // call the theme init method
                Galleria.theme.init.call( this, this._options );

                // call the extend option
                this._options.extend.call( this, this._options );

                // show the initial image
                // first test for permalinks in history
                if ( /^[0-9]{1,4}$/.test( HASH ) && Galleria.History ) {
                    this.show( HASH, undef, true );

                } else {
                    this.show( this._options.show );
                }
            };
        }( one )));

        // build the gallery frame
        this.append({
            'info-text' :
                ['info-title', 'info-description', 'info-author'],
            'info' :
                ['info-text'],
            'image-nav' :
                ['image-nav-right', 'image-nav-left'],
            'stage' :
                ['images', 'loader', 'counter', 'image-nav'],
            'thumbnails-list' :
                ['thumbnails'],
            'thumbnails-container' :
                ['thumb-nav-left', 'thumbnails-list', 'thumb-nav-right'],
            'container' :
                ['stage', 'thumbnails-container', 'info', 'tooltip']
        });

        Utils.hide( this.$( 'counter' ).append(
            this.get( 'current' ),
            ' / ',
            this.get( 'total' )
        ) );

        this.setCounter('&#8211;');
        
        Utils.hide( self.get('tooltip') );

        // add images to the controls
        $.each( new Array(2), function(i) {

            // create a new Picture instance
            var image = new Galleria.Picture();

            // apply some styles
            $( image.container ).css({
                position: 'absolute',
                top: 0,
                left: 0
            });

            // append the image
            self.$( 'images' ).append( image.container );

            // reload the controls
            self._controls[i] = image;

        });

        // some forced generic styling
        this.$( 'images' ).css({
            position: 'relative',
            top: 0,
            left: 0,
            width: '100%',
            height: '100%'
        });

        this.$( 'thumbnails, thumbnails-list' ).css({
            overflow: 'hidden',
            position: 'relative'
        });

        // bind image navigation arrows
        this.$( 'image-nav-right, image-nav-left' ).bind( CLICK(), function(e) {

            // tune the clicknext option
            if ( self._options.clicknext ) {
                e.stopPropagation();
            }

            // pause if options is set
            if ( self._options.pause_on_interaction ) {
                self.pause();
            }

            // navigate
            var fn = /right/.test( this.className ) ? 'next' : 'prev';
            self[ fn ]();

        });

        // hide controls if chosen to
        $.each( ['info','counter','image-nav'], function( i, el ) {
            if ( self._options[ 'show' + el.substr(0,1).toUpperCase() + el.substr(1).replace(/-/,'') ] === false ) {
                Utils.moveOut( self.get( el.toLowerCase() ) );
            }
        });

        // load up target content
        this.load();

        // now it's usually safe to remove the content
        // IE will never stop loading if we remove it, so let's keep it hidden for IE (it's usually fast enough anyway)
        if ( !this._options.keep_source && !IE ) {
            this._target.innerHTML = '';
        }

        // append the gallery frame
        this.$( 'target' ).append( this.get( 'container' ) );

        // parse the carousel on each thumb load
        if ( this._options.carousel ) {
            this.bind( Galleria.THUMBNAIL, function() {
                this.updateCarousel();
            });
        }

        return this;
    },

    // Creates the thumbnails and carousel
    // can be used at any time, f.ex when the data object is manipulated

    _createThumbnails : function() {

        var i,
            src,
            thumb,
            data,

            $container,

            self = this,
            o = this._options,

            // get previously active thumbnail, if exists
            active = (function() {
                var a = self.$('thumbnails').find('.active');
                if ( !a.length ) {
                    return false;
                }
                return a.find('img').attr('src');
            }()),

            // cache the thumbnail option
            optval = typeof o.thumbnails === 'string' ? o.thumbnails.toLowerCase() : null,

            // move some data into the instance
            // for some reason, jQuery cant handle css(property) when zooming in FF, breaking the gallery
            // so we resort to getComputedStyle for browsers who support it
            getStyle = function( prop ) {
                return doc.defaultView && doc.defaultView.getComputedStyle ?
                    doc.defaultView.getComputedStyle( thumb.container, null )[ prop ] :
                    $container.css( prop );
            },

            fake = function(image, index, container) {
                return function() {
                    $( container ).append( image );
                    self.trigger({
                        type: Galleria.THUMBNAIL,
                        thumbTarget: image,
                        index: index
                    });
                };
            },

            onThumbEvent = function( e ) {

                // pause if option is set
                if ( o.pauseOnInteraction ) {
                    self.pause();
                }

                // extract the index from the data
                var index = $( e.currentTarget ).data( 'index' );
                if ( self.getIndex() !== index ) {
                    self.show( index );
                }

                e.preventDefault();
            },

            onThumbLoad = function( thumb ) {

                // scale when ready
                thumb.scale({
                    width:    thumb.data.width,
                    height:   thumb.data.height,
                    crop:     o.thumbCrop,
                    margin:   o.thumbMargin,
                    complete: function( thumb ) {

                        // shrink thumbnails to fit
                        var top = ['left', 'top'],
                            arr = ['Width', 'Height'],
                            m,
                            css;

                        // calculate shrinked positions
                        $.each(arr, function( i, measure ) {
                            m = measure.toLowerCase();
                            if ( (o.thumbCrop !== true || o.thumbCrop === m ) && o.thumbFit ) {
                                css = {};
                                css[ m ] = thumb[ m ];
                                $( thumb.container ).css( css );
                                css = {};
                                css[ top[ i ] ] = 0;
                                $( thumb.image ).css( css );
                            }

                            // cache outer measures
                            thumb[ 'outer' + measure ] = $( thumb.container )[ 'outer' + measure ]( true );
                        });

                        // set high quality if downscale is moderate
                        Utils.toggleQuality( thumb.image,
                            o.thumbQuality === true ||
                            ( o.thumbQuality === 'auto' && thumb.original.width < thumb.width * 3 )
                        );

                        // trigger the THUMBNAIL event
                        self.trigger({
                            type: Galleria.THUMBNAIL,
                            thumbTarget: thumb.image,
                            index: thumb.data.order
                        });
                    }
                });
            };

        this._thumbnails = [];

        this.$( 'thumbnails' ).empty();

        // loop through data and create thumbnails
        for( i = 0; this._data[ i ]; i++ ) {

            data = this._data[ i ];

            if ( o.thumbnails === true ) {

                // add a new Picture instance
                thumb = new Galleria.Picture(i);

                // get source from thumb or image
                src = data.thumb || data.image;

                // append the thumbnail
                this.$( 'thumbnails' ).append( thumb.container );

                // cache the container
                $container = $( thumb.container );

                thumb.data = {
                    width  : Utils.parseValue( getStyle( 'width' ) ),
                    height : Utils.parseValue( getStyle( 'height' ) ),
                    order  : i
                };

                // grab & reset size for smoother thumbnail loads
                if ( o.thumbFit && o.thumbCrop !== true ) {
                    $container.css( { width: 0, height: 0 } );
                } else {
                    $container.css( { width: thumb.data.width, height: thumb.data.height } );
                }


                // load the thumbnail
                thumb.load( src, onThumbLoad );
				
				/* BEGIN ADDITION */
				$container.wrapInner('<div class="img-frame" />');
				/* END ADDITION */

                // preload all images here
                if ( o.preload === 'all' ) {
                    thumb.add( data.image );
                }

            // create empty spans if thumbnails is set to 'empty'
            } else if ( optval === 'empty' || optval === 'numbers' ) {

                thumb = {
                    container:  Utils.create( 'galleria-image' ),
                    image: Utils.create( 'img', 'span' ),
                    ready: true
                };

                // create numbered thumbnails
                if ( optval === 'numbers' ) {
                    $( thumb.image ).text( i + 1 );
                }

                this.$( 'thumbnails' ).append( thumb.container );

                // we need to "fake" a loading delay before we append and trigger
                // 50+ should be enough

                window.setTimeout( ( fake )( thumb.image, i, thumb.container ), 50 + ( i*20 ) );

            // create null object to silent errors
            } else {
                thumb = {
                    container: null,
                    image: null
                };
            }

            // add events for thumbnails
            // you can control the event type using thumb_event_type
            // we'll add the same event to the source if it's kept

            $( thumb.container ).add( o.keepSource && o.linkSourceImages ? data.original : null )
                .data('index', i).bind( o.thumbEventType, onThumbEvent );

            if (active === src) {
                $( thumb.container ).addClass( 'active' );
            }

            this._thumbnails.push( thumb );
        }
	},

    // the internal _run method should be called after loading data into galleria
    // makes sure the gallery has proper measurements before triggering ready
    _run : function() {

        var self = this;

		self._createThumbnails();

        // make sure we have a stageHeight && stageWidth

        Utils.wait({

            until: function() {
                
                // Opera crap
                if ( Galleria.OPERA ) {
                    self.$( 'stage' ).css( 'display', 'inline-block' );
                }
                
                self._stageWidth  = self.$( 'stage' ).width();
                self._stageHeight = self.$( 'stage' ).height();
                
                return( self._stageWidth && 
                        self._stageHeight > 50 ); // what is an acceptable height?
            },

            success: function() {
                self.trigger( Galleria.READY );
            },

            error: function() {
                Galleria.raise('Stage measures not found', true);
            }

        });
    },

    /**
        Loads data into the gallery.
        You can call this method on an existing gallery to reload the gallery with new data.

        @param {Array|string} source Optional JSON array of data or selector of where to find data in the document.
        Defaults to the Galleria target or dataSource option.

        @param {string} selector Optional element selector of what elements to parse.
        Defaults to 'img'.

        @param {Function} [config] Optional function to modify the data extraction proceedure from the selector.
        See the data_config option for more information.

        @returns Instance
    */

    load : function( source, selector, config ) {

        var self = this;

        // empty the data array
        this._data = [];

        // empty the thumbnails
        this._thumbnails = [];
        this.$('thumbnails').empty();

        // shorten the arguments
        if ( typeof selector === 'function' ) {
            config = selector;
            selector = null;
        }

        // use the source set by target
        source = source || this._options.dataSource;

        // use selector set by option
        selector = selector || this._options.dataSelector;

        // use the data_config set by option
        config = config || this._options.dataConfig;

        // check if the data is an array already
        if ( source.constructor === Array ) {
            if ( this.validate( source ) ) {

                this._data = source;
                this._parseData().trigger( Galleria.DATA );

            } else {
                Galleria.raise( 'Load failed: JSON Array not valid.' );
            }
            return this;
        }
        // loop through images and set data
        $( source ).find( selector ).each( function( i, img ) {
            img = $( img );
            var data = {},
                parent = img.parent(),
                href = parent.attr( 'href' );

            // check if it's a link to another image
            if ( /\.(png|gif|jpg|jpeg)(\?.*)?$/i.test(href) ) {
                data.image = href;

            // else assign the href as a link if it exists
            } else if ( href ) {
                data.link = href;
            }

            // mix default extractions with the hrefs and config
            // and push it into the data array
            self._data.push( $.extend({

                title:       img.attr('title'),
                thumb:       img.attr('src'),
                image:       img.attr('src'),
                description: img.attr('alt'),
                link:        img.attr('longdesc'),
                original:    img.get(0) // saved as a reference

            }, data, config( img ) ) );

        });
        // trigger the DATA event and return
        if ( this.getDataLength() ) {
            this.trigger( Galleria.DATA );
        } else {
            Galleria.raise('Load failed: no data found.');
        }
        return this;

    },

    // make sure the data works properly
    _parseData : function() {

        var self = this;

        // copy image as thumb if no thumb exists
        $.each( this._data, function( i, data ) {
            if ( 'thumb' in data === false ) {
                self._data[ i ].thumb = data.image;
            }
        });

        return this;
    },

    /**
        Adds and/or removes images from the gallery
		Works just like Array.splice
		https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

        @example this.splice( 2, 4 ); // removes 4 images after the second image

        @returns Instance
    */

	splice: function() {
		Array.prototype.splice.apply( this._data, Utils.array( arguments ) );
		return this._parseData()._createThumbnails();
	},

	/**
        Append images to the gallery
		Works just like Array.push
		https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push

        @example this.push({
            image: 'image1.jpg'
        }); // appends the image to the gallery

        @returns Instance
    */

	push: function() {
		Array.prototype.push.apply( this._data, Utils.array( arguments ) );
		return this._parseData()._createThumbnails();
	},

    _getActive: function() {
        return this._controls.getActive();
    },

    validate : function( data ) {
        // todo: validate a custom data array
        return true;
    },

    /**
        Bind any event to Galleria

        @param {string} type The Event type to listen for
        @param {Function} fn The function to execute when the event is triggered

        @example this.bind( 'image', function() { Galleria.log('image shown') });

        @returns Instance
    */

    bind : function(type, fn) {
        // allow 'image' instead of Galleria.IMAGE
        type = _patchEvent( type );

        this.$( 'container' ).bind( type, this.proxy(fn) );
        return this;
    },

    /**
        Unbind any event to Galleria

        @param {string} type The Event type to forget

        @returns Instance
    */

    unbind : function(type) {

        type = _patchEvent( type );

        this.$( 'container' ).unbind( type );
        return this;
    },

    /**
        Manually trigger a Galleria event

        @param {string} type The Event to trigger

        @returns Instance
    */

    trigger : function( type ) {

        type = typeof type === 'object' ?
            $.extend( type, { scope: this } ) :
            { type: _patchEvent( type ), scope: this };

        this.$( 'container' ).trigger( type );

        return this;
    },

    /**
        Assign an "idle state" to any element.
        The idle state will be applied after a certain amount of idle time
        Useful to hide f.ex navigation when the gallery is inactive

        @param {HTMLElement|string} elem The Dom node or selector to apply the idle state to
        @param {Object} styles the CSS styles to apply

        @example addIdleState( this.get('image-nav'), { opacity: 0 });
        @example addIdleState( '.galleria-image-nav', { top: -200 });

        @returns Instance
    */

    addIdleState: function( elem, styles ) {
        this._idle.add.apply( this._idle, Utils.array( arguments ) );
        return this;
    },

    /**
        Removes any idle state previously set using addIdleState()

        @param {HTMLElement|string} elem The Dom node or selector to remove the idle state from.

        @returns Instance
    */

    removeIdleState: function( elem ) {
        this._idle.remove.apply( this._idle, Utils.array( arguments ) );
        return this;
    },

    /**
        Force Galleria to enter idle mode.

        @returns Instance
    */

    enterIdleMode: function() {
        this._idle.hide();
        return this;
    },

    /**
        Force Galleria to exit idle mode.

        @returns Instance
    */

    exitIdleMode: function() {
        this._idle.showAll();
        return this;
    },

    /**
        Enter FullScreen mode

        @param {Function} callback the function to be executed when the fullscreen mode is fully applied.

        @returns Instance
    */

    enterFullscreen: function( callback ) {
        this._fullscreen.enter.apply( this, Utils.array( arguments ) );
        return this;
    },

    /**
        Exits FullScreen mode

        @param {Function} callback the function to be executed when the fullscreen mode is fully applied.

        @returns Instance
    */

    exitFullscreen: function( callback ) {
        this._fullscreen.exit.apply( this, Utils.array( arguments ) );
        return this;
    },

    /**
        Toggle FullScreen mode

        @param {Function} callback the function to be executed when the fullscreen mode is fully applied or removed.

        @returns Instance
    */

    toggleFullscreen: function( callback ) {
        this._fullscreen[ this.isFullscreen() ? 'exit' : 'enter'].apply( this, Utils.array( arguments ) );
        return this;
    },

    /**
        Adds a tooltip to any element.
        You can also call this method with an object as argument with elemID:value pairs to apply tooltips to (see examples)

        @param {HTMLElement} elem The DOM Node to attach the event to
        @param {string|Function} value The tooltip message. Can also be a function that returns a string.

        @example this.bindTooltip( this.get('thumbnails'), 'My thumbnails');
        @example this.bindTooltip( this.get('thumbnails'), function() { return 'My thumbs' });
        @example this.bindTooltip( { image_nav: 'Navigation' });

        @returns Instance
    */

    bindTooltip: function( elem, value ) {
        this._tooltip.bind.apply( this._tooltip, Utils.array(arguments) );
        return this;
    },

    /**
        Note: this method is deprecated. Use refreshTooltip() instead.

        Redefine a tooltip.
        Use this if you want to re-apply a tooltip value to an already bound tooltip element.

        @param {HTMLElement} elem The DOM Node to attach the event to
        @param {string|Function} value The tooltip message. Can also be a function that returns a string.

        @returns Instance
    */

    defineTooltip: function( elem, value ) {
        this._tooltip.define.apply( this._tooltip, Utils.array(arguments) );
        return this;
    },

    /**
        Refresh a tooltip value.
        Use this if you want to change the tooltip value at runtime, f.ex if you have a play/pause toggle.

        @param {HTMLElement} elem The DOM Node that has a tooltip that should be refreshed

        @returns Instance
    */

    refreshTooltip: function( elem ) {
        this._tooltip.show.apply( this._tooltip, Utils.array(arguments) );
        return this;
    },

    /**
        Open a pre-designed lightbox with the currently active image.
        You can control some visuals using gallery options.

        @returns Instance
    */

    openLightbox: function() {
        this._lightbox.show.apply( this._lightbox, Utils.array( arguments ) );
        return this;
    },

    /**
        Close the lightbox.

        @returns Instance
    */

    closeLightbox: function() {
        this._lightbox.hide.apply( this._lightbox, Utils.array( arguments ) );
        return this;
    },

    /**
        Get the currently active image element.

        @returns {HTMLElement} The image element
    */

    getActiveImage: function() {
        return this._getActive().image || undef;
    },

    /**
        Get the currently active thumbnail element.

        @returns {HTMLElement} The thumbnail element
    */

    getActiveThumb: function() {
        return this._thumbnails[ this._active ].image || undef;
    },

    /**
        Get the mouse position relative to the gallery container

        @param e The mouse event

        @example

var gallery = this;
$(document).mousemove(function(e) {
    console.log( gallery.getMousePosition(e).x );
});

        @returns {Object} Object with x & y of the relative mouse postion
    */

    getMousePosition : function(e) {
        return {
            x: e.pageX - this.$( 'container' ).offset().left,
            y: e.pageY - this.$( 'container' ).offset().top
        };
    },

    /**
        Adds a panning effect to the image

        @param img The optional image element. If not specified it takes the currently active image

        @returns Instance
    */

    addPan : function( img ) {

        if ( this._options.imageCrop === false ) {
            return;
        }

        img = $( img || this.getActiveImage() );

        // define some variables and methods
        var self   = this,
            x      = img.width() / 2,
            y      = img.height() / 2,
            destX  = parseInt( img.css( 'left' ), 10 ),
            destY  = parseInt( img.css( 'top' ), 10 ),
            curX   = destX || 0,
            curY   = destY || 0,
            distX  = 0,
            distY  = 0,
            active = false,
            ts     = Utils.timestamp(),
            cache  = 0,
            move   = 0,

            // positions the image
            position = function( dist, cur, pos ) {
                if ( dist > 0 ) {
                    move = Math.round( Math.max( dist * -1, Math.min( 0, cur ) ) );
                    if ( cache !== move ) {

                        cache = move;

                        if ( IE === 8 ) { // scroll is faster for IE
                            img.parent()[ 'scroll' + pos ]( move * -1 );
                        } else {
                            var css = {};
                            css[ pos.toLowerCase() ] = move;
                            img.css(css);
                        }
                    }
                }
            },

            // calculates mouse position after 50ms
            calculate = function(e) {
                if (Utils.timestamp() - ts < 50) {
                    return;
                }
                active = true;
                x = self.getMousePosition(e).x;
                y = self.getMousePosition(e).y;
            },

            // the main loop to check
            loop = function(e) {

                if (!active) {
                    return;
                }

                distX = img.width() - self._stageWidth;
                distY = img.height() - self._stageHeight;
                destX = x / self._stageWidth * distX * -1;
                destY = y / self._stageHeight * distY * -1;
                curX += ( destX - curX ) / self._options.imagePanSmoothness;
                curY += ( destY - curY ) / self._options.imagePanSmoothness;

                position( distY, curY, 'Top' );
                position( distX, curX, 'Left' );

            };

        // we need to use scroll in IE8 to speed things up
        if ( IE === 8 ) {

            img.parent().scrollTop( curY * -1 ).scrollLeft( curX * -1 );
            img.css({
                top: 0,
                left: 0
            });

        }

        // unbind and bind event
        this.$( 'stage' ).unbind( 'mousemove', calculate ).bind( 'mousemove', calculate );

        // loop the loop
        Utils.addTimer('pan', loop, 50, true);

        return this;
    },

    /**
        Brings the scope into any callback

        @param fn The callback to bring the scope into
        @param scope Optional scope to bring

        @example $('#fullscreen').click( this.proxy(function() { this.enterFullscreen(); }) )

        @returns {Function} Return the callback with the gallery scope
    */

    proxy : function( fn, scope ) {
        if ( typeof fn !== 'function' ) {
            return function() {};
        }
        scope = scope || this;
        return function() {
            return fn.apply( scope, Utils.array( arguments ) );
        };
    },

    /**
        Removes the panning effect set by addPan()

        @returns Instance
    */

    removePan: function() {

        // todo: doublecheck IE8

        this.$( 'stage' ).unbind( 'mousemove' );

        Utils.clearTimer( 'pan' );

        return this;
    },

    /**
        Adds an element to the Galleria DOM array.
        When you add an element here, you can access it using element ID in many API calls

        @param {string} id The element ID you wish to use. You can add many elements by adding more arguments.

        @example addElement('mybutton');
        @example addElement('mybutton','mylink');

        @returns Instance
    */

    addElement : function( id ) {

        var dom = this._dom;

        $.each( Utils.array(arguments), function( i, blueprint ) {
           dom[ blueprint ] = Utils.create( 'galleria-' + blueprint );
        });

        return this;
    },

    /**
        Attach keyboard events to Galleria

        @param {Object} map The map object of events.
        Possible keys are 'UP', 'DOWN', 'LEFT', 'RIGHT', 'RETURN', 'ESCAPE', 'BACKSPACE', and 'SPACE'.

        @example

this.attachKeyboard({
    right: this.next,
    left: this.prev,
    up: function() {
        console.log( 'up key pressed' )
    }
});

        @returns Instance
    */

    attachKeyboard : function( map ) {
        this._keyboard.attach.apply( this._keyboard, Utils.array( arguments ) );
        return this;
    },

    /**
        Detach all keyboard events to Galleria

        @returns Instance
    */

    detachKeyboard : function() {
        this._keyboard.detach.apply( this._keyboard, Utils.array( arguments ) );
        return this;
    },

    /**
        Fast helper for appending galleria elements that you added using addElement()

        @param {string} parentID The parent element ID where the element will be appended
        @param {string} childID the element ID that should be appended

        @example this.addElement('myElement');
        this.appendChild( 'info', 'myElement' );

        @returns Instance
    */

    appendChild : function( parentID, childID ) {
        this.$( parentID ).append( this.get( childID ) || childID );
        return this;
    },

    /**
        Fast helper for prepending galleria elements that you added using addElement()

        @param {string} parentID The parent element ID where the element will be prepended
        @param {string} childID the element ID that should be prepended

        @example

this.addElement('myElement');
this.prependChild( 'info', 'myElement' );

        @returns Instance
    */

    prependChild : function( parentID, childID ) {
        this.$( parentID ).prepend( this.get( childID ) || childID );
        return this;
    },

    /**
        Remove an element by blueprint

        @param {string} elemID The element to be removed.
        You can remove multiple elements by adding arguments.

        @returns Instance
    */

    remove : function( elemID ) {
        this.$( Utils.array( arguments ).join(',') ).remove();
        return this;
    },

    // a fast helper for building dom structures
    // leave this out of the API for now

    append : function( data ) {
        var i, j;
        for( i in data ) {
            if ( data.hasOwnProperty( i ) ) {
                if ( data[i].constructor === Array ) {
                    for( j = 0; data[i][j]; j++ ) {
                        this.appendChild( i, data[i][j] );
                    }
                } else {
                    this.appendChild( i, data[i] );
                }
            }
        }
        return this;
    },

    // an internal helper for scaling according to options
    _scaleImage : function( image, options ) {

        options = $.extend({
            width:    this._stageWidth,
            height:   this._stageHeight,
            crop:     this._options.imageCrop,
            max:      this._options.maxScaleRatio,
            min:      this._options.minScaleRatio,
            margin:   this._options.imageMargin,
            position: this._options.imagePosition
        }, options );

       ( image || this._controls.getActive() ).scale( options );

        return this;
    },

    /**
        Updates the carousel,
        useful if you resize the gallery and want to re-check if the carousel nav is needed.

        @returns Instance
    */

    updateCarousel : function() {
        this._carousel.update();
        return this;
    },

    /**
        Rescales the gallery

        @param {number} width The target width
        @param {number} height The target height
        @param {Function} complete The callback to be called when the scaling is complete

        @returns Instance
    */

    rescale : function( width, height, complete ) {

        var self = this;

        // allow rescale(fn)
        if ( typeof width === 'function' ) {
            complete = width;
            width = undef;
        }

        var scale = function() {

            // set stagewidth
            self._stageWidth = width || self.$( 'stage' ).width();
            self._stageHeight = height || self.$( 'stage' ).height();

            // scale the active image
            self._scaleImage();

            if ( self._options.carousel ) {
                self.updateCarousel();
            }

            self.trigger( Galleria.RESCALE );

            if ( typeof complete === 'function' ) {
                complete.call( self );
            }
        };

        if ( Galleria.WEBKIT && !width && !height ) {
            Utils.addTimer( 'scale', scale, 5 );// webkit is too fast
        } else {
            scale.call( self );
        }

        return this;
    },

    /**
        Refreshes the gallery.
        Useful if you change image options at runtime and want to apply the changes to the active image.

        @returns Instance
    */

    refreshImage : function() {
        this._scaleImage();
        if ( this._options.imagePan ) {
            this.addPan();
        }
        return this;
    },

	
	track: function(evt, name) {
		var s=s_gi(s_account);
		s.linkTrackVars="eVar34,campaign,events"; 
		s.linkTrackEvents="event38";
		s.eVar34=name; 
		s.events="event38";
		void(s.tl(evt,'o',"HottestImage||"+name));
	},

    /**
        Shows an image by index

        @param {number|boolean} index The index to show
        @param {Boolean} rewind A boolean that should be true if you want the transition to go back

        @returns Instance
    */

    show : function( index, rewind, _history ) {
        // do nothing if index is false or queue is false and transition is in progress
        if ( index === false || ( !this._options.queue && this._queue.stalled ) ) {
            return;
        }
        this.track(true, this._original.options.name);

        index = Math.max( 0, Math.min( parseInt( index, 10 ), this.getDataLength() - 1 ) );

        rewind = typeof rewind !== 'undefined' ? !!rewind : index < this.getIndex();

        _history = _history || false;

        // do the history thing and return
        if ( !_history && Galleria.History ) {
            Galleria.History.value( index.toString() );
            return;
        }

        this._active = index;

        Array.prototype.push.call( this._queue, {
            index : index,
            rewind : rewind
        });
        if ( !this._queue.stalled ) {
            this._show();
        }

        return this;
    },

    // the internal _show method does the actual showing
    _show : function() {// shortcuts
        var self   = this,
            queue  = this._queue[ 0 ],
            data   = this.getData( queue.index );

        if ( !data ) {
            return;
        }
		
        var src    = data.image,
            active = this._controls.getActive(),
            next   = this._controls.getNext(),
            cached = next.isCached( src ),
            thumb  = this._thumbnails[ queue.index ];

        // to be fired when loading & transition is complete:
        var complete = function() {

            var win;

            // remove stalled
            self._queue.stalled = false;

            // optimize quality
            Utils.toggleQuality( next.image, self._options.imageQuality );

            // swap
            $( active.container ).css({
                zIndex: 0,
                opacity: 0
            });
            $( next.container ).css({
                zIndex: 1,
                opacity: 1
            });
            self._controls.swap();

            // add pan according to option
            if ( self._options.imagePan ) {
                self.addPan( next.image );
            }

            // make the image link
            if ( data.link ) {

                $( next.image ).css({
                    cursor: 'pointer'
                }).bind( CLICK(), function() {

                    // popup link
                    if ( self._options.popupLinks ) {
                        win = window.open( data.link, '_blank' );
                    } else {
                        window.location.href = data.link;
                    }
                });
            }

            // remove the queued image
            Array.prototype.shift.call( self._queue );

            // if we still have images in the queue, show it
            if ( self._queue.length ) {
                self._show();
            }

            // check if we are playing
            self._playCheck();

            // trigger IMAGE event
            self.trigger({
                type:        Galleria.IMAGE,
                index:       queue.index,
                imageTarget: next.image,
                thumbTarget: thumb.image
            });
        };

        // let the carousel follow
        if ( this._options.carousel && this._options.carouselFollow ) {
            this._carousel.follow( queue.index );
        }

        // preload images
        if ( this._options.preload ) {

            var p, i,
                n = this.getNext();

            try {
                for ( i = this._options.preload; i > 0; i-- ) {
                    p = new Galleria.Picture();
                    p.add( self.getData( n ).image );
                    n = self.getNext( n );
                }
            } catch(e) {}
        }

        // show the next image, just in case
        //Utils.show( next.container ); //commented out to avoid flickering of image on initial load in IE - chris 2011/03/15

        // add active classes
        $( self._thumbnails[ queue.index ].container )
            .addClass( 'active' )
            .siblings( '.active' )
            .removeClass( 'active' );

        // trigger the LOADSTART event
        self.trigger( {
            type: Galleria.LOADSTART,
            cached: cached,
            index: queue.index,
            imageTarget: next.image,
            thumbTarget: thumb.image
        });
        // begin loading the next image
        next.load( src, function( next ) {
            self._scaleImage( next, {

                complete: function( next ) {

                    Utils.show( next.container );

                    // toggle low quality for IE
                    if ( 'image' in active ) {
                        Utils.toggleQuality( active.image, false );
                    }
                    Utils.toggleQuality( next.image, false );

                    // stall the queue
                    self._queue.stalled = true;

                    // remove the image panning, if applied
                    // TODO: rethink if this is necessary
                    self.removePan();

                    // set the captions and counter
                    self.setInfo( queue.index );
                    self.setCounter( queue.index );

                    // trigger the LOADFINISH event
                    self.trigger({
                        type: Galleria.LOADFINISH,
                        cached: cached,
                        index: queue.index,
                        imageTarget: next.image,
                        thumbTarget: self._thumbnails[ queue.index ].image
                    });

                    var transition = active.image === null && self._options.transitionInitial ?
                        self._options.transition_Initial : self._options.transition;

                    // validate the transition
                    if ( transition in _transitions === false ) {

                        complete();

                    } else {
                        var params = {
                            prev:   active.image,
                            next:   next.image,
                            rewind: queue.rewind,
                            speed:  self._options.transitionSpeed || 400
                        };

                        // call the transition function and send some stuff
                        _transitions[ transition ].call(self, params, complete );

                    }
                }
            });
        });
    },

    /**
        Gets the next index

        @param {number} base Optional starting point

        @returns {number} the next index, or the first if you are at the first (looping)
    */

    getNext : function( base ) {
        base = typeof base === 'number' ? base : this.getIndex();
        return base === this.getDataLength() - 1 ? 0 : base + 1;
    },

    /**
        Gets the previous index

        @param {number} base Optional starting point

        @returns {number} the previous index, or the last if you are at the first (looping)
    */

    getPrev : function( base ) {
        base = typeof base === 'number' ? base : this.getIndex();
        return base === 0 ? this.getDataLength() - 1 : base - 1;
    },

    /**
        Shows the next image in line

        @returns Instance
    */

    next : function() {
        if ( this.getDataLength() > 1 ) {
            this.show( this.getNext(), false );
        }
        return this;
    },

    /**
        Shows the previous image in line

        @returns Instance
    */

    prev : function() {
        if ( this.getDataLength() > 1 ) {
            this.show( this.getPrev(), true );
        }
        return this;
    },

    /**
        Retrieve a DOM element by element ID

        @param {string} elemId The delement ID to fetch

        @returns {HTMLElement} The elements DOM node or null if not found.
    */

    get : function( elemId ) {
        return elemId in this._dom ? this._dom[ elemId ] : null;
    },

    /**
        Retrieve a data object

        @param {number} index The data index to retrieve.
        If no index specified it will take the currently active image

        @returns {Object} The data object
    */

    getData : function( index ) {
        return index in this._data ?
            this._data[ index ] : this._data[ this._active ];
    },

    /**
        Retrieve the number of data items

        @returns {number} The data length
    */
    getDataLength : function() {
        return this._data.length;
    },

    /**
        Retrieve the currently active index

        @returns {number|boolean} The active index or false if none found
    */

    getIndex : function() {
        return typeof this._active === 'number' ? this._active : false;
    },

    /**
        Retrieve the stage height

        @returns {number} The stage height
    */

    getStageHeight : function() {
        return this._stageHeight;
    },

    /**
        Retrieve the stage width

        @returns {number} The stage width
    */

    getStageWidth : function() {
        return this._stageWidth;
    },

    /**
        Retrieve the option

        @param {string} key The option key to retrieve. If no key specified it will return all options in an object.

        @returns option or options
    */

    getOptions : function( key ) {
        return typeof key === 'undefined' ? this._options : this._options[ key ];
    },

    /**
        Set options to the instance.
        You can set options using a key & value argument or a single object argument (see examples)

        @param {string} key The option key
        @param {string} value the the options value

        @example setOptions( 'autoplay', true )
        @example setOptions({ autoplay: true });

        @returns Instance
    */

    setOptions : function( key, value ) {
        if ( typeof key === 'object' ) {
            $.extend( this._options, key );
        } else {
            this._options[ key ] = value;
        }
        return this;
    },

    /**
        Starts playing the slideshow

        @param {number} delay Sets the slideshow interval in milliseconds.
        If you set it once, you can just call play() and get the same interval the next time.

        @returns Instance
    */

    play : function( delay ) {

        this._playing = true;

        this._playtime = delay || this._playtime;

        this._playCheck();

        this.trigger( Galleria.PLAY );

        return this;
    },

    /**
        Stops the slideshow if currently playing

        @returns Instance
    */

    pause : function() {

        this._playing = false;

        this.trigger( Galleria.PAUSE );

        return this;
    },

    /**
        Toggle between play and pause events.

        @param {number} delay Sets the slideshow interval in milliseconds.

        @returns Instance
    */

    playToggle : function( delay ) {
        return ( this._playing ) ? this.pause() : this.play( delay );
    },

    /**
        Checks if the gallery is currently playing

        @returns {Boolean}
    */

    isPlaying : function() {
        return this._playing;
    },

    /**
        Checks if the gallery is currently in fullscreen mode

        @returns {Boolean}
    */

    isFullscreen : function() {
        return this._fullscreen.active;
    },

    _playCheck : function() {
        var self = this,
            played = 0,
            interval = 20,
            now = Utils.timestamp(),
			timer_id = 'play' + this._id;

        if ( this._playing ) {

			Utils.clearTimer( timer_id );

            var fn = function() {

                played = Utils.timestamp() - now;
                if ( played >= self._playtime && self._playing ) {
                    Utils.clearTimer( timer_id );
                    self.next();
                    return;
                }
                if ( self._playing ) {

                    // trigger the PROGRESS event
                    self.trigger({
                        type:         Galleria.PROGRESS,
                        percent:      Math.ceil( played / self._playtime * 100 ),
                        seconds:      Math.floor( played / 1000 ),
                        milliseconds: played
                    });

                    Utils.addTimer( timer_id, fn, interval );
                }
            };
            Utils.addTimer( timer_id, fn, interval );
        }
    },

    setIndex: function( val ) {
        this._active = val;
        return this;
    },

    /**
        Manually modify the counter

        @param {number} index Optional data index to fectch,
        if no index found it assumes the currently active index

        @returns Instance
    */

    setCounter: function( index ) {

        if ( typeof index === 'number' ) {
            index++;
        } else if ( typeof index === 'undefined' ) {
            index = this.getIndex()+1;
        }

        this.get( 'current' ).innerHTML = index;

        if ( IE ) { // weird IE bug

            var count = this.$( 'counter' ),
                opacity = count.css( 'opacity' ),
                style = count.attr('style');
                
            if ( style && parseInt( opacity, 10 ) === 1) {
                count.attr('style', style.replace(/filter[^\;]+\;/i,''));
            } else {
                this.$( 'counter' ).css( 'opacity', opacity );
            }

        }

        return this;
    },

    /**
        Manually set captions

        @param {number} index Optional data index to fectch and apply as caption,
        if no index found it assumes the currently active index

        @returns Instance
    */

    setInfo : function( index ) {

        var self = this,
            data = this.getData( index );

        $.each( ['title','description','author'], function( i, type ) {

            var elem = self.$( 'info-' + type );

            if ( !!data[type] ) {
                elem[ data[ type ].length ? 'show' : 'hide' ]().html( data[ type ] );
            } else {
               elem.empty().hide();
            }
        });

        return this;
    },

    /**
        Checks if the data contains any captions

        @param {number} index Optional data index to fectch,
        if no index found it assumes the currently active index.

        @returns {boolean}
    */

    hasInfo : function( index ) {

        var check = 'title description'.split(' '),
            i;

        for ( i = 0; check[i]; i++ ) {
            if ( !!this.getData( index )[ check[i] ] ) {
                return true;
            }
        }
        return false;

    },

    jQuery : function( str ) {

        var self = this,
            ret = [];

        $.each( str.split(','), function( i, elemId ) {
            elemId = $.trim( elemId );

            if ( self.get( elemId ) ) {
                ret.push( elemId );
            }
        });

        var jQ = $( self.get( ret.shift() ) );

        $.each( ret, function( i, elemId ) {
            jQ = jQ.add( self.get( elemId ) );
        });

        return jQ;

    },

    /**
        Converts element IDs into a jQuery collection
        You can call for multiple IDs separated with commas.

        @param {string} str One or more element IDs (comma-separated)

        @returns jQuery

        @example this.$('info,container').hide();
    */

    $ : function( str ) {
        return this.jQuery.apply( this, Utils.array( arguments ) );
    }

};

// End of Galleria prototype

// Add events as static variables
$.each( _events, function( i, ev ) {

    // legacy events
    var type = /_/.test( ev ) ? ev.replace( /_/g, '' ) : ev;

    Galleria[ ev.toUpperCase() ] = 'galleria.'+type;

} );

$.extend( Galleria, {

    // Browser helpers
    IE9:     IE === 9,
    IE8:     IE === 8,
    IE7:     IE === 7,
    IE6:     IE === 6,
    IE:      !!IE,
    WEBKIT:  /webkit/.test( NAV ),
    SAFARI:  /safari/.test( NAV ),
    CHROME:  /chrome/.test( NAV ),
    QUIRK:   ( IE && doc.compatMode && doc.compatMode === "BackCompat" ),
    MAC:     /mac/.test( navigator.platform.toLowerCase() ),
    OPERA:   !!window.opera,
    IPHONE:  /iphone/.test( NAV ),
    IPAD:    /ipad/.test( NAV ),
    ANDROID: /android/.test( NAV ),

    // Todo detect touch devices in a better way, possibly using event detection
    TOUCH:   !!( /iphone/.test( NAV ) || /ipad/.test( NAV ) || /android/.test( NAV ) )

});

// Galleria static methods

/**
    Adds a theme that you can use for your Gallery

    @param {Object} theme Object that should contain all your theme settings.
    <ul>
        <li>name – name of the theme</li>
        <li>author - name of the author</li>
        <li>css - css file name (not path)</li>
        <li>defaults - default options to apply, including theme-specific options</li>
        <li>init - the init function</li>
    </ul>

    @returns {Object} theme
*/

Galleria.addTheme = function( theme ) {

    // make sure we have a name
    if ( !theme.name ) {
        Galleria.raise('No theme name specified');
    }

    if ( typeof theme.defaults !== 'object' ) {
        theme.defaults = {};
    } else {
        theme.defaults = _legacyOptions( theme.defaults );
    }

    var css = false,
        reg;
    
    if ( typeof theme.css === 'string' ) {
        
        // look for manually added CSS
        $('link').each(function( i, link ) {
            reg = new RegExp( theme.css );
            if ( reg.test( link.href ) ) {
                
                // we found the css
                css = true;
                Galleria.theme = theme;
                
                return false;
            }
        });
        
        // else look for the absolute path and load the CSS dynamic
        if ( !css ) {

            $('script').each(function( i, script ) {

                // look for the theme script
                reg = new RegExp( 'galleria\\.' + theme.name.toLowerCase() + '\\.' );
                if( reg.test( script.src )) {

                    // we have a match
                    css = script.src.replace(/[^\/]*$/, '') + theme.css;

                    Utils.addTimer( "css", function() {
                        Utils.loadCSS( css, 'galleria-theme', function() {
                            Galleria.theme = theme;
                        });
                    }, 1);

                }
            });
        }

        if ( !css ) {
            Galleria.raise('No theme CSS loaded');
        }
    } else {
        
        // pass
        Galleria.theme = theme;
    }
    return theme;
};

/**
    loadTheme loads a theme js file and attaches a load event to Galleria

    @param {string} src The relative path to the theme source file

    @param {Object} [options] Optional options you want to apply
*/

Galleria.loadTheme = function( src, options ) {

    var loaded = false,
        length = _galleries.length;

    // first clear the current theme, if exists
    Galleria.theme = undef;

    // load the theme
    Utils.loadScript( src, function() {
        loaded = true;
    } );

    // set a 1 sec timeout, then display a hard error if no theme is loaded
    Utils.wait({
        until: function() {
            return loaded;
        },
        error: function() {
            Galleria.raise( "Theme at " + src + " could not load, check theme path.", true );
        },
        success: function() {

            // check for existing galleries and reload them with the new theme
            if ( length ) {

                // temporary save the new galleries
                var refreshed = [];

                // refresh all instances
                // when adding a new theme to an existing gallery, all options will be resetted but the data will be kept
                // you can apply new options as a second argument
                $.each( Galleria.get(), function(i, instance) {

                    // mix the old data and options into the new instance
                    var op = $.extend( instance._original.options, {
                        data_source: instance._data
                    }, options);

                    // remove the old container
                    instance.$('container').remove();

                    // create a new instance
                    var g = new Galleria();

                    // move the id
                    g._id = instance._id;

                    // initialize the new instance
                    g.init( instance._original.target, op );

                    // push the new instance
                    refreshed.push( g );
                });

                // now overwrite the old holder with the new instances
                _galleries = refreshed;
            }
        },
        timeout: 2000
    });
};

/**
    Retrieves a Galleria instance.

    @param {number} [index] Optional index to retrieve.
    If no index is supplied, the method will return all instances in an array.

    @returns Instance or Array of instances
*/

Galleria.get = function( index ) {
    if ( !!_galleries[ index ] ) {
        return _galleries[ index ];
    } else if ( typeof index !== 'number' ) {
        return _galleries;
    } else {
        Galleria.raise('Gallery index ' + index + ' not found');
    }
};

/**
    Creates a transition to be used in your gallery

    @param {string} name The name of the transition that you will use as an option

    @param {Function} fn The function to be executed in the transition.
    The function contains two arguments, params and complete.
    Use the params Object to integrate the transition, and then call complete when you are done.

*/

Galleria.addTransition = function( name, fn ) {
    _transitions[name] = fn;
};

Galleria.utils = Utils;

/**
    A helper metod for cross-browser logging.
    It uses the console log if available otherwise it falls back to the opera
    debugger and finally <code>alert()</code>

    @example Galleria.log("hello", document.body, [1,2,3]);
*/

Galleria.log = function() {
    try {
        window.console.log.apply( window.console, Utils.array( arguments ) );
    } catch( e ) {
        try {
            window.opera.postError.apply( window.opera, arguments );
        } catch( er ) {
              window.alert( Utils.array( arguments ).split(', ') );
        }
    }
};

/**
    Method for raising errors

    @param {string} msg The message to throw

    @param {boolean} [fatal] Set this to true to override debug settings and display a fatal error
*/

Galleria.raise = function( msg, fatal ) {

    if ( DEBUG || fatal ) {
        var type = fatal ? 'Fatal error' : 'Error';
        throw new Error(type + ': ' + msg);
    }

};

/**
    Adds preload, cache, scale and crop functionality

    @constructor

    @requires jQuery

    @param {number} [id] Optional id to keep track of instances
*/

Galleria.Picture = function( id ) {

    // save the id
    this.id = id || null;

    // the image should be null until loaded
    this.image = null;

    // Create a new container
    this.container = Utils.create('galleria-image');

    // add container styles
    $( this.container ).css({
        overflow: 'hidden',
        position: 'relative' // for IE Standards mode
    });

    // saves the original measurements
    this.original = {
        width: 0,
        height: 0
    };

    // flag when the image is ready
    this.ready = false;

    // flag when the image is loaded
    this.loaded = false;

};

Galleria.Picture.prototype = {

    // the inherited cache object
    cache: {},

    // creates a new image and adds it to cache when loaded
    add: function( src ) {

        var i = 0,
            self = this,

            // create the image
            image = new Image(),
            
            onload = function() {
                
                // force chrome to reload the image in case of cache bug
                // set a limit just in case
                if ( ( !this.width || !this.height ) && i < 1000 ) {
                    i++;
                    $( image ).load( onload ).attr( 'src', src+'?'+new Date().getTime() );
                }

                self.original = {
                    height: this.height,
                    width: this.width
                };

                self.cache[ src ] = src; // will override old cache
                self.loaded = true;
            };

        // force a block display
        $( image ).css( 'display', 'block');
        
        if ( self.cache[ src ] ) {
            // no need to onload if the image is cached
            image.src = src;
            onload.call( image );
            return image;
        }

        // begin preload and insert in cache when done
        $( image ).load( onload ).attr( 'src', src );

        return image;

    },

    // show the image on stage
    show: function() {
        Utils.show( this.image );
    },

    // hide the image
    hide: function() {
        Utils.moveOut( this.image );
    },

    clear: function() {
        this.image = null;
    },

    /**
        Checks if an image is in cache

        @param {string} src The image source path, ex '/path/to/img.jpg'

        @returns {boolean}
    */

    isCached: function( src ) {
        return !!this.cache[src];
    },

    /**
        Loads an image and call the callback when ready.
        Will also add the image to cache.

        @param {string} src The image source path, ex '/path/to/img.jpg'
        @param {Function} callback The function to be executed when the image is loaded & scaled

        @returns The image container (jQuery object)
    */

    load: function(src, callback) {

        // save the instance
        var self = this;

        $( this.container ).empty(true);

        // add the image to cache and hide it
        this.image = this.add( src );
        Utils.hide( this.image );

        // append the image into the container
        $( this.container ).append( this.image );

        // check for loaded image using a timeout
        Utils.wait({
            until: function() {
                // TODO this should be properly tested in Opera
                return self.loaded && self.image.complete && self.original.width && self.image.width;
            },
            success: function() {
                // call success
                window.setTimeout(function() { callback.call( self, self ); }, 50 );
            },
            error: function() {
                window.setTimeout(function() { callback.call( self, self ); }, 50 );
                Galleria.raise('image not loaded in 10 seconds: '+ src);
            },
            timeout: 10000
        });

        // return the container
        return this.container;
    },

    /**
        Scales and crops the image

        @param {Object} options The method takes an object with a number of options:

        <ul>
            <li>width - width of the container</li>
            <li>height - height of the container</li>
            <li>min - minimum scale ratio</li>
            <li>max - maximum scale ratio</li>
            <li>margin - distance in pixels from the image border to the container</li>
            <li>complete - a callback that fires when scaling is complete</li>
            <li>position - positions the image, works like the css background-image property.</li>
            <li>crop - defines how to crop. Can be true, false, 'width' or 'height'</li>
        </ul>

        @returns The image container object (jQuery)
    */

    scale: function( options ) {

        // extend some defaults
        options = $.extend({
            width: 0,
            height: 0,
            min: undef,
            max: undef,
            margin: 0,
            complete: function() {},
            position: 'center',
            crop: false
        }, options);

        // return the element if no image found
        if (!this.image) {
            return this.container;
        }

        // store locale variables of width & height
        var width,
            height,
            self = this,
            $container = $( self.container );

        // wait for the width/height
        Utils.wait({
            until: function() {

                width  = options.width
                    || $container.width()
                    || Utils.parseValue( $container.css('width') );

                height = options.height
                    || $container.height()
                    || Utils.parseValue( $container.css('height') );

                return width && height;
            },
            success: function() {
                // calculate some cropping
                var newWidth = ( width - options.margin * 2 ) / self.original.width,
                    newHeight = ( height - options.margin * 2 ) / self.original.height,
                    cropMap = {
                        'true'  : Math.max( newWidth, newHeight ),
                        'width' : newWidth,
                        'height': newHeight,
                        'false' : Math.min( newWidth, newHeight )
                    },
                    ratio = cropMap[ options.crop.toString() ];

                // allow max_scale_ratio
                if ( options.max ) {
                    ratio = Math.min( options.max, ratio );
                }

                // allow min_scale_ratio
                if ( options.min ) {
                    ratio = Math.max( options.min, ratio );
                }

                $( self.container ).width( width ).height( height );

                // round up the width / height
                $.each( ['width','height'], function( i, m ) {
                    $( self.image )[ m ]( self.image[m] = self[ m ] = Math.round( self.original[ m ] * ratio ) );
                });

                // calculate image_position
                var pos = {},
                    mix = {},
                    getPosition = function(value, measure, margin) {
                        var result = 0;
                        if (/\%/.test(value)) {
                            var flt = parseInt( value, 10 ) / 100,
                                m = self.image[ measure ] || $( self.image )[ measure ]();

                            result = Math.ceil( m * -1 * flt + margin * flt );
                        } else {
                            result = Utils.parseValue( value );
                        }
                        return result;
                    },
                    positionMap = {
                        'top': { top: 0 },
                        'left': { left: 0 },
                        'right': { left: '100%' },
                        'bottom': { top: '100%' }
                    };

                $.each( options.position.toLowerCase().split(' '), function( i, value ) {
                    if ( value === 'center' ) {
                        value = '50%';
                    }
                    pos[i ? 'top' : 'left'] = value;
                });

                $.each( pos, function( i, value ) {
                    if ( positionMap.hasOwnProperty( value ) ) {
                        $.extend( mix, positionMap[ value ] );
                    }
                });

                pos = pos.top ? $.extend( pos, mix ) : mix;

                pos = $.extend({
                    top: '50%',
                    left: '50%'
                }, pos);

                // apply position
                $( self.image ).css({
                    position : 'relative',
                    top :  getPosition(pos.top, 'height', height),
                    left : getPosition(pos.left, 'width', width)
                });

                // show the image
                self.show();

                // flag ready and call the callback
                self.ready = true;
                options.complete.call( self, self );
            },
            error: function() {
                Galleria.raise('Could not scale image: '+self.image.src);
            },
            timeout: 1000
        });
        return this;
    }
};

// our own easings 
$.extend( $.easing, {

    galleria: function (_, t, b, c, d) {
        if ((t/=d/2) < 1) {
            return c/2*t*t*t*t + b;
        }
        return -c/2 * ((t-=2)*t*t*t - 2) + b;
    },

    galleriaIn: function (_, t, b, c, d) {
        return c*(t/=d)*t*t*t + b;
    },

    galleriaOut: function (_, t, b, c, d) {
        return -c * ((t=t/d-1)*t*t*t - 1) + b;
    }

});

// the plugin initializer
$.fn.galleria = function( options ) {

    return this.each(function() {

        var gallery = new Galleria();
        gallery.init( this, options );

    });
};

// Expose
window.Galleria = Galleria;

// phew

}( jQuery ) );(function ($) {
	// constructor
	function InstagramGallery(root, conf)
	{	
		// Private fields ------------------------------------------------------------------

		var $root = $(root),
			$domElem = $root[0],
			_self = this,
			
			$btnBack,
			$btnPlayPause,
			$btnMore,
			$instaInfo,
			$instaPhoto,
			$instaUser,
			$instaCaption,
			$instaFilter,
			$timerBar,
			timerMaxWidth,
			
			curStartIndex = 0,
			numThumbs = 16,
			_imgData,
			
			GALLERIA,
			$galleryStage,
			SLIDESHOW_WAIT = 4000, //milliseconds to show each image
			isPlaying = false,
			isPlayingOverride = false,
			loadMoreTimeout = -1,
			
			$opts = {
				imgData: null,
				eventName: 'instagramDefault',
				showLocation: true,
				defaultMapAddress: '',
				mainImgWidth: 612,
				mainImgHeight: 612
			};
			
		$.extend($opts, conf);

		// Public methods ------------------------------------------------------------------
		
		$.extend(_self, {
			onProgressEvent: function(evt) {
				updateTimerPercent(evt.percent);
			},
			onPlayEvent: function(e) {
				isPlaying = true;
				
				startCountdown();
				setPauseState();
			},
			onPauseEvent: function(e) {
				isPlaying = false;
				clearTimeout(loadMoreTimeout);
				
				stopCountdown();
				setPlayState();
			},
			onImageLoaded: function(e) {
				setInfo();
			},
			onImageDisplayed: function(e) {
				GALLERIA.$('loader').hide();
				if (isPlaying == true) {
					testLoadMore();
				}
			},
			onSlideshowMoreLoaded: function() {
				GALLERIA.unbind('loadfinish');
				GALLERIA.bind('loadfinish', GALLERIA._options.galleriaMgr.onImageLoaded);
				clearTimeout(loadMoreTimeout);
				loadMoreTimeout = setTimeout(resumeSlideshow, 100);
			}
		});

		// Private methods -----------------------------------------------------------------
		function initGalleria() {
			Galleria.addTheme({
			    name: 'classic',
			    init: function(options) {
			        this.$('loader').show().css('opacity', 0.4);
					
					this.bind('play', this._options.galleriaMgr.onPlayEvent);
					this.bind('pause', this._options.galleriaMgr.onPauseEvent);
					this.bind('progress', this._options.galleriaMgr.onProgressEvent);
					this.bind('loadfinish', this._options.galleriaMgr.onImageLoaded);
					this.bind('image', this._options.galleriaMgr.onImageDisplayed);
			        
			        this.bind('loadstart', function(e) {
			            if (!e.cached) {
			                this.$('loader').show();
			            }
			        });
			        
			        this.bind('loadfinish', function(e) {
			            this.$('loader').hide();
			        });
			    }
			});

			var curData = _imgData.slice(curStartIndex,numThumbs);
			$('#galleria').galleria({
				dataSource: curData,
				name: $opts.eventName,
				galleriaMgr: _self,
				preload: 5,
				transition: 'fade',
				width: 960,
				height: $opts.mainImgHeight,
				showInfo: false,
				showCounter: false,
				thumbCrop: true,
				transition: 'none',
				thumbFit: false,
				imageCrop: false //true means images will be scaled to fill the stage, centered and cropped. # false will scale down so the entire image fits.
			});
			
			GALLERIA = Galleria.get(0);
			$galleryStage = $('.galleria-stage');
			
			$('.instagram-galleria-nav').appendTo('.galleria-container').show();
			if ($opts.showLocation == true) {
				$('.instagram-galleria-map').appendTo('.galleria-container').show();
			}
		}
				
		function showGalleria(){
			$galleryStage.show();
		}		
		function testLoadMore() {
			var doLoadMore = GALLERIA.getNext() == 0 && _imgData.length > numThumbs;
//			trace('GALLERIA.getNext(): ' + GALLERIA.getNext());
//			trace('doLoadMore: ' + doLoadMore);
			if (doLoadMore) {
				loadMoreTimeout = setTimeout(loadMoreSlideshow, SLIDESHOW_WAIT);
			}
		}
		function setInfo() {
			var data = GALLERIA.getData(GALLERIA.getIndex());
			$instaPhoto.attr('src', data.profile_picture);
			$instaUser.html(data.username);
			$instaCaption.html(data.caption);
			$instaFilter.html(data.filter);
			$instaInfo.show();
			
			if ($opts.showLocation == true) {
				var mapUrl = "http://maps.googleapis.com/maps/api/staticmap?center="+$opts.defaultMapAddress+"&zoom=14&size=313x208&maptype=roadmap&sensor=false";
				if (data.location && data.location.latitude) {
					var latLong = data.location.latitude + "," + data.location.longitude;
					mapUrl = "http://maps.googleapis.com/maps/api/staticmap?center="+latLong+"&zoom=14&size=313x208&maptype=roadmap&sensor=false&markers=color:blue|"+latLong;
					
					$instaMapImg.attr("src", mapUrl);
					$instaMapImg.css('opacity', 1);
					$instaMapMsg.hide();
				} else {
					$instaMapImg.attr("src", mapUrl);
					$instaMapImg.css('opacity', .5);
					$instaMapMsg.show();
				}
			}
		}
		function resumeSlideshow() {
			GALLERIA.play(SLIDESHOW_WAIT);
		}
		function doPlay(evt) {
			GALLERIA.play(SLIDESHOW_WAIT);
			testLoadMore();
			trackClick(evt, 'Play SlideShow ' + $opts.eventName);
			
			return false;
		}
		function doPause() {
			GALLERIA.pause();
			
			return false;
		}
		function setPauseState() {
			$btnPlayPause.unbind();
			$btnPlayPause.addClass("show-paused")
				.find('.slideshow-caption').html("STOP");
			$btnPlayPause.click(doPause);
		}
		function setPlayState() {
			if (isPlayingOverride) {
				isPlayingOverride = false;
			} else {
				$btnPlayPause.unbind();
				$btnPlayPause.removeClass("show-paused").find('.slideshow-caption').html("SLIDESHOW");
				$btnPlayPause.click(doPlay);
			}
		}
		function loadPrev(evt) {
			GALLERIA.pause();
			curStartIndex = Math.max(curStartIndex-numThumbs, 0);
			loadCurrentSet();
			updateNavStates();
			
			return false;
		}
		function loadMoreSlideshow() {
			isPlayingOverride = true;
			GALLERIA.pause();
			GALLERIA.unbind('loadfinish');
			GALLERIA.bind('loadfinish', GALLERIA._options.galleriaMgr.onSlideshowMoreLoaded);
			
			loadMore();
		}
		function loadMore(evt) {
			GALLERIA.pause();
			curStartIndex = curStartIndex + numThumbs;
			if (curStartIndex >= _imgData.length) {
				curStartIndex = 0;
			}
			loadCurrentSet();
			updateNavStates();
			
			return false;
		}
		function loadCurrentSet() {
			var curData = _imgData.slice(curStartIndex,curStartIndex+numThumbs);
			GALLERIA.load(curData);
		}
		function updateNavStates() {
			$btnBack.unbind();
			if (curStartIndex > 0) {
	        	$btnBack.bind("click", loadPrev);
				$btnBack.removeClass('inactive');
			} else {
				$btnBack.addClass('inactive');
			}
			$btnMore.unbind();
			var hasMore = (curStartIndex + numThumbs) < _imgData.length;
			if (hasMore) {
	        	$btnMore.bind("click", loadMore);
				$btnMore.removeClass('inactive');
			} else {
				$btnMore.addClass('inactive');
			}
		}
		
		function startCountdown(){
			$timerBar.show();
		}
		
		function updateTimerPercent(percent){
			var maxWidth = timerMaxWidth || initTimerMaxWidth(); 
			var displayPercent = (100-percent) / 100;
			$timerBar.width(maxWidth * displayPercent);
		}
		
		function stopCountdown(){
			$timerBar.hide();
		}
		
		function initTimerMaxWidth(){
			timerMaxWidth = parseInt($timerBar.css("width"));
			return timerMaxWidth;
		}
		
		function trackClick(evt, name) {
			/*
			try {
				var s=s_gi(s_account);
				s.linkTrackVars="eVar34,campaign,events"; 
				s.linkTrackEvents="event38";
				s.eVar34=name; 
				s.events="event38";
				void(s.tl(evt,'o',"InstagramClick||"+name));
			} catch (e) {}
			*/
		}
		
		function init() {
			_imgData = $opts.imgData;
			
			//trace('_imgData.length: ' + _imgData.length);
			
			if (_imgData == null || _imgData.length == 0) {
				//trace('no images');
			} else {
				$instaInfo = $('.instagram-info');
				$instaPhoto = $(".instagram-profile-pic img");
				$instaUser = $(".instagram-username");
				$instaCaption = $(".instagram-caption");
				$instaFilter = $(".instagram-filter");
				
				$instaMap = $('.instagram-galleria-map');
				$instaMapImg = $('.instagram-galleria-map img');
				$instaMapMsg = $('.instagram-galleria-map .map-no-data-message');
				
	        	$btnBack = $(".instagram-back");//.bind("click", loadPrev);
	        	$btnPlayPause = $(".instagram-slideshow").bind("click", doPlay);
	        	$btnMore = $(".instagram-more");//.bind("click", loadMore);
				updateNavStates();
			
				$timerWrapper = $('div.timer-wrapper');
				$timerBar = $('div.timer-bar');
				
				initGalleria();
			}
		}

		// Initialization ------------------------------------------------------------------
		init();
	};

	// jQuery plugin implementation
	$.fn.instagramGallery = function(conf)
	{ 
		this.each(function() {
			var $instance = new InstagramGallery(this, conf);
			$(this).data("instagramGallery", $instance);
		});
		
		return this;
	};
})(jQuery);
