// declare nav global variables
var megaNavArray = [], megaNavArrayLength, mainNavArray = [], mainNavArrayLength, bannerArray = [], bannerArrayLength, bannerIndex;

// declare function variables to make them global
var prepareNav, prepareShowcase, prepareBanner, showcaseLeftAnim, showcaseRightAnim, bannerLeftAnim, bannerRightAnim, hideMegaNavs, removeHere, overlayOn, overlayOff, tertiaryWidth = 0, tertiaryLeftMax, tertiaryMaxWidth = 880, yearsVisibleInNav = 12;

// JSON declaration should be pulled to a place where content can be modified and translated
var strings={
	closedToggle: "Search Again",
	openedToggle: "Close"
};

(function ($) {
		$.extend({
			getUrlVars: function(){
				var vars = [], hash;
				var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
				for(var i = 0; i < hashes.length; i++)
				{
					hash = hashes[i].split('=');
					vars.push(hash[0]);
					vars[hash[0]] = hash[1];
				}
				return vars;
			},
			getUrlVar: function(name){
				return $.getUrlVars()[name];
			}
		});
		prepareNav = function(){
			$("body").prepend("<div id='overlay'></div>"); // onmouseover='overlayOff();'
			$(".mega").each(function() { megaNavArray.push(this.id) });
			megaNavArrayLength = megaNavArray.length;
			$('#nav li a').each(function(){
				mainNavArray.push(this.id);
				$(this).bind("mouseover",function(e){
					e.preventDefault();
					overlayOn(this.id);
				});
			});
			mainNavArrayLength = mainNavArray.length;
		};
		prepareShowcase = function(){
			$('#showcase-content').append("<div class='showcase-control' id='showcase-left' onclick='showcaseLeftAnim();'><a href='javascript:void(0);'></a></div>");
			$('#showcase-content').append("<div class='showcase-control' id='showcase-right' onclick='showcaseRightAnim();'><a href='javascript:void(0);'></a></div>");
		};
		prepareBanner = function(){
			$('#banner-nav-content').append("<div class='banner-control' id='banner-left' onclick='bannerLeftAnim();'><a href='javascript:void(0);'></a></div>");
			$('#banner-nav-content').append("<div class='banner-control' id='banner-right' onclick='bannerRightAnim();'><a href='javascript:void(0);'></a></div>");
			$('.home-bd').each(function(){
				bannerArray.push(this.id);
				$(this).css('display','none');
			});
			bannerArrayLength = bannerArray.length;
			bannerIndex = bannerArrayLength - 1;
			bannerIndex = 0;
			bannerHere(bannerIndex);
		};
		prepareProjectSearch = function(){
			$('#bd-header-content').append("<div class='project-search-toggle' id='project-search-toggle-closed' onclick='projectSearchToggle();'><a href='javascript:void(0);'></a></div>");
			$('#bd-header-content').append("<div class='project-search-toggle' id='project-search-toggle-open' onclick='projectSearchToggle();'><a href='javascript:void(0);'></a></div>");
			$('#project-search-toggle-closed a').text(strings.closedToggle);
			$('#project-search-toggle-open a').text(strings.openedToggle);
		};
		prepareInnerBanner = function(){
			$('#banner-nav-content').append("<div class='banner-control' id='banner-left' onclick='bannerLeftAnim();'><a href='javascript:void(0);'></a></div>");
			$('#banner-nav-content').append("<div class='banner-control' id='banner-right' onclick='bannerRightAnim();'><a href='javascript:void(0);'></a></div>");
			$('.banner-bd').each(function(){
				bannerArray.push(this.id);
			});
			bannerArrayLength = bannerArray.length;
			bannerIndex = bannerArrayLength - 1;
			var i = 0;
			$('#banner-nav-content ol li p a').each(function(i, val){
				$(this).bind("click",function(e){
					e.preventDefault();
					bannerAnim(i);
				});
			});
			bannerIndex = 0;
			bannerHere(bannerIndex);
		};
		activateTertiaryControls = function(){
			$('#tertiary-left').bind("click",function(e){
				e.preventDefault();
				tertiaryAnimLeft();
			});
			$('#tertiary-right').bind("click",function(e){
				e.preventDefault();
				tertiaryAnimRight();
			});
		};
		tertiaryAnimLeft = function(){
			var tertiaryLocation = $('#tertiary-mask ul').position().left;
			if($('#tertiary-mask ul').position().left < 0){
				$('#tertiary-mask ul').animate({"left": "+="+tertiaryLeftMax+"px"}, "fast");
			};
		};
		tertiaryAnimRight = function(){
			var tertiaryLocation = $('#tertiary-mask ul').position().left;
			if($('#tertiary-mask ul').position().left >= 0){
				$('#tertiary-mask ul').animate({"left": "-="+tertiaryLeftMax+"px"}, "fast");
			};
		};
		perpareTertiary = function(){
			$('#tertiary-content ul li').each(function(i, val){
				tertiaryWidth = tertiaryWidth + $(this).width();
			});
			if(tertiaryWidth>tertiaryMaxWidth){
				tertiaryLeftMax = tertiaryWidth-tertiaryMaxWidth;
				activateTertiaryControls();
			};
		};
		projectSearchToggle = function(){
			var height = $('#bd-header').height();
			if (height<=50){
				$('#bd-header').animate({"height": "230px"}, "fast");
				$('#project-search-toggle-closed').css('display','none');
				$('#project-search-toggle-open').css('display','block');
			}else if (height >=230){
				$('#bd-header').animate({"height": "50px"}, "fast");
				$('#project-search-toggle-open').css('display','none');
				$('#project-search-toggle-closed').css('display','block');
			}
		}
		prepareProjectListShowcase = function(){
			$('#primary').append("<div class='showcase-control' id='showcase-left' onclick='projectListShowcaseLeftAnim();'><a href='javascript:void(0);'></a></div>");
			$('#primary').append("<div class='showcase-control' id='showcase-right' onclick='projectListShowcaseRightAnim();'><a href='javascript:void(0);'></a></div>");
		};
		/**
		projectListShowcaseLeftAnim = function(){
			if ($('#primary ul:first').position().left < 0){
				$('#primary ul:first').animate({"left": "+=222px"}, "fast");
			};
		};
		projectListShowcaseLeftAnim = function(){
			var listCount = $('#primary ul:first > li').size();
			var itemWidth = $('#primary ul:first > li').width();
			var maxLeft = ((listCount - 4) * itemWidth);
			if ($('#primary ul:first').position().left > -maxLeft){
				$('#primary ul:first').animate({"left": "-=222px"}, "fast");
			};
		};
		**/
		projectListShowcaseLeftAnim = function(){
			var parentPosition = $('#project-list-mask').offset();
			var lastItemPosition = $('#project-list-mask ul li:first').offset();
			if ((parentPosition.left) > lastItemPosition.left){
				$('#project-list-mask ul').animate({"left": "+=220px"}, "fast");
			};
		};
		projectListShowcaseRightAnim = function(){
			var itemWidth = $('#project-list-mask ul li:first').outerWidth() + 10;
			var parentPosition = $('#project-list-mask').offset();
			var lastItemPosition = $('#project-list-mask ul li:last').offset();
			if ((parentPosition.left + itemWidth*4) < lastItemPosition.left){
				$('#project-list-mask ul').animate({"left": "-=220px"}, "fast");
			};
		};		
		
		bannerHere = function(i){
			$('#banner-nav-content ol li').css('display','none');
			$('#'+bannerArray[i]).css('display','block');
		}
		bannerAnim = function(i){
			if (i != bannerIndex){
				$('#'+bannerArray[bannerIndex]).fadeOut('slow');
				$('#'+bannerArray[i]).fadeIn('slow');
				bannerIndex = i;
				bannerHere(bannerIndex);
			}
		};
		bannerRightAnim = function(){
			$('#'+bannerArray[bannerIndex]).fadeOut('slow');
			bannerIndex++;
			if (bannerIndex>=bannerArrayLength) bannerIndex = 0;
			$('#'+bannerArray[bannerIndex]).fadeIn('slow');
			bannerHere(bannerIndex);
		};
		bannerLeftAnim = function(){
			$('#'+bannerArray[bannerIndex]).fadeOut('slow');
			bannerIndex--;
			if (bannerIndex<0) bannerIndex = bannerArrayLength-1;
			$('#'+bannerArray[bannerIndex]).fadeIn('slow');
			bannerHere(bannerIndex);
		};
		showcaseLeftAnim = function(){
			var parentPosition = $('#showcase-content').offset();
			var lastItemPosition = $('#showcase-content ul li.views-row-first').offset();
			//alert(parentPosition.left - lastItemPosition.left);
			if ((parentPosition.left) > lastItemPosition.left){
				$('#showcase-content ul').animate({"left": "+=170px"}, "fast");
			};
		};
		showcaseRightAnim = function(){
			var itemWidth = $('#showcase-content ul li.views-row-first').outerWidth() + 10;
			var parentPosition = $('#showcase-content').offset();
			var lastItemPosition = $('#showcase-content ul li.views-row-last').offset();
			//alert(lastItemPosition.left - (parentPosition.left + itemWidth*5));
			if ((parentPosition.left + itemWidth*5) < lastItemPosition.left){
				$('#showcase-content ul').animate({"left": "-=170px"}, "fast");
			};
		};
		hideMegaNavs = function(){
			for(i=0;i<megaNavArrayLength;i++){
				//document.getElementById(megaNavArray[i]).style.display = 'none';
			};
		};
		removeHere = function(){
			for(i=0;i<mainNavArrayLength;i++){
				//FIX THIS - document.getElementById(mainNavArray[i]).className = '';
			};
		};
		prepareContact = function(){
			$('#country-tabs li').each(function(i, val){
				$(this).bind("click",function(e){
					e.preventDefault();
					setContact(val);
				});
			});
			//add toggle functionality
			$('.office-locations dt').each(function(i, val){
				$(this).bind("click",function(e){
					e.preventDefault();
					toggleLocation(val);
				});
			});
		};
		toggleLocation = function(me){
			if($(me).next().css("display")=='none'){
				$(me).next().css("display","block");
				$(me).css({backgroundPosition: '-1051px -205px'});
			}else{
				$(me).next().css("display","none");
				$(me).css({backgroundPosition: '-758px -205px'});
			};
		};
		hideContact = function(){
			$('#country-tabs li').each(function(i, val){
				$(this).removeClass("here");
			});
			$('.country-tab-content').each(function(i, val){
				$(this).css("display","none");
			});
		};
		setContact = function(me){
			hideContact();
			$(me).addClass("here");
			$('#'+me.id+'-contact-info').css("display","block");
			//turn on the background
		};
		initTimeline = function(){
			$('#timeline-nav ul > li').live('click', function(e){
				selectItem(this);
			});

			$('#timeline-list > li').live('click',function(e){
				selectItem($('#timeline-nav ul > li:eq(' + $(this).index() +')'));
			});

			$('#timeline-list > li a').live('click',function(e){
				if(!$(this).parent().parent().parent().parent().hasClass('selected')){
					e.preventDefault();
				}
			});

			$('#timeline-nav .previous').live('click', function(e){
				timelineNavLeft();
			});

			$('#timeline-nav .next').live('click', function(e){
				timelineNavRight();
			});
		};
		initWidgetMembrane = function(){
			var blnOpen = false;
			var intImgSelected = 0;
			var intCapSelected = 0;
			$('#launch').bind('click',function() {
				toggleControls(this);
			});
			$('#btn-1').bind('click',function() {
				toggleLayer(1);
			});
			$('#btn-2').bind('click',function() {
				toggleLayer(2);
			});
			$('#btn-3').bind('click',function() {
				toggleLayer(3);
			});
			$('#btn-4').bind('click',function() {
				toggleLayer(4);
			});
			$('#btn-5').bind('click',function() {
				toggleLayer(5);
			});
			toggleControls = function(me) {
				if(blnOpen) {
					$(me).removeClass('selected');
					$(me).html("Expand and Explore Layers");
					$('#controls').removeClass().addClass('hide');
					$('#btn-'+intImgSelected).removeClass();
					$('#image').removeClass();
					$('#caption-'+intCapSelected).removeClass().addClass('hide');
					intImgSelected = 5;
					intCapSelected = 0;
					blnOpen = false;
				} else {
					$(me).addClass('selected');
					$(me).html('Compress Layers');
					$('#controls').removeClass().addClass('show');
					$('#image').addClass('panel-5');
					$('#caption-0').removeClass().addClass('show');
					intImgSelected = 5;
					intCapSelected = 0;
					blnOpen = true;
				};
			};
			toggleLayer = function(me) {
				if(intCapSelected!=me) {
					$('#btn-'+intImgSelected).removeClass();
					$('#btn-'+me).addClass('selected');
					$('#caption-'+intCapSelected).removeClass().addClass('hide');
					$('#caption-'+me).removeClass().addClass('show');
					$('#image').removeClass().addClass('panel-'+me);
					intImgSelected = me;
					intCapSelected = me;
				};
			};
		};
		initWidgetComponents = function(){
			var blnOpen = false;
			var intImgSelected = 0;
			var intCapSelected = 0;
			$('#launch').bind('click',function() {
				toggleControls(this);
			});
			$('#btn-1').bind('click',function() {
				toggleLayer(1);
			});
			$('#btn-2').bind('click',function() {
				toggleLayer(2);
			});
			$('#btn-3').bind('click',function() {
				toggleLayer(3);
			});
			$('#btn-4').bind('click',function() {
				toggleLayer(4);
			});
			$('#btn-5').bind('click',function() {
				toggleLayer(5);
			});
			toggleControls = function(me) {
				if(blnOpen) {
					$(me).removeClass('selected');
					$(me).html("Explore the Components");
					$('#controls').removeClass().addClass('hide');
					$('#btn-'+intImgSelected).removeClass();
					$('#image').removeClass();
					$('#caption-'+intCapSelected).removeClass().addClass('hide');
					intImgSelected = 5;
					intCapSelected = 0;
					blnOpen = false;
				} else {
					$(me).addClass('selected');
					$(me).html('');
					$('#controls').removeClass().addClass('show');
					$('#caption-0').removeClass().addClass('show');
					intImgSelected = 0;
					intCapSelected = 0;
					blnOpen = true;
				};
			};
			toggleLayer = function(me) {
				if(intCapSelected!=me) {
					$('#btn-'+intImgSelected).removeClass();
					$('#btn-'+me).addClass('selected');
					$('#caption-'+intCapSelected).removeClass().addClass('hide');
					$('#caption-'+me).removeClass().addClass('show');
					$('#image').removeClass().addClass('panel-'+me);
					intImgSelected = me;
					intCapSelected = me;
				};
			};
		};
		initWidgetInsulation = function(){
			var blnOpen = false;
			var intImgSelected = 0;
			var intCapSelected = 0;
			$('#btn-0').bind('click',function() {
				toggleControls(this);
			});
			$('#btn-1').bind('click',function() {
				toggleLayer(1);
			});
			$('#btn-2').bind('click',function() {
				toggleLayer(2);
			});
			$('#btn-3').bind('click',function() {
				toggleLayer(3);
			});
			toggleControls = function(me) {
				if(blnOpen) {
					$('#sub-title').removeClass().addClass('show');
					$(me).removeClass('selected');
					$(me).html("Compare R-Values");
					$('#controls').removeClass().addClass('hide');
					toggleLayer(0);
					blnOpen = false;
				} else {
					$('#sub-title').removeClass().addClass('hide');
					$(me).addClass('selected');
					$(me).html('Close');
					$('#controls').removeClass().addClass('show');
					toggleLayer(1);
					blnOpen = true;
				};
			};
			toggleLayer = function(me) {
				if(intCapSelected!=me) {
					$('#btn-'+intImgSelected).removeClass();
					$('#btn-'+me).removeClass().addClass('selected');
					$('#caption-'+intCapSelected).removeClass().addClass('hide');
					$('#caption-'+me).removeClass().addClass('show');
					$('#fact-'+intCapSelected).removeClass().addClass('hide');
					$('#fact-'+me).removeClass().addClass('show');
					$('#image').removeClass().addClass('panel-'+me);
					intImgSelected = me;
					intCapSelected = me;
				};
			};
		};
		initWidgetAluminum = function(){
			var blnOpen = false;
			var intSelected = 0;
			$('#launch').bind('click',function() {
				toggleControls(this);
			});
			$('#btn-1').bind('click',function() {
				toggleLayer(1);
			});
			$('#btn-2').bind('click',function() {
				toggleLayer(2);
			});
			$('#btn-3').bind('click',function() {
				toggleLayer(3);
			});
			$('#btn-4').bind('click',function() {
				toggleLayer(4);
			});
			$('#btn-5').bind('click',function() {
				toggleLayer(5);
			});
			$('#btn-6').bind('click',function() {
				toggleLayer(6);
			});
			$('#btn-7').bind('click',function() {
				toggleLayer(7);
			});
			toggleControls = function(me) {
				if(blnOpen) {
					$(me).removeClass('selected');
					$(me).html("Learn How...");
					$('#controls').removeClass().addClass('hide');
					toggleLayer(0);
					blnOpen = false;
				} else {
					$(me).addClass('selected');
					$(me).html('');
					$('#controls').removeClass().addClass('show');
					toggleLayer(1);
					blnOpen = true;
				};
			};
			toggleLayer = function(me) {
				if(intSelected!=me) {
					$('#btn-'+intSelected).removeClass();
					$('#btn-'+me).addClass('selected');
					$('#caption-'+intSelected).removeClass().addClass('hide');
					$('#caption-'+me).removeClass().addClass('show');
					intSelected = me;
				};
			};
		};
		selectItem = function(that){
			var currEle = $('#timeline-list > li:eq(' + $(that).index() +')');
			var listCount = $('#timeline-nav ul > li').size();
			var itemWidth = parseInt($('#timeline-nav ul > li:first').css('marginLeft'))+$('#timeline-nav ul > li:first').width();
			var maxLeft = ((listCount - yearsVisibleInNav) * itemWidth);
			$('#timeline-nav ul > li').removeClass('selected');
			$(that).addClass('selected');
			$('#timeline-list > li').removeClass('selected');
			currEle.addClass('selected');
			$('#timeline-list').animate({'left': '-' + currEle.position().left + 'px'}, 'fast');

			if (listCount-$(that).index()+1 > yearsVisibleInNav){
				$('#timeline-nav ul').animate({'left': '-'+ Math.floor($(that).position().left) + 'px'}, 'fast');
			}
			else{
				$('#timeline-nav ul').animate({'left': '-'+ maxLeft + 'px'}, 'fast');
			}
		};
		timelineNavLeft = function(){
			var itemWidth = parseInt($('#timeline-nav ul > li:first').css('marginLeft'))+$('#timeline-nav ul > li:first').width();
			if (Math.ceil($('#timeline-nav ul').position().left) < 0){
				$('#timeline-nav ul').animate({'left': '+='+ itemWidth + 'px'}, 'fast');
			};
		};
		timelineNavRight = function(){
			var listCount = $('#timeline-nav ul > li').size();
			var itemWidth = parseInt($('#timeline-nav ul > li:first').css('marginLeft'))+$('#timeline-nav ul > li:first').width();
			var maxLeft = ((listCount - yearsVisibleInNav) * itemWidth);
			if ($('#timeline-nav ul').position().left > -maxLeft){
				$('#timeline-nav ul').animate({'left': '-='+ itemWidth + 'px'}, 'fast');
			};
		};
		overlayOn = function(subnav){
			hideMegaNavs();
			removeHere();
			if ($('#'+subnav+'-nav').length){
				//$('#overlay').css('display', 'block');
			//	if($.browser.msie && parseInt($.browser.version, 10) <= 7) {
			//		$('#overlay').css('display', 'none');
			//	};
			//	$('#nav-sections').css('display', 'block');
			//	$('#nav').attr("class","active");
			//	$('a[id^='+subnav+']').attr("class","here");
			//	$('div[id^='+subnav+'-nav]').css('display', 'block');
			}else{
				overlayOff();
			};
		};
		overlayOff = function(){
			$('#overlay').css('display', 'none');
			$('#nav-sections').css('display', 'none');
			$('#nav').attr('class','');
			hideMegaNavs();
			removeHere();
		};
		
		var types = ['DOMMouseScroll', 'mousewheel'];

		$.event.special.mousewheel = {
			setup: function() {
				if ( this.addEventListener )
					for ( var i=types.length; i; )
						this.addEventListener( types[--i], handler, false );
				else
					this.onmousewheel = handler;
			},

			teardown: function() {
				if ( this.removeEventListener )
					for ( var i=types.length; i; )
						this.removeEventListener( types[--i], handler, false );
				else
					this.onmousewheel = null;
			}
		};

		$.fn.extend({
			mousewheel: function(fn) {
				return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
			},

			unmousewheel: function(fn) {
				return this.unbind("mousewheel", fn);
			}
		});


		function handler(event) {
			var args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true;

			event = $.event.fix(event || window.event);
			event.type = "mousewheel";

			if ( event.wheelDelta ) delta = event.wheelDelta/120;
			if ( event.detail     ) delta = -event.detail/3;

			// Add events and delta to the front of the arguments
			args.unshift(event, delta);

			return $.event.handle.apply(this, args);
		}
		
		$('a.overlay').colorbox();

		})(jQuery);

		/**
		 * @version		$Id:  $Revision
		 * @package		jquery
		 * @subpackage	lofslidernews
		 * @copyright	Copyright (C) JAN 2010 LandOfCoder.com <@emai:landofcoder@gmail.com>. All rights reserved.
		 * @website     http://landofcoder.com
		 * @license		This plugin is dual-licensed under the GNU General Public License and the MIT License 
		 */
		// JavaScript Document
		(function($) {
			 $.fn.lofJSidernews = function( settings ) {
			 	return this.each(function() {
					// get instance of the lofSiderNew.
					new  $.lofSidernews( this, settings ); 
				});
		 	 }
			 $.lofSidernews = function( obj, settings ){
				this.settings = {
					direction	    	: '',
					mainItemSelector    : 'li',
					navInnerSelector	: 'ul',
					navSelector  		: 'li' ,
					navigatorEvent		: 'click',
					wapperSelector: 	'.lof-main-wapper',
					interval	  	 	: 4000,
					auto			    : true, // whether to automatic play the slideshow
					maxItemDisplay	 	: 3,
					startItem			: 0,
					navPosition			: 'vertical', 
					navigatorHeight		: 111,
					navigatorWidth		: 389,
					duration			: 600,
					navItemsSelector    : '.lof-navigator li',
					navOuterSelector    : '.lof-navigator-outer' ,
					isPreloaded			: true,
					easing				: 'easeInOutQuad'
				}	
				$.extend( this.settings, settings ||{} );	
				this.nextNo         = null;
				this.previousNo     = null;
				this.maxWidth  = this.settings.mainWidth || 590;
				this.wrapper = $( obj ).find( this.settings.wapperSelector );	
				this.slides = this.wrapper.find( this.settings.mainItemSelector );
				if( !this.wrapper.length || !this.slides.length ) return ;
				// set width of wapper
				if( this.settings.maxItemDisplay > this.slides.length ){
					this.settings.maxItemDisplay = this.slides.length;	
				}
				this.currentNo      = isNaN(this.settings.startItem)||this.settings.startItem > this.slides.length?0:this.settings.startItem;
				this.navigatorOuter = $( obj ).find( this.settings.navOuterSelector );	
				this.navigatorItems = $( obj ).find( this.settings.navItemsSelector ) ;
				this.navigatorInner = this.navigatorOuter.find( this.settings.navInnerSelector );

				if( this.settings.navPosition == 'horizontal' ){ 
					this.navigatorInner.width( this.slides.length * this.settings.navigatorWidth );
					this.navigatorOuter.width( this.settings.maxItemDisplay * this.settings.navigatorWidth );
					this.navigatorOuter.height(	this.settings.navigatorHeight );

				} else {
					this.navigatorInner.height( this.slides.length * this.settings.navigatorHeight );	

					this.navigatorOuter.height( this.settings.maxItemDisplay * this.settings.navigatorHeight );
					this.navigatorOuter.width(	this.settings.navigatorWidth );
				}		
				this.navigratorStep = this.__getPositionMode( this.settings.navPosition );		
				this.directionMode = this.__getDirectionMode();  


				if( this.settings.direction == 'opacity') {
					this.wrapper.addClass( 'lof-opacity' );
					$(this.slides).css('opacity',0).eq(this.currentNo).css('opacity',1);
					this.caption = $( obj ).find( '.lof-main-item-desc' );
					$( obj ).find( '.lof-main-item-desc' ).hide().eq(0).show();
				} else { 
					this.wrapper.css({'left':'-'+this.currentNo*this.maxSize+'px', 'width':( this.maxWidth ) * this.slides.length } );
				}


				if( this.settings.isPreloaded ) {
					this.preLoadImage( this.onComplete );
				} else {
					this.onComplete();
				}

			 }
		     $.lofSidernews.fn =  $.lofSidernews.prototype;
		     $.lofSidernews.fn.extend =  $.lofSidernews.extend = $.extend;

			 $.lofSidernews.fn.extend({

				startUp:function( obj, wrapper ) {
					seft = this;

					this.navigatorItems.each( function(index, item ){
						$(item).click( function(){
							seft.jumping( index, true );
							seft.setNavActive( index, item );					
						} );
						$(item).css( {'height': seft.settings.navigatorHeight, 'width':  seft.settings.navigatorWidth} );
					})
					this.registerWheelHandler( this.navigatorOuter, this );
					this.setNavActive(this.currentNo );

					if( this.settings.buttons && typeof (this.settings.buttons) == "object" ){
						this.registerButtonsControl( 'click', this.settings.buttons, this );

					}
					if( this.settings.auto ) 
					this.play( this.settings.interval,'next', true );

					return this;
				},
				onComplete:function(){
					setTimeout( function(){ $('.preload').fadeOut( 900 ); }, 400 );	this.startUp( );
				},
				preLoadImage:function(  callback ){
					var self = this;
					var images = this.wrapper.find( 'img' );

					var count = 0;
					images.each( function(index,image){ 
						if( !image.complete ){				  
							image.onload =function(){
								count++;
								if( count >= images.length ){
									self.onComplete();
								}
							}
							image.onerror =function(){ 
								count++;
								if( count >= images.length ){
									self.onComplete();
								}	
							}
						}else {
							count++;
							if( count >= images.length ){
								self.onComplete();
							}	
						}
					} );
				},
				navivationAnimate:function( currentIndex ) { 
					if (currentIndex <= this.settings.startItem 
						|| currentIndex - this.settings.startItem >= this.settings.maxItemDisplay-1) {
							this.settings.startItem = currentIndex - this.settings.maxItemDisplay+2;
							if (this.settings.startItem < 0) this.settings.startItem = 0;
							if (this.settings.startItem >this.slides.length-this.settings.maxItemDisplay) {
								this.settings.startItem = this.slides.length-this.settings.maxItemDisplay;
							}
					}		
					this.navigatorInner.stop().animate( eval('({'+this.navigratorStep[0]+':-'+this.settings.startItem*this.navigratorStep[1]+'})'), 
														{duration:500, easing:'easeInOutQuad'} );	
				},
				setNavActive:function( index, item ){
					if( (this.navigatorItems) ){ 
						this.navigatorItems.removeClass( 'active' );
						$(this.navigatorItems.get(index)).addClass( 'active' );	
						this.navivationAnimate( this.currentNo );	
					}
				},
				__getPositionMode:function( position ){
					if(	position  == 'horizontal' ){
						return ['left', this.settings.navigatorWidth];
					}
					return ['top', this.settings.navigatorHeight];
				},
				__getDirectionMode:function(){
					switch( this.settings.direction ){
						case 'opacity': this.maxSize=0; return ['opacity','opacity'];
						default: this.maxSize=this.maxWidth; return ['left','width'];
					}
				},
				registerWheelHandler:function( element, obj ){ 
					 element.bind('mousewheel', function(event, delta ) {
						var dir = delta > 0 ? 'Up' : 'Down',
							vel = Math.abs(delta);
						if( delta > 0 ){
							obj.previous( true );
						} else {
							obj.next( true );
						}
						return false;
					});
				},
				registerButtonsControl:function( eventHandler, objects, self ){ 
					for( var action in objects ){ 
						switch (action.toString() ){
							case 'next':
								objects[action].click( function() { self.next( true) } );
								break;
							case 'previous':
								objects[action].click( function() { self.previous( true) } );
								break;
						}
					}
					return this;	
				},
				onProcessing:function( manual, start, end ){	 		
					this.previousNo = this.currentNo + (this.currentNo>0 ? -1 : this.slides.length-1);
					this.nextNo 	= this.currentNo + (this.currentNo < this.slides.length-1 ? 1 : 1- this.slides.length);				
					return this;
				},
				finishFx:function( manual ){
					if( manual ) this.stop();
					if( manual && this.settings.auto ){ 
						this.play( this.settings.interval,'next', true );
					}		
					this.setNavActive( this.currentNo );	
				},
				getObjectDirection:function( start, end ){
					return eval("({'"+this.directionMode[0]+"':-"+(this.currentNo*start)+"})");	
				},
				fxStart:function( index, obj, currentObj ){
						if( this.settings.direction == 'opacity' ) { 
							$(this.slides).stop().animate({opacity:0}, {duration: this.settings.duration, easing:this.settings.easing} );
							$(this.slides).eq(index).stop().animate( {opacity:1},this.settings.duration, this.settings.easing, function(){
																					$(currentObj.caption.slideUp().eq(index)).slideDown();																
																			} );

						}else {
							this.wrapper.stop().animate( obj, {duration: this.settings.duration, easing:this.settings.easing} );
						}
					return this;
				},
				jumping:function( no, manual ){
					this.stop(); 
					if( this.currentNo == no ) return;		
					 var obj = eval("({'"+this.directionMode[0]+"':-"+(this.maxSize*no)+"})");
					this.onProcessing( null, manual, 0, this.maxSize )
						.fxStart( no, obj, this )
						.finishFx( manual );	
						this.currentNo  = no;
				},
				next:function( manual , item){

					this.currentNo += (this.currentNo < this.slides.length-1) ? 1 : (1 - this.slides.length);	
					this.onProcessing( item, manual, 0, this.maxSize )
						.fxStart( this.currentNo, this.getObjectDirection(this.maxSize ), this )
						.finishFx( manual );
				},
				previous:function( manual, item ){
					this.currentNo += this.currentNo > 0 ? -1 : this.slides.length - 1;
					this.onProcessing( item, manual )
						.fxStart( this.currentNo, this.getObjectDirection(this.maxSize ), this )
						.finishFx( manual	);			
				},
				play:function( delay, direction, wait ){	
					this.stop(); 
					if(!wait){ this[direction](false); }
					var self  = this;
					this.isRun = setTimeout(function() { self[direction](true); }, delay);
				},
				stop:function(){ 
					if (this.isRun == null) return;
					clearTimeout(this.isRun);
		            this.isRun = null; 
				}
			})
			
			/*
			 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
			 *
			 * Uses the built in easing capabilities added In jQuery 1.1
			 * to offer multiple easing options
			 *
			 * TERMS OF USE - jQuery Easing
			 * 
			 * Open source under the BSD License. 
			 * 
			 * Copyright © 2008 George McGinley Smith
			 * All rights reserved.
			 * 
			 * Redistribution and use in source and binary forms, with or without modification, 
			 * are permitted provided that the following conditions are met:
			 * 
			 * Redistributions of source code must retain the above copyright notice, this list of 
			 * conditions and the following disclaimer.
			 * Redistributions in binary form must reproduce the above copyright notice, this list 
			 * of conditions and the following disclaimer in the documentation and/or other materials 
			 * provided with the distribution.
			 * 
			 * Neither the name of the author nor the names of contributors may be used to endorse 
			 * or promote products derived from this software without specific prior written permission.
			 * 
			 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
			 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
			 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
			 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
			 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
			 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
			 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
			 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
			 * OF THE POSSIBILITY OF SUCH DAMAGE. 
			 *
			*/

			// t: current time, b: begInnIng value, c: change In value, d: duration
			jQuery.easing['jswing'] = jQuery.easing['swing'];

			jQuery.extend( jQuery.easing,
			{
				def: 'easeOutQuad',
				swing: function (x, t, b, c, d) {
					//alert(jQuery.easing.default);
					return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
				},
				easeInQuad: function (x, t, b, c, d) {
					return c*(t/=d)*t + b;
				},
				easeOutQuad: function (x, t, b, c, d) {
					return -c *(t/=d)*(t-2) + b;
				},
				easeInOutQuad: function (x, t, b, c, d) {
					if ((t/=d/2) < 1) return c/2*t*t + b;
					return -c/2 * ((--t)*(t-2) - 1) + b;
				},
				easeInCubic: function (x, t, b, c, d) {
					return c*(t/=d)*t*t + b;
				},
				easeOutCubic: function (x, t, b, c, d) {
					return c*((t=t/d-1)*t*t + 1) + b;
				},
				easeInOutCubic: function (x, t, b, c, d) {
					if ((t/=d/2) < 1) return c/2*t*t*t + b;
					return c/2*((t-=2)*t*t + 2) + b;
				},
				easeInQuart: function (x, t, b, c, d) {
					return c*(t/=d)*t*t*t + b;
				},
				easeOutQuart: function (x, t, b, c, d) {
					return -c * ((t=t/d-1)*t*t*t - 1) + b;
				},
				easeInOutQuart: function (x, 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;
				},
				easeInQuint: function (x, t, b, c, d) {
					return c*(t/=d)*t*t*t*t + b;
				},
				easeOutQuint: function (x, t, b, c, d) {
					return c*((t=t/d-1)*t*t*t*t + 1) + b;
				},
				easeInOutQuint: function (x, t, b, c, d) {
					if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
					return c/2*((t-=2)*t*t*t*t + 2) + b;
				},
				easeInSine: function (x, t, b, c, d) {
					return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
				},
				easeOutSine: function (x, t, b, c, d) {
					return c * Math.sin(t/d * (Math.PI/2)) + b;
				},
				easeInOutSine: function (x, t, b, c, d) {
					return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
				},
				easeInExpo: function (x, t, b, c, d) {
					return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
				},
				easeOutExpo: function (x, t, b, c, d) {
					return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
				},
				easeInOutExpo: function (x, t, b, c, d) {
					if (t==0) return b;
					if (t==d) return b+c;
					if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
					return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
				},
				easeInCirc: function (x, t, b, c, d) {
					return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
				},
				easeOutCirc: function (x, t, b, c, d) {
					return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
				},
				easeInOutCirc: function (x, t, b, c, d) {
					if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
					return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
				},
				easeInElastic: function (x, t, b, c, d) {
					var s=1.70158;var p=0;var a=c;
					if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
					if (a < Math.abs(c)) { a=c; var s=p/4; }
					else var s = p/(2*Math.PI) * Math.asin (c/a);
					return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
				},
				easeOutElastic: function (x, t, b, c, d) {
					var s=1.70158;var p=0;var a=c;
					if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
					if (a < Math.abs(c)) { a=c; var s=p/4; }
					else var s = p/(2*Math.PI) * Math.asin (c/a);
					return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
				},
				easeInOutElastic: function (x, t, b, c, d) {
					var s=1.70158;var p=0;var a=c;
					if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
					if (a < Math.abs(c)) { a=c; var s=p/4; }
					else var s = p/(2*Math.PI) * Math.asin (c/a);
					if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
					return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
				},
				easeInBack: function (x, t, b, c, d, s) {
					if (s == undefined) s = 1.70158;
					return c*(t/=d)*t*((s+1)*t - s) + b;
				},
				easeOutBack: function (x, t, b, c, d, s) {
					if (s == undefined) s = 1.70158;
					return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
				},
				easeInOutBack: function (x, t, b, c, d, s) {
					if (s == undefined) s = 1.70158; 
					if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
					return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
				},
				easeInBounce: function (x, t, b, c, d) {
					return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
				},
				easeOutBounce: function (x, t, b, c, d) {
					if ((t/=d) < (1/2.75)) {
						return c*(7.5625*t*t) + b;
					} else if (t < (2/2.75)) {
						return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
					} else if (t < (2.5/2.75)) {
						return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
					} else {
						return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
					}
				},
				easeInOutBounce: function (x, t, b, c, d) {
					if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
					return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
				}
			});

			/*
			 *
			 * TERMS OF USE - EASING EQUATIONS
			 * 
			 * Open source under the BSD License. 
			 * 
			 * Copyright © 2001 Robert Penner
			 * All rights reserved.
			 * 
			 * Redistribution and use in source and binary forms, with or without modification, 
			 * are permitted provided that the following conditions are met:
			 * 
			 * Redistributions of source code must retain the above copyright notice, this list of 
			 * conditions and the following disclaimer.
			 * Redistributions in binary form must reproduce the above copyright notice, this list 
			 * of conditions and the following disclaimer in the documentation and/or other materials 
			 * provided with the distribution.
			 * 
			 * Neither the name of the author nor the names of contributors may be used to endorse 
			 * or promote products derived from this software without specific prior written permission.
			 * 
			 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
			 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
			 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
			 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
			 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
			 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
			 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
			 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
			 * OF THE POSSIBILITY OF SUCH DAMAGE. 
			 *
			 */

		// load dynamic elements
		$(document).ready(function() {
			prepareNav();

			if($('#showcase-content').length){
				//prepareShowcase();
			};
			if($('.home-bd').length){
				prepareBanner();
			};
			if($('#search-form').length){
				prepareProjectSearch();
			};
			if($('#project-list-mask').length){
				//prepareProjectListShowcase();
			};
			if($('#country-tabs').length){
				prepareContact();
			};
			if($('.banner-bd').length){
				prepareInnerBanner();
			};
			if($('#tertiary').length){
				perpareTertiary();
			};
			if($('#timeline-nav').length){
				initTimeline();
			};
			if($('#widget-membrane').length){
				initWidgetMembrane();
			};
			if($('#widget-components').length){
				initWidgetComponents();
			};
			if($('#widget-insulation').length){
				initWidgetInsulation();
			};
			if($('#widget-aluminum').length){
				initWidgetAluminum();
			};
			if($('#clientsidevalidation-webform-client-form-160-errors').length){
				$('#clientsidevalidation-webform-client-form-160-errors').prepend('<h3>! Please correct the following errors...</h3>');
				var messageSent = $.getUrlVar('success');
				if (messageSent) {
					$('#contact-us-header-content h1').html('<span class="orange">Submission Sent!</span>');
					$('#contact-us-header-content .field-type-text-with-summary .field-items .field-item').html('<p class="orange">Thank you for your interest in Sprung. We will reply to your request shortly.</p>');
				}
			}
			//if($('#project-list-mask.scroll-off').length){
			//	$('.showcase-control').css('display','none');
			//};
			if($('.tooltip-OFF').length){
				$("#a1").tooltip({tip: '#toolbox1', effect: 'slide', position: 'center tight', relative: 'true', offset: [10, 10]});
				$("#a2").tooltip({tip: '#toolbox2', effect: 'slide', position: 'center right', relative: 'true', offset: [10, 10]});
				$("#a3").tooltip({tip: '#toolbox3', effect: 'slide', position: 'center right', relative: 'true', offset: [10, 10]});
				$("#a4").tooltip({tip: '#toolbox4', effect: 'slide', position: 'center right', relative: 'true', offset: [10, 10]});
				$("#a5").tooltip({tip: '#toolbox5', effect: 'slide', position: 'center right', relative: 'true', offset: [10, 10]});
				$("#a6").tooltip({tip: '#toolbox6', effect: 'slide', position: 'center right', relative: 'true', offset: [10, 10]});
				$("#a7").tooltip({tip: '#toolbox7', effect: 'slide', position: 'center right', relative: 'true', offset: [10, 10]});
				$("#a8").tooltip({tip: '#toolbox8', effect: 'slide', position: 'center right', relative: 'true', offset: [10, 10]});
				$("#a9").tooltip({tip: '#toolbox9', effect: 'slide', position: 'center right', relative: 'true', offset: [10, 10]});
				$("#a10").tooltip({tip: '#toolbox10', effect: 'slide', position: 'center right', relative: 'true', offset: [10, 10]});
			}
			$('#lofslidecontent45').lofJSidernews( {interval:4000,
												   direction:'opacity',
												   duration:1000,
												   easing:'easeInOutSine'} );
												   
			$(".colorbox-video a").colorbox({width:"840", height:"560",opacity:0, iframe:true });
		});
		
})(jQuery);



;
var sprung_clear_form_element, sprung_reload_form_element;

(function ($) {
	
	sprung_reload_form_element = function(form_item){
		
		//sprung_clear_form_element('field_country', 'Need or Sector');
		
		// form_item value
		var needs_val = $("#field_needs").val();
		var sector_val = $("#field_sector").val();
		var country_val = $("#field_country").val();
		
		//var new_val = $("#"+form_item).val();
		if (form_item == 'field_needs'){
		
			sprung_ajaxify_form_item('sector', needs_val, sector_val, country_val, 1);
			sprung_ajaxify_form_item('country', needs_val, sector_val, country_val, 2);
		
		}else if (form_item == 'field_sector') {
			
			sprung_ajaxify_form_item('needs', needs_val, sector_val, country_val, 0);
			sprung_ajaxify_form_item('country', needs_val, sector_val, country_val, 2);
		
		}else {
			
			sprung_ajaxify_form_item('needs', needs_val, sector_val, country_val, 0);
			sprung_ajaxify_form_item('sector', needs_val, sector_val, country_val, 1);
			
		}
		//alert('reloaded via ajax!!!');
	};
	
	
	sprung_ajaxify_form_item = function(form_item, needs_val, sector_val, country_val, index){
		
		$.ajax({
			url: '/ajax/sprung-form-field-update',
			type: 'get',
			data: ({'field_needs':needs_val,'field_sector':sector_val,'field_country':country_val,'index':index}),
			dataType: 'json',
			success: function(data) {
			$.each(data, function(messageIndex, message) {
				if (messageIndex == 1){
					$("#field_"+form_item).html(message['data']);
				}
			});
			}
		});
	};		
			
	sprung_clear_form_element = function(form_item, previous_select){
		
		//alert('clearing '+form_item);
		$("#"+form_item).html('<option value="all">choose '+previous_select+' first</option>');

	};
	
})(jQuery);;
/*
VideoJS - HTML5 Video Player
v2.0.2

This file is part of VideoJS. Copyright 2010 Zencoder, Inc.

VideoJS is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

VideoJS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with VideoJS.  If not, see <http://www.gnu.org/licenses/>.
*/

// Self-executing function to prevent global vars and help with minification
(function(window, undefined){
  var document = window.document;

// Using jresig's Class implementation http://ejohn.org/blog/simple-javascript-inheritance/
(function(){var initializing=false, fnTest=/xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; this.JRClass = function(){}; JRClass.extend = function(prop) { var _super = this.prototype; initializing = true; var prototype = new this(); initializing = false; for (var name in prop) { prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn){ return function() { var tmp = this._super; this._super = _super[name]; var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } function JRClass() { if ( !initializing && this.init ) this.init.apply(this, arguments); } JRClass.prototype = prototype; JRClass.constructor = JRClass; JRClass.extend = arguments.callee; return JRClass;};})();

// Video JS Player Class
var VideoJS = JRClass.extend({

  // Initialize the player for the supplied video tag element
  // element: video tag
  init: function(element, setOptions){

    // Allow an ID string or an element
    if (typeof element == 'string') {
      this.video = document.getElementById(element);
    } else {
      this.video = element;
    }
    // Store reference to player on the video element.
    // So you can acess the player later: document.getElementById("video_id").player.play();
    this.video.player = this;
    this.values = {}; // Cache video values.
    this.elements = {}; // Store refs to controls elements.

    // Default Options
    this.options = {
      autoplay: false,
      preload: true,
      useBuiltInControls: false, // Use the browser's controls (iPhone)
      controlsBelow: false, // Display control bar below video vs. in front of
      controlsAtStart: false, // Make controls visible when page loads
      controlsHiding: true, // Hide controls when not over the video
      defaultVolume: 0.85, // Will be overridden by localStorage volume if available
      playerFallbackOrder: ["html5", "flash", "links"], // Players and order to use them
      flashPlayer: "htmlObject",
      flashPlayerVersion: false // Required flash version for fallback
    };
    // Override default options with global options
    if (typeof VideoJS.options == "object") { _V_.merge(this.options, VideoJS.options); }
    // Override default & global options with options specific to this player
    if (typeof setOptions == "object") { _V_.merge(this.options, setOptions); }
    // Override preload & autoplay with video attributes
    if (this.getPreloadAttribute() !== undefined) { this.options.preload = this.getPreloadAttribute(); }
    if (this.getAutoplayAttribute() !== undefined) { this.options.autoplay = this.getAutoplayAttribute(); }

    // Store reference to embed code pieces
    this.box = this.video.parentNode;
    this.linksFallback = this.getLinksFallback();
    this.hideLinksFallback(); // Will be shown again if "links" player is used

    // Loop through the player names list in options, "html5" etc.
    // For each player name, initialize the player with that name under VideoJS.players
    // If the player successfully initializes, we're done
    // If not, try the next player in the list
    this.each(this.options.playerFallbackOrder, function(playerType){
      if (this[playerType+"Supported"]()) { // Check if player type is supported
        this[playerType+"Init"](); // Initialize player type
        return true; // Stop looping though players
      }
    });

    // Start Global Listeners - API doesn't exist before now
    this.activateElement(this, "player");
    this.activateElement(this.box, "box");
  },
  /* Behaviors
  ================================================================================ */
  behaviors: {},
  newBehavior: function(name, activate, functions){
    this.behaviors[name] = activate;
    this.extend(functions);
  },
  activateElement: function(element, behavior){
    // Allow passing and ID string
    if (typeof element == "string") { element = document.getElementById(element); }
    this.behaviors[behavior].call(this, element);
  },
  /* Errors/Warnings
  ================================================================================ */
  errors: [], // Array to track errors
  warnings: [],
  warning: function(warning){
    this.warnings.push(warning);
    this.log(warning);
  },
  /* History of errors/events (not quite there yet)
  ================================================================================ */
  history: [],
  log: function(event){
    if (!event) { return; }
    if (typeof event == "string") { event = { type: event }; }
    if (event.type) { this.history.push(event.type); }
    if (this.history.length >= 50) { this.history.shift(); }
    try { console.log(event.type); } catch(e) { try { opera.postError(event.type); } catch(e){} }
  },
  /* Local Storage
  ================================================================================ */
  setLocalStorage: function(key, value){
    if (!localStorage) { return; }
    try {
      localStorage[key] = value;
    } catch(e) {
      if (e.code == 22 || e.code == 1014) { // Webkit == 22 / Firefox == 1014
        this.warning(VideoJS.warnings.localStorageFull);
      }
    }
  },
  /* Helpers
  ================================================================================ */
  getPreloadAttribute: function(){
    if (typeof this.video.hasAttribute == "function" && this.video.hasAttribute("preload")) {
      var preload = this.video.getAttribute("preload");
      // Only included the attribute, thinking it was boolean
      if (preload === "" || preload === "true") { return "auto"; }
      if (preload === "false") { return "none"; }
      return preload;
    }
  },
  getAutoplayAttribute: function(){
    if (typeof this.video.hasAttribute == "function" && this.video.hasAttribute("autoplay")) {
      var autoplay = this.video.getAttribute("autoplay");
      if (autoplay === "false") { return false; }
      return true;
    }
  },
  // Calculates amoutn of buffer is full
  bufferedPercent: function(){ return (this.duration()) ? this.buffered()[1] / this.duration() : 0; },
  // Each that maintains player as context
  // Break if true is returned
  each: function(arr, fn){
    if (!arr || arr.length === 0) { return; }
    for (var i=0,j=arr.length; i<j; i++) {
      if (fn.call(this, arr[i], i)) { break; }
    }
  },
  extend: function(obj){
    for (var attrname in obj) {
      if (obj.hasOwnProperty(attrname)) { this[attrname]=obj[attrname]; }
    }
  }
});
VideoJS.player = VideoJS.prototype;

////////////////////////////////////////////////////////////////////////////////
// Player Types
////////////////////////////////////////////////////////////////////////////////

/* Flash Object Fallback (Player Type)
================================================================================ */
VideoJS.player.extend({
  flashSupported: function(){
    if (!this.flashElement) { this.flashElement = this.getFlashElement(); }
    // Check if object exists & Flash Player version is supported
    if (this.flashElement && this.flashPlayerVersionSupported()) {
      return true;
    } else {
      return false;
    }
  },
  flashInit: function(){
    this.replaceWithFlash();
    this.element = this.flashElement;
    this.video.src = ""; // Stop video from downloading if HTML5 is still supported
    var flashPlayerType = VideoJS.flashPlayers[this.options.flashPlayer];
    this.extend(VideoJS.flashPlayers[this.options.flashPlayer].api);
    (flashPlayerType.init.context(this))();
  },
  // Get Flash Fallback object element from Embed Code
  getFlashElement: function(){
    var children = this.video.children;
    for (var i=0,j=children.length; i<j; i++) {
      if (children[i].className == "vjs-flash-fallback") {
        return children[i];
      }
    }
  },
  // Used to force a browser to fall back when it's an HTML5 browser but there's no supported sources
  replaceWithFlash: function(){
    // this.flashElement = this.video.removeChild(this.flashElement);
    if (this.flashElement) {
      this.box.insertBefore(this.flashElement, this.video);
      this.video.style.display = "none"; // Removing it was breaking later players
    }
  },
  // Check if browser can use this flash player
  flashPlayerVersionSupported: function(){
    var playerVersion = (this.options.flashPlayerVersion) ? this.options.flashPlayerVersion : VideoJS.flashPlayers[this.options.flashPlayer].flashPlayerVersion;
    return VideoJS.getFlashVersion() >= playerVersion;
  }
});
VideoJS.flashPlayers = {};
VideoJS.flashPlayers.htmlObject = {
  flashPlayerVersion: 9,
  init: function() { return true; },
  api: { // No video API available with HTML Object embed method
    width: function(width){
      if (width !== undefined) {
        this.element.width = width;
        this.box.style.width = width+"px";
        this.triggerResizeListeners();
        return this;
      }
      return this.element.width;
    },
    height: function(height){
      if (height !== undefined) {
        this.element.height = height;
        this.box.style.height = height+"px";
        this.triggerResizeListeners();
        return this;
      }
      return this.element.height;
    }
  }
};


/* Download Links Fallback (Player Type)
================================================================================ */
VideoJS.player.extend({
  linksSupported: function(){ return true; },
  linksInit: function(){
    this.showLinksFallback();
    this.element = this.video;
  },
  // Get the download links block element
  getLinksFallback: function(){ return this.box.getElementsByTagName("P")[0]; },
  // Hide no-video download paragraph
  hideLinksFallback: function(){
    if (this.linksFallback) { this.linksFallback.style.display = "none"; }
  },
  // Hide no-video download paragraph
  showLinksFallback: function(){
    if (this.linksFallback) { this.linksFallback.style.display = "block"; }
  }
});

////////////////////////////////////////////////////////////////////////////////
// Class Methods
// Functions that don't apply to individual videos.
////////////////////////////////////////////////////////////////////////////////

// Combine Objects - Use "safe" to protect from overwriting existing items
VideoJS.merge = function(obj1, obj2, safe){
  for (var attrname in obj2){
    if (obj2.hasOwnProperty(attrname) && (!safe || !obj1.hasOwnProperty(attrname))) { obj1[attrname]=obj2[attrname]; }
  }
  return obj1;
};
VideoJS.extend = function(obj){ this.merge(this, obj, true); };

VideoJS.extend({
  // Add VideoJS to all video tags with the video-js class when the DOM is ready
  setupAllWhenReady: function(options){
    // Options is stored globally, and added ot any new player on init
    VideoJS.options = options;
    VideoJS.DOMReady(VideoJS.setup);
  },

  // Run the supplied function when the DOM is ready
  DOMReady: function(fn){
    VideoJS.addToDOMReady(fn);
  },

  // Set up a specific video or array of video elements
  // "video" can be:
  //    false, undefined, or "All": set up all videos with the video-js class
  //    A video tag ID or video tag element: set up one video and return one player
  //    An array of video tag elements/IDs: set up each and return an array of players
  setup: function(videos, options){
    var returnSingular = false,
    playerList = [],
    videoElement;

    // If videos is undefined or "All", set up all videos with the video-js class
    if (!videos || videos == "All") {
      videos = VideoJS.getVideoJSTags();
    // If videos is not an array, add to an array
    } else if (typeof videos != 'object' || videos.nodeType == 1) {
      videos = [videos];
      returnSingular = true;
    }

    // Loop through videos and create players for them
    for (var i=0; i<videos.length; i++) {
      if (typeof videos[i] == 'string') {
        videoElement = document.getElementById(videos[i]);
      } else { // assume DOM object
        videoElement = videos[i];
      }
      playerList.push(new VideoJS(videoElement, options));
    }

    // Return one or all depending on what was passed in
    return (returnSingular) ? playerList[0] : playerList;
  },

  // Find video tags with the video-js class
  getVideoJSTags: function() {
    var videoTags = document.getElementsByTagName("video"),
    videoJSTags = [], videoTag;

    for (var i=0,j=videoTags.length; i<j; i++) {
      videoTag = videoTags[i];
      if (videoTag.className.indexOf("video-js") != -1) {
        videoJSTags.push(videoTag);
      }
    }
    return videoJSTags;
  },

  // Check if the browser supports video.
  browserSupportsVideo: function() {
    if (typeof VideoJS.videoSupport != "undefined") { return VideoJS.videoSupport; }
    VideoJS.videoSupport = !!document.createElement('video').canPlayType;
    return VideoJS.videoSupport;
  },

  getFlashVersion: function(){
    // Cache Version
    if (typeof VideoJS.flashVersion != "undefined") { return VideoJS.flashVersion; }
    var version = 0, desc;
    if (typeof navigator.plugins != "undefined" && typeof navigator.plugins["Shockwave Flash"] == "object") {
      desc = navigator.plugins["Shockwave Flash"].description;
      if (desc && !(typeof navigator.mimeTypes != "undefined" && navigator.mimeTypes["application/x-shockwave-flash"] && !navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin)) {
        version = parseInt(desc.match(/^.*\s+([^\s]+)\.[^\s]+\s+[^\s]+$/)[1], 10);
      }
    } else if (typeof window.ActiveXObject != "undefined") {
      try {
        var testObject = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
        if (testObject) {
          version = parseInt(testObject.GetVariable("$version").match(/^[^\s]+\s(\d+)/)[1], 10);
        }
      }
      catch(e) {}
    }
    VideoJS.flashVersion = version;
    return VideoJS.flashVersion;
  },

  // Browser & Device Checks
  isIE: function(){ return !+"\v1"; },
  isIPad: function(){ return navigator.userAgent.match(/iPad/i) !== null; },
  isIPhone: function(){ return navigator.userAgent.match(/iPhone/i) !== null; },
  isIOS: function(){ return VideoJS.isIPhone() || VideoJS.isIPad(); },
  iOSVersion: function() {
    var match = navigator.userAgent.match(/OS (\d+)_/i);
    if (match && match[1]) { return match[1]; }
  },
  isAndroid: function(){ return navigator.userAgent.match(/Android/i) !== null; },
  androidVersion: function() {
    var match = navigator.userAgent.match(/Android (\d+)\./i);
    if (match && match[1]) { return match[1]; }
  },

  warnings: {
    // Safari errors if you call functions on a video that hasn't loaded yet
    videoNotReady: "Video is not ready yet (try playing the video first).",
    // Getting a QUOTA_EXCEEDED_ERR when setting local storage occasionally
    localStorageFull: "Local Storage is Full"
  }
});

// Shim to make Video tag valid in IE
if(VideoJS.isIE()) { document.createElement("video"); }

// Expose to global
window.VideoJS = window._V_ = VideoJS;

/* HTML5 Player Type
================================================================================ */
VideoJS.player.extend({
  html5Supported: function(){
    if (VideoJS.browserSupportsVideo() && this.canPlaySource()) {
      return true;
    } else {
      return false;
    }
  },
  html5Init: function(){
    this.element = this.video;

    this.fixPreloading(); // Support old browsers that used autobuffer
    this.supportProgressEvents(); // Support browsers that don't use 'buffered'

    // Set to stored volume OR 85%
    this.volume((localStorage && localStorage.volume) || this.options.defaultVolume);

    // Update interface for device needs
    if (VideoJS.isIOS()) {
      this.options.useBuiltInControls = true;
      this.iOSInterface();
    } else if (VideoJS.isAndroid()) {
      this.options.useBuiltInControls = true;
      this.androidInterface();
    }

    // Add VideoJS Controls
    if (!this.options.useBuiltInControls) {
      this.video.controls = false;

      if (this.options.controlsBelow) { _V_.addClass(this.box, "vjs-controls-below"); }

      // Make a click on th video act as a play button
      this.activateElement(this.video, "playToggle");

      // Build Interface
      this.buildStylesCheckDiv(); // Used to check if style are loaded
      this.buildAndActivatePoster();
      this.buildBigPlayButton();
      this.buildAndActivateSpinner();
      this.buildAndActivateControlBar();
      this.loadInterface(); // Show everything once styles are loaded
      this.getSubtitles();
    }
  },
  /* Source Managemet
  ================================================================================ */
  canPlaySource: function(){
    // Cache Result
    if (this.canPlaySourceResult) { return this.canPlaySourceResult; }
    // Loop through sources and check if any can play
    var children = this.video.children;
    for (var i=0,j=children.length; i<j; i++) {
      if (children[i].tagName.toUpperCase() == "SOURCE") {
        var canPlay = this.video.canPlayType(children[i].type) || this.canPlayExt(children[i].src);
        if (canPlay == "probably" || canPlay == "maybe") {
          this.firstPlayableSource = children[i];
          this.canPlaySourceResult = true;
          return true;
        }
      }
    }
    this.canPlaySourceResult = false;
    return false;
  },
  // Check if the extention is compatible, for when type won't work
  canPlayExt: function(src){
    if (!src) { return ""; }
    var match = src.match(/\.([^\.]+)$/);
    if (match && match[1]) {
      var ext = match[1].toLowerCase();
      // Android canPlayType doesn't work
      if (VideoJS.isAndroid()) {
        if (ext == "mp4" || ext == "m4v") { return "maybe"; }
      // Allow Apple HTTP Streaming for iOS
      } else if (VideoJS.isIOS()) {
        if (ext == "m3u8") { return "maybe"; }
      }
    }
    return "";
  },
  // Force the video source - Helps fix loading bugs in a handful of devices, like the iPad/iPhone poster bug
  // And iPad/iPhone javascript include location bug. And Android type attribute bug
  forceTheSource: function(){
    this.video.src = this.firstPlayableSource.src; // From canPlaySource()
    this.video.load();
  },
  /* Device Fixes
  ================================================================================ */
  // Support older browsers that used "autobuffer"
  fixPreloading: function(){
    if (typeof this.video.hasAttribute == "function" && this.video.hasAttribute("preload") && this.video.preload != "none") {
      this.video.autobuffer = true; // Was a boolean
    } else {
      this.video.autobuffer = false;
      this.video.preload = "none";
    }
  },

  // Listen for Video Load Progress (currently does not if html file is local)
  // Buffered does't work in all browsers, so watching progress as well
  supportProgressEvents: function(e){
    _V_.addListener(this.video, 'progress', this.playerOnVideoProgress.context(this));
  },
  playerOnVideoProgress: function(event){
    this.setBufferedFromProgress(event);
  },
  setBufferedFromProgress: function(event){ // HTML5 Only
    if(event.total > 0) {
      var newBufferEnd = (event.loaded / event.total) * this.duration();
      if (newBufferEnd > this.values.bufferEnd) { this.values.bufferEnd = newBufferEnd; }
    }
  },

  iOSInterface: function(){
    if(VideoJS.iOSVersion() < 4) { this.forceTheSource(); } // Fix loading issues
    if(VideoJS.isIPad()) { // iPad could work with controlsBelow
      this.buildAndActivateSpinner(); // Spinner still works well on iPad, since iPad doesn't have one
    }
  },

  // Fix android specific quirks
  // Use built-in controls, but add the big play button, since android doesn't have one.
  androidInterface: function(){
    this.forceTheSource(); // Fix loading issues
    _V_.addListener(this.video, "click", function(){ this.play(); }); // Required to play
    this.buildBigPlayButton(); // But don't activate the normal way. Pause doesn't work right on android.
    _V_.addListener(this.bigPlayButton, "click", function(){ this.play(); }.context(this));
    this.positionBox();
    this.showBigPlayButtons();
  },
  /* Wait for styles (TODO: move to _V_)
  ================================================================================ */
  loadInterface: function(){
    if(!this.stylesHaveLoaded()) {
      // Don't want to create an endless loop either.
      if (!this.positionRetries) { this.positionRetries = 1; }
      if (this.positionRetries++ < 100) {
        setTimeout(this.loadInterface.context(this),10);
        return;
      }
    }
    this.hideStylesCheckDiv();
    this.showPoster();
    if (this.video.paused !== false) { this.showBigPlayButtons(); }
    if (this.options.controlsAtStart) { this.showControlBars(); }
    this.positionAll();
  },
  /* Control Bar
  ================================================================================ */
  buildAndActivateControlBar: function(){
    /* Creating this HTML
      <div class="vjs-controls">
        <div class="vjs-play-control">
          <span></span>
        </div>
        <div class="vjs-progress-control">
          <div class="vjs-progress-holder">
            <div class="vjs-load-progress"></div>
            <div class="vjs-play-progress"></div>
          </div>
        </div>
        <div class="vjs-time-control">
          <span class="vjs-current-time-display">00:00</span><span> / </span><span class="vjs-duration-display">00:00</span>
        </div>
        <div class="vjs-volume-control">
          <div>
            <span></span><span></span><span></span><span></span><span></span><span></span>
          </div>
        </div>
        <div class="vjs-fullscreen-control">
          <div>
            <span></span><span></span><span></span><span></span>
          </div>
        </div>
      </div>
    */

    // Create a div to hold the different controls
    this.controls = _V_.createElement("div", { className: "vjs-controls" });
    // Add the controls to the video's container
    this.box.appendChild(this.controls);
    this.activateElement(this.controls, "controlBar");
    this.activateElement(this.controls, "mouseOverVideoReporter");

    // Build the play control
    this.playControl = _V_.createElement("div", { className: "vjs-play-control", innerHTML: "<span></span>" });
    this.controls.appendChild(this.playControl);
    this.activateElement(this.playControl, "playToggle");

    // Build the progress control
    this.progressControl = _V_.createElement("div", { className: "vjs-progress-control" });
    this.controls.appendChild(this.progressControl);

    // Create a holder for the progress bars
    this.progressHolder = _V_.createElement("div", { className: "vjs-progress-holder" });
    this.progressControl.appendChild(this.progressHolder);
    this.activateElement(this.progressHolder, "currentTimeScrubber");

    // Create the loading progress display
    this.loadProgressBar = _V_.createElement("div", { className: "vjs-load-progress" });
    this.progressHolder.appendChild(this.loadProgressBar);
    this.activateElement(this.loadProgressBar, "loadProgressBar");

    // Create the playing progress display
    this.playProgressBar = _V_.createElement("div", { className: "vjs-play-progress" });
    this.progressHolder.appendChild(this.playProgressBar);
    this.activateElement(this.playProgressBar, "playProgressBar");

    // Create the progress time display (00:00 / 00:00)
    this.timeControl = _V_.createElement("div", { className: "vjs-time-control" });
    this.controls.appendChild(this.timeControl);

    // Create the current play time display
    this.currentTimeDisplay = _V_.createElement("span", { className: "vjs-current-time-display", innerHTML: "00:00" });
    this.timeControl.appendChild(this.currentTimeDisplay);
    this.activateElement(this.currentTimeDisplay, "currentTimeDisplay");

    // Add time separator
    this.timeSeparator = _V_.createElement("span", { innerHTML: " / " });
    this.timeControl.appendChild(this.timeSeparator);

    // Create the total duration display
    this.durationDisplay = _V_.createElement("span", { className: "vjs-duration-display", innerHTML: "00:00" });
    this.timeControl.appendChild(this.durationDisplay);
    this.activateElement(this.durationDisplay, "durationDisplay");

    // Create the volumne control
    this.volumeControl = _V_.createElement("div", {
      className: "vjs-volume-control",
      innerHTML: "<div><span></span><span></span><span></span><span></span><span></span><span></span></div>"
    });
    this.controls.appendChild(this.volumeControl);
    this.activateElement(this.volumeControl, "volumeScrubber");

    this.volumeDisplay = this.volumeControl.children[0];
    this.activateElement(this.volumeDisplay, "volumeDisplay");

    // Crete the fullscreen control
    this.fullscreenControl = _V_.createElement("div", {
      className: "vjs-fullscreen-control",
      innerHTML: "<div><span></span><span></span><span></span><span></span></div>"
    });
    this.controls.appendChild(this.fullscreenControl);
    this.activateElement(this.fullscreenControl, "fullscreenToggle");
  },
  /* Poster Image
  ================================================================================ */
  buildAndActivatePoster: function(){
    this.updatePosterSource();
    if (this.video.poster) {
      this.poster = document.createElement("img");
      // Add poster to video box
      this.box.appendChild(this.poster);

      // Add poster image data
      this.poster.src = this.video.poster;
      // Add poster styles
      this.poster.className = "vjs-poster";
      this.activateElement(this.poster, "poster");
    } else {
      this.poster = false;
    }
  },
  /* Big Play Button
  ================================================================================ */
  buildBigPlayButton: function(){
    /* Creating this HTML
      <div class="vjs-big-play-button"><span></span></div>
    */
    this.bigPlayButton = _V_.createElement("div", {
      className: "vjs-big-play-button",
      innerHTML: "<span></span>"
    });
    this.box.appendChild(this.bigPlayButton);
    this.activateElement(this.bigPlayButton, "bigPlayButton");
  },
  /* Spinner (Loading)
  ================================================================================ */
  buildAndActivateSpinner: function(){
    this.spinner = _V_.createElement("div", {
      className: "vjs-spinner",
      innerHTML: "<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>"
    });
    this.box.appendChild(this.spinner);
    this.activateElement(this.spinner, "spinner");
  },
  /* Styles Check - Check if styles are loaded (move ot _V_)
  ================================================================================ */
  // Sometimes the CSS styles haven't been applied to the controls yet
  // when we're trying to calculate the height and position them correctly.
  // This causes a flicker where the controls are out of place.
  buildStylesCheckDiv: function(){
    this.stylesCheckDiv = _V_.createElement("div", { className: "vjs-styles-check" });
    this.stylesCheckDiv.style.position = "absolute";
    this.box.appendChild(this.stylesCheckDiv);
  },
  hideStylesCheckDiv: function(){ this.stylesCheckDiv.style.display = "none"; },
  stylesHaveLoaded: function(){
    if (this.stylesCheckDiv.offsetHeight != 5) {
       return false;
    } else {
      return true;
    }
  },
  /* VideoJS Box - Holds all elements
  ================================================================================ */
  positionAll: function(){
    this.positionBox();
    this.positionControlBars();
    this.positionPoster();
  },
  positionBox: function(){
    // Set width based on fullscreen or not.
    if (this.videoIsFullScreen) {
      this.box.style.width = "";
      this.element.style.height="";
      if (this.options.controlsBelow) {
        this.box.style.height = "";
        this.element.style.height = (this.box.offsetHeight - this.controls.offsetHeight) + "px";
      }
    } else {
      this.box.style.width = this.width() + "px";
      this.element.style.height=this.height()+"px";
      if (this.options.controlsBelow) {
        this.element.style.height = "";
        // this.box.style.height = this.video.offsetHeight + this.controls.offsetHeight + "px";
      }
    }
  },
  /* Subtitles
  ================================================================================ */
  getSubtitles: function(){
    var tracks = this.video.getElementsByTagName("TRACK");
    for (var i=0,j=tracks.length; i<j; i++) {
      if (tracks[i].getAttribute("kind") == "subtitles" && tracks[i].getAttribute("src")) {
        this.subtitlesSource = tracks[i].getAttribute("src");
        this.loadSubtitles();
        this.buildSubtitles();
      }
    }
  },
  loadSubtitles: function() { _V_.get(this.subtitlesSource, this.parseSubtitles.context(this)); },
  parseSubtitles: function(subText) {
    var lines = subText.split("\n"),
        line = "",
        subtitle, time, text;
    this.subtitles = [];
    this.currentSubtitle = false;
    this.lastSubtitleIndex = 0;

    for (var i=0; i<lines.length; i++) {
      line = _V_.trim(lines[i]); // Trim whitespace and linebreaks
      if (line) { // Loop until a line with content

        // First line - Number
        subtitle = {
          id: line, // Subtitle Number
          index: this.subtitles.length // Position in Array
        };

        // Second line - Time
        line = _V_.trim(lines[++i]);
        time = line.split(" --> ");
        subtitle.start = this.parseSubtitleTime(time[0]);
        subtitle.end = this.parseSubtitleTime(time[1]);

        // Additional lines - Subtitle Text
        text = [];
        for (var j=i; j<lines.length; j++) { // Loop until a blank line or end of lines
          line = _V_.trim(lines[++i]);
          if (!line) { break; }
          text.push(line);
        }
        subtitle.text = text.join('<br/>');

        // Add this subtitle
        this.subtitles.push(subtitle);
      }
    }
  },

  parseSubtitleTime: function(timeText) {
    var parts = timeText.split(':'),
        time = 0;
    // hours => seconds
    time += parseFloat(parts[0])*60*60;
    // minutes => seconds
    time += parseFloat(parts[1])*60;
    // get seconds
    var seconds = parts[2].split(/\.|,/); // Either . or ,
    time += parseFloat(seconds[0]);
    // add miliseconds
    ms = parseFloat(seconds[1]);
    if (ms) { time += ms/1000; }
    return time;
  },

  buildSubtitles: function(){
    /* Creating this HTML
      <div class="vjs-subtitles"></div>
    */
    this.subtitlesDisplay = _V_.createElement("div", { className: 'vjs-subtitles' });
    this.box.appendChild(this.subtitlesDisplay);
    this.activateElement(this.subtitlesDisplay, "subtitlesDisplay");
  },

  /* Player API - Translate functionality from player to video
  ================================================================================ */
  addVideoListener: function(type, fn){ _V_.addListener(this.video, type, fn.rEvtContext(this)); },

  play: function(){
    this.video.play();
    return this;
  },
  onPlay: function(fn){ this.addVideoListener("play", fn); return this; },

  pause: function(){
    this.video.pause();
    return this;
  },
  onPause: function(fn){ this.addVideoListener("pause", fn); return this; },
  paused: function() { return this.video.paused; },

  currentTime: function(seconds){
    if (seconds !== undefined) {
      try { this.video.currentTime = seconds; }
      catch(e) { this.warning(VideoJS.warnings.videoNotReady); }
      this.values.currentTime = seconds;
      return this;
    }
    return this.video.currentTime;
  },
  onCurrentTimeUpdate: function(fn){
    this.currentTimeListeners.push(fn);
  },

  duration: function(){
    return this.video.duration;
  },

  buffered: function(){
    // Storing values allows them be overridden by setBufferedFromProgress
    if (this.values.bufferStart === undefined) {
      this.values.bufferStart = 0;
      this.values.bufferEnd = 0;
    }
    if (this.video.buffered && this.video.buffered.length > 0) {
      var newEnd = this.video.buffered.end(0);
      if (newEnd > this.values.bufferEnd) { this.values.bufferEnd = newEnd; }
    }
    return [this.values.bufferStart, this.values.bufferEnd];
  },

  volume: function(percentAsDecimal){
    if (percentAsDecimal !== undefined) {
      // Force value to between 0 and 1
      this.values.volume = Math.max(0, Math.min(1, parseFloat(percentAsDecimal)));
      this.video.volume = this.values.volume;
      this.setLocalStorage("volume", this.values.volume);
      return this;
    }
    if (this.values.volume) { return this.values.volume; }
    return this.video.volume;
  },
  onVolumeChange: function(fn){ _V_.addListener(this.video, 'volumechange', fn.rEvtContext(this)); },

  width: function(width){
    if (width !== undefined) {
      this.video.width = width; // Not using style so it can be overridden on fullscreen.
      this.box.style.width = width+"px";
      this.triggerResizeListeners();
      return this;
    }
    return this.video.offsetWidth;
  },
  height: function(height){
    if (height !== undefined) {
      this.video.height = height;
      this.box.style.height = height+"px";
      this.triggerResizeListeners();
      return this;
    }
    return this.video.offsetHeight;
  },

  supportsFullScreen: function(){
    if(typeof this.video.webkitEnterFullScreen == 'function') {
      // Seems to be broken in Chromium/Chrome
      if (!navigator.userAgent.match("Chrome") && !navigator.userAgent.match("Mac OS X 10.5")) {
        return true;
      }
    }
    return false;
  },

  html5EnterNativeFullScreen: function(){
    try {
      this.video.webkitEnterFullScreen();
    } catch (e) {
      if (e.code == 11) { this.warning(VideoJS.warnings.videoNotReady); }
    }
    return this;
  },

  // Turn on fullscreen (window) mode
  // Real fullscreen isn't available in browsers quite yet.
  enterFullScreen: function(){
    if (this.supportsFullScreen()) {
      this.html5EnterNativeFullScreen();
    } else {
      this.enterFullWindow();
    }
  },

  exitFullScreen: function(){
    if (this.supportsFullScreen()) {
      // Shouldn't be called
    } else {
      this.exitFullWindow();
    }
  },

  enterFullWindow: function(){
    this.videoIsFullScreen = true;
    // Storing original doc overflow value to return to when fullscreen is off
    this.docOrigOverflow = document.documentElement.style.overflow;
    // Add listener for esc key to exit fullscreen
    _V_.addListener(document, "keydown", this.fullscreenOnEscKey.rEvtContext(this));
    // Add listener for a window resize
    _V_.addListener(window, "resize", this.fullscreenOnWindowResize.rEvtContext(this));
    // Hide any scroll bars
    document.documentElement.style.overflow = 'hidden';
    // Apply fullscreen styles
    _V_.addClass(this.box, "vjs-fullscreen");
    // Resize the box, controller, and poster
    this.positionAll();
  },

  // Turn off fullscreen (window) mode
  exitFullWindow: function(){
    this.videoIsFullScreen = false;
    document.removeEventListener("keydown", this.fullscreenOnEscKey, false);
    window.removeEventListener("resize", this.fullscreenOnWindowResize, false);
    // Unhide scroll bars.
    document.documentElement.style.overflow = this.docOrigOverflow;
    // Remove fullscreen styles
    _V_.removeClass(this.box, "vjs-fullscreen");
    // Resize the box, controller, and poster to original sizes
    this.positionAll();
  },

  onError: function(fn){ this.addVideoListener("error", fn); return this; },
  onEnded: function(fn){
    this.addVideoListener("ended", fn); return this;
  }
});

////////////////////////////////////////////////////////////////////////////////
// Element Behaviors
// Tell elements how to act or react
////////////////////////////////////////////////////////////////////////////////

/* Player Behaviors - How VideoJS reacts to what the video is doing.
================================================================================ */
VideoJS.player.newBehavior("player", function(player){
    this.onError(this.playerOnVideoError);
    // Listen for when the video is played
    this.onPlay(this.playerOnVideoPlay);
    this.onPlay(this.trackCurrentTime);
    // Listen for when the video is paused
    this.onPause(this.playerOnVideoPause);
    this.onPause(this.stopTrackingCurrentTime);
    // Listen for when the video ends
    this.onEnded(this.playerOnVideoEnded);
    // Set interval for load progress using buffer watching method
    // this.trackCurrentTime();
    this.trackBuffered();
    // Buffer Full
    this.onBufferedUpdate(this.isBufferFull);
  },{
    playerOnVideoError: function(event){
      this.log(event);
      this.log(this.video.error);
    },
    playerOnVideoPlay: function(event){ this.hasPlayed = true; },
    playerOnVideoPause: function(event){},
    playerOnVideoEnded: function(event){
      this.currentTime(0);
      this.pause();
    },

    /* Load Tracking -------------------------------------------------------------- */
    // Buffer watching method for load progress.
    // Used for browsers that don't support the progress event
    trackBuffered: function(){
      this.bufferedInterval = setInterval(this.triggerBufferedListeners.context(this), 500);
    },
    stopTrackingBuffered: function(){ clearInterval(this.bufferedInterval); },
    bufferedListeners: [],
    onBufferedUpdate: function(fn){
      this.bufferedListeners.push(fn);
    },
    triggerBufferedListeners: function(){
      this.isBufferFull();
      this.each(this.bufferedListeners, function(listener){
        (listener.context(this))();
      });
    },
    isBufferFull: function(){
      if (this.bufferedPercent() == 1) { this.stopTrackingBuffered(); }
    },

    /* Time Tracking -------------------------------------------------------------- */
    trackCurrentTime: function(){
      if (this.currentTimeInterval) { clearInterval(this.currentTimeInterval); }
      this.currentTimeInterval = setInterval(this.triggerCurrentTimeListeners.context(this), 100); // 42 = 24 fps
      this.trackingCurrentTime = true;
    },
    // Turn off play progress tracking (when paused or dragging)
    stopTrackingCurrentTime: function(){
      clearInterval(this.currentTimeInterval);
      this.trackingCurrentTime = false;
    },
    currentTimeListeners: [],
    // onCurrentTimeUpdate is in API section now
    triggerCurrentTimeListeners: function(late, newTime){ // FF passes milliseconds late as the first argument
      this.each(this.currentTimeListeners, function(listener){
        (listener.context(this))(newTime || this.currentTime());
      });
    },

    /* Resize Tracking -------------------------------------------------------------- */
    resizeListeners: [],
    onResize: function(fn){
      this.resizeListeners.push(fn);
    },
    // Trigger anywhere the video/box size is changed.
    triggerResizeListeners: function(){
      this.each(this.resizeListeners, function(listener){
        (listener.context(this))();
      });
    }
  }
);
/* Mouse Over Video Reporter Behaviors - i.e. Controls hiding based on mouse location
================================================================================ */
VideoJS.player.newBehavior("mouseOverVideoReporter", function(element){
    // Listen for the mouse move the video. Used to reveal the controller.
    _V_.addListener(element, "mousemove", this.mouseOverVideoReporterOnMouseMove.context(this));
    // Listen for the mouse moving out of the video. Used to hide the controller.
    _V_.addListener(element, "mouseout", this.mouseOverVideoReporterOnMouseOut.context(this));
  },{
    mouseOverVideoReporterOnMouseMove: function(){
      this.showControlBars();
      clearInterval(this.mouseMoveTimeout);
      this.mouseMoveTimeout = setTimeout(this.hideControlBars.context(this), 4000);
    },
    mouseOverVideoReporterOnMouseOut: function(event){
      // Prevent flicker by making sure mouse hasn't left the video
      var parent = event.relatedTarget;
      while (parent && parent !== this.box) {
        parent = parent.parentNode;
      }
      if (parent !== this.box) {
        this.hideControlBars();
      }
    }
  }
);
/* Mouse Over Video Reporter Behaviors - i.e. Controls hiding based on mouse location
================================================================================ */
VideoJS.player.newBehavior("box", function(element){
    this.positionBox();
    _V_.addClass(element, "vjs-paused");
    this.activateElement(element, "mouseOverVideoReporter");
    this.onPlay(this.boxOnVideoPlay);
    this.onPause(this.boxOnVideoPause);
  },{
    boxOnVideoPlay: function(){
      _V_.removeClass(this.box, "vjs-paused");
      _V_.addClass(this.box, "vjs-playing");
    },
    boxOnVideoPause: function(){
      _V_.removeClass(this.box, "vjs-playing");
      _V_.addClass(this.box, "vjs-paused");
    }
  }
);
/* Poster Image Overlay
================================================================================ */
VideoJS.player.newBehavior("poster", function(element){
    this.activateElement(element, "mouseOverVideoReporter");
    this.activateElement(element, "playButton");
    this.onPlay(this.hidePoster);
    this.onEnded(this.showPoster);
    this.onResize(this.positionPoster);
  },{
    showPoster: function(){
      if (!this.poster) { return; }
      this.poster.style.display = "block";
      this.positionPoster();
    },
    positionPoster: function(){
      // Only if the poster is visible
      if (!this.poster || this.poster.style.display == 'none') { return; }
      this.poster.style.height = this.height() + "px"; // Need incase controlsBelow
      this.poster.style.width = this.width() + "px"; // Could probably do 100% of box
    },
    hidePoster: function(){
      if (!this.poster) { return; }
      this.poster.style.display = "none";
    },
    // Update poster source from attribute or fallback image
    // iPad breaks if you include a poster attribute, so this fixes that
    updatePosterSource: function(){
      if (!this.video.poster) {
        var images = this.video.getElementsByTagName("img");
        if (images.length > 0) { this.video.poster = images[0].src; }
      }
    }
  }
);
/* Control Bar Behaviors
================================================================================ */
VideoJS.player.newBehavior("controlBar", function(element){
    if (!this.controlBars) {
      this.controlBars = [];
      this.onResize(this.positionControlBars);
    }
    this.controlBars.push(element);
    _V_.addListener(element, "mousemove", this.onControlBarsMouseMove.context(this));
    _V_.addListener(element, "mouseout", this.onControlBarsMouseOut.context(this));
  },{
    showControlBars: function(){
      if (!this.options.controlsAtStart && !this.hasPlayed) { return; }
      this.each(this.controlBars, function(bar){
        bar.style.display = "block";
      });
    },
    // Place controller relative to the video's position (now just resizing bars)
    positionControlBars: function(){
      this.updatePlayProgressBars();
      this.updateLoadProgressBars();
    },
    hideControlBars: function(){
      if (this.options.controlsHiding && !this.mouseIsOverControls) {
        this.each(this.controlBars, function(bar){
          bar.style.display = "none";
        });
      }
    },
    // Block controls from hiding when mouse is over them.
    onControlBarsMouseMove: function(){ this.mouseIsOverControls = true; },
    onControlBarsMouseOut: function(event){
      this.mouseIsOverControls = false;
    }
  }
);
/* PlayToggle, PlayButton, PauseButton Behaviors
================================================================================ */
// Play Toggle
VideoJS.player.newBehavior("playToggle", function(element){
    if (!this.elements.playToggles) {
      this.elements.playToggles = [];
      this.onPlay(this.playTogglesOnPlay);
      this.onPause(this.playTogglesOnPause);
    }
    this.elements.playToggles.push(element);
    _V_.addListener(element, "click", this.onPlayToggleClick.context(this));
  },{
    onPlayToggleClick: function(event){
      if (this.paused()) {
        this.play();
      } else {
        this.pause();
      }
    },
    playTogglesOnPlay: function(event){
      this.each(this.elements.playToggles, function(toggle){
        _V_.removeClass(toggle, "vjs-paused");
        _V_.addClass(toggle, "vjs-playing");
      });
    },
    playTogglesOnPause: function(event){
      this.each(this.elements.playToggles, function(toggle){
        _V_.removeClass(toggle, "vjs-playing");
        _V_.addClass(toggle, "vjs-paused");
      });
    }
  }
);
// Play
VideoJS.player.newBehavior("playButton", function(element){
    _V_.addListener(element, "click", this.onPlayButtonClick.context(this));
  },{
    onPlayButtonClick: function(event){ this.play(); }
  }
);
// Pause
VideoJS.player.newBehavior("pauseButton", function(element){
    _V_.addListener(element, "click", this.onPauseButtonClick.context(this));
  },{
    onPauseButtonClick: function(event){ this.pause(); }
  }
);
/* Play Progress Bar Behaviors
================================================================================ */
VideoJS.player.newBehavior("playProgressBar", function(element){
    if (!this.playProgressBars) {
      this.playProgressBars = [];
      this.onCurrentTimeUpdate(this.updatePlayProgressBars);
    }
    this.playProgressBars.push(element);
  },{
    // Ajust the play progress bar's width based on the current play time
    updatePlayProgressBars: function(newTime){
      var progress = (newTime !== undefined) ? newTime / this.duration() : this.currentTime() / this.duration();
      if (isNaN(progress)) { progress = 0; }
      this.each(this.playProgressBars, function(bar){
        if (bar.style) { bar.style.width = _V_.round(progress * 100, 2) + "%"; }
      });
    }
  }
);
/* Load Progress Bar Behaviors
================================================================================ */
VideoJS.player.newBehavior("loadProgressBar", function(element){
    if (!this.loadProgressBars) { this.loadProgressBars = []; }
    this.loadProgressBars.push(element);
    this.onBufferedUpdate(this.updateLoadProgressBars);
  },{
    updateLoadProgressBars: function(){
      this.each(this.loadProgressBars, function(bar){
        if (bar.style) { bar.style.width = _V_.round(this.bufferedPercent() * 100, 2) + "%"; }
      });
    }
  }
);

/* Current Time Display Behaviors
================================================================================ */
VideoJS.player.newBehavior("currentTimeDisplay", function(element){
    if (!this.currentTimeDisplays) {
      this.currentTimeDisplays = [];
      this.onCurrentTimeUpdate(this.updateCurrentTimeDisplays);
    }
    this.currentTimeDisplays.push(element);
  },{
    // Update the displayed time (00:00)
    updateCurrentTimeDisplays: function(newTime){
      if (!this.currentTimeDisplays) { return; }
      // Allows for smooth scrubbing, when player can't keep up.
      var time = (newTime) ? newTime : this.currentTime();
      this.each(this.currentTimeDisplays, function(dis){
        dis.innerHTML = _V_.formatTime(time);
      });
    }
  }
);

/* Duration Display Behaviors
================================================================================ */
VideoJS.player.newBehavior("durationDisplay", function(element){
    if (!this.durationDisplays) {
      this.durationDisplays = [];
      this.onCurrentTimeUpdate(this.updateDurationDisplays);
    }
    this.durationDisplays.push(element);
  },{
    updateDurationDisplays: function(){
      if (!this.durationDisplays) { return; }
      this.each(this.durationDisplays, function(dis){
        if (this.duration()) { dis.innerHTML = _V_.formatTime(this.duration()); }
      });
    }
  }
);

/* Current Time Scrubber Behaviors
================================================================================ */
VideoJS.player.newBehavior("currentTimeScrubber", function(element){
    _V_.addListener(element, "mousedown", this.onCurrentTimeScrubberMouseDown.rEvtContext(this));
  },{
    // Adjust the play position when the user drags on the progress bar
    onCurrentTimeScrubberMouseDown: function(event, scrubber){
      event.preventDefault();
      this.currentScrubber = scrubber;

      this.stopTrackingCurrentTime(); // Allows for smooth scrubbing

      this.videoWasPlaying = !this.paused();
      this.pause();

      _V_.blockTextSelection();
      this.setCurrentTimeWithScrubber(event);
      _V_.addListener(document, "mousemove", this.onCurrentTimeScrubberMouseMove.rEvtContext(this));
      _V_.addListener(document, "mouseup", this.onCurrentTimeScrubberMouseUp.rEvtContext(this));
    },
    onCurrentTimeScrubberMouseMove: function(event){ // Removeable
      this.setCurrentTimeWithScrubber(event);
    },
    onCurrentTimeScrubberMouseUp: function(event){ // Removeable
      _V_.unblockTextSelection();
      document.removeEventListener("mousemove", this.onCurrentTimeScrubberMouseMove, false);
      document.removeEventListener("mouseup", this.onCurrentTimeScrubberMouseUp, false);
      if (this.videoWasPlaying) {
        this.play();
        this.trackCurrentTime();
      }
    },
    setCurrentTimeWithScrubber: function(event){
      var newProgress = _V_.getRelativePosition(event.pageX, this.currentScrubber);
      var newTime = newProgress * this.duration();
      this.triggerCurrentTimeListeners(0, newTime); // Allows for smooth scrubbing
      // Don't let video end while scrubbing.
      if (newTime == this.duration()) { newTime = newTime - 0.1; }
      this.currentTime(newTime);
    }
  }
);
/* Volume Display Behaviors
================================================================================ */
VideoJS.player.newBehavior("volumeDisplay", function(element){
    if (!this.volumeDisplays) {
      this.volumeDisplays = [];
      this.onVolumeChange(this.updateVolumeDisplays);
    }
    this.volumeDisplays.push(element);
    this.updateVolumeDisplay(element); // Set the display to the initial volume
  },{
    // Update the volume control display
    // Unique to these default controls. Uses borders to create the look of bars.
    updateVolumeDisplays: function(){
      if (!this.volumeDisplays) { return; }
      this.each(this.volumeDisplays, function(dis){
        this.updateVolumeDisplay(dis);
      });
    },
    updateVolumeDisplay: function(display){
      var volNum = Math.ceil(this.volume() * 6);
      this.each(display.children, function(child, num){
        if (num < volNum) {
          _V_.addClass(child, "vjs-volume-level-on");
        } else {
          _V_.removeClass(child, "vjs-volume-level-on");
        }
      });
    }
  }
);
/* Volume Scrubber Behaviors
================================================================================ */
VideoJS.player.newBehavior("volumeScrubber", function(element){
    _V_.addListener(element, "mousedown", this.onVolumeScrubberMouseDown.rEvtContext(this));
  },{
    // Adjust the volume when the user drags on the volume control
    onVolumeScrubberMouseDown: function(event, scrubber){
      // event.preventDefault();
      _V_.blockTextSelection();
      this.currentScrubber = scrubber;
      this.setVolumeWithScrubber(event);
      _V_.addListener(document, "mousemove", this.onVolumeScrubberMouseMove.rEvtContext(this));
      _V_.addListener(document, "mouseup", this.onVolumeScrubberMouseUp.rEvtContext(this));
    },
    onVolumeScrubberMouseMove: function(event){
      this.setVolumeWithScrubber(event);
    },
    onVolumeScrubberMouseUp: function(event){
      this.setVolumeWithScrubber(event);
      _V_.unblockTextSelection();
      document.removeEventListener("mousemove", this.onVolumeScrubberMouseMove, false);
      document.removeEventListener("mouseup", this.onVolumeScrubberMouseUp, false);
    },
    setVolumeWithScrubber: function(event){
      var newVol = _V_.getRelativePosition(event.pageX, this.currentScrubber);
      this.volume(newVol);
    }
  }
);
/* Fullscreen Toggle Behaviors
================================================================================ */
VideoJS.player.newBehavior("fullscreenToggle", function(element){
    _V_.addListener(element, "click", this.onFullscreenToggleClick.context(this));
  },{
    // When the user clicks on the fullscreen button, update fullscreen setting
    onFullscreenToggleClick: function(event){
      if (!this.videoIsFullScreen) {
        this.enterFullScreen();
      } else {
        this.exitFullScreen();
      }
    },

    fullscreenOnWindowResize: function(event){ // Removeable
      this.positionControlBars();
    },
    // Create listener for esc key while in full screen mode
    fullscreenOnEscKey: function(event){ // Removeable
      if (event.keyCode == 27) {
        this.exitFullScreen();
      }
    }
  }
);
/* Big Play Button Behaviors
================================================================================ */
VideoJS.player.newBehavior("bigPlayButton", function(element){
    if (!this.elements.bigPlayButtons) {
      this.elements.bigPlayButtons = [];
      this.onPlay(this.bigPlayButtonsOnPlay);
      this.onEnded(this.bigPlayButtonsOnEnded);
    }
    this.elements.bigPlayButtons.push(element);
    this.activateElement(element, "playButton");
  },{
    bigPlayButtonsOnPlay: function(event){ this.hideBigPlayButtons(); },
    bigPlayButtonsOnEnded: function(event){ this.showBigPlayButtons(); },
    showBigPlayButtons: function(){
      this.each(this.elements.bigPlayButtons, function(element){
        element.style.display = "block";
      });
    },
    hideBigPlayButtons: function(){
      this.each(this.elements.bigPlayButtons, function(element){
        element.style.display = "none";
      });
    }
  }
);
/* Spinner
================================================================================ */
VideoJS.player.newBehavior("spinner", function(element){
    if (!this.spinners) {
      this.spinners = [];
      _V_.addListener(this.video, "loadeddata", this.spinnersOnVideoLoadedData.context(this));
      _V_.addListener(this.video, "loadstart", this.spinnersOnVideoLoadStart.context(this));
      _V_.addListener(this.video, "seeking", this.spinnersOnVideoSeeking.context(this));
      _V_.addListener(this.video, "seeked", this.spinnersOnVideoSeeked.context(this));
      _V_.addListener(this.video, "canplay", this.spinnersOnVideoCanPlay.context(this));
      _V_.addListener(this.video, "canplaythrough", this.spinnersOnVideoCanPlayThrough.context(this));
      _V_.addListener(this.video, "waiting", this.spinnersOnVideoWaiting.context(this));
      _V_.addListener(this.video, "stalled", this.spinnersOnVideoStalled.context(this));
      _V_.addListener(this.video, "suspend", this.spinnersOnVideoSuspend.context(this));
      _V_.addListener(this.video, "playing", this.spinnersOnVideoPlaying.context(this));
      _V_.addListener(this.video, "timeupdate", this.spinnersOnVideoTimeUpdate.context(this));
    }
    this.spinners.push(element);
  },{
    showSpinners: function(){
      this.each(this.spinners, function(spinner){
        spinner.style.display = "block";
      });
      clearInterval(this.spinnerInterval);
      this.spinnerInterval = setInterval(this.rotateSpinners.context(this), 100);
    },
    hideSpinners: function(){
      this.each(this.spinners, function(spinner){
        spinner.style.display = "none";
      });
      clearInterval(this.spinnerInterval);
    },
    spinnersRotated: 0,
    rotateSpinners: function(){
      this.each(this.spinners, function(spinner){
        // spinner.style.transform =       'scale(0.5) rotate('+this.spinnersRotated+'deg)';
        spinner.style.WebkitTransform = 'scale(0.5) rotate('+this.spinnersRotated+'deg)';
        spinner.style.MozTransform =    'scale(0.5) rotate('+this.spinnersRotated+'deg)';
      });
      if (this.spinnersRotated == 360) { this.spinnersRotated = 0; }
      this.spinnersRotated += 45;
    },
    spinnersOnVideoLoadedData: function(event){ this.hideSpinners(); },
    spinnersOnVideoLoadStart: function(event){ this.showSpinners(); },
    spinnersOnVideoSeeking: function(event){ /* this.showSpinners(); */ },
    spinnersOnVideoSeeked: function(event){ /* this.hideSpinners(); */ },
    spinnersOnVideoCanPlay: function(event){ /* this.hideSpinners(); */ },
    spinnersOnVideoCanPlayThrough: function(event){ this.hideSpinners(); },
    spinnersOnVideoWaiting: function(event){
      // Safari sometimes triggers waiting inappropriately
      // Like after video has played, any you play again.
      this.showSpinners();
    },
    spinnersOnVideoStalled: function(event){},
    spinnersOnVideoSuspend: function(event){},
    spinnersOnVideoPlaying: function(event){ this.hideSpinners(); },
    spinnersOnVideoTimeUpdate: function(event){
      // Safari sometimes calls waiting and doesn't recover
      if(this.spinner.style.display == "block") { this.hideSpinners(); }
    }
  }
);
/* Subtitles
================================================================================ */
VideoJS.player.newBehavior("subtitlesDisplay", function(element){
    if (!this.subtitleDisplays) {
      this.subtitleDisplays = [];
      this.onCurrentTimeUpdate(this.subtitleDisplaysOnVideoTimeUpdate);
      this.onEnded(function() { this.lastSubtitleIndex = 0; }.context(this));
    }
    this.subtitleDisplays.push(element);
  },{
    subtitleDisplaysOnVideoTimeUpdate: function(time){
      // Assuming all subtitles are in order by time, and do not overlap
      if (this.subtitles) {
        // If current subtitle should stay showing, don't do anything. Otherwise, find new subtitle.
        if (!this.currentSubtitle || this.currentSubtitle.start >= time || this.currentSubtitle.end < time) {
          var newSubIndex = false,
              // Loop in reverse if lastSubtitle is after current time (optimization)
              // Meaning the user is scrubbing in reverse or rewinding
              reverse = (this.subtitles[this.lastSubtitleIndex].start > time),
              // If reverse, step back 1 becase we know it's not the lastSubtitle
              i = this.lastSubtitleIndex - (reverse) ? 1 : 0;
          while (true) { // Loop until broken
            if (reverse) { // Looping in reverse
              // Stop if no more, or this subtitle ends before the current time (no earlier subtitles should apply)
              if (i < 0 || this.subtitles[i].end < time) { break; }
              // End is greater than time, so if start is less, show this subtitle
              if (this.subtitles[i].start < time) {
                newSubIndex = i;
                break;
              }
              i--;
            } else { // Looping forward
              // Stop if no more, or this subtitle starts after time (no later subtitles should apply)
              if (i >= this.subtitles.length || this.subtitles[i].start > time) { break; }
              // Start is less than time, so if end is later, show this subtitle
              if (this.subtitles[i].end > time) {
                newSubIndex = i;
                break;
              }
              i++;
            }
          }

          // Set or clear current subtitle
          if (newSubIndex !== false) {
            this.currentSubtitle = this.subtitles[newSubIndex];
            this.lastSubtitleIndex = newSubIndex;
            this.updateSubtitleDisplays(this.currentSubtitle.text);
          } else if (this.currentSubtitle) {
            this.currentSubtitle = false;
            this.updateSubtitleDisplays("");
          }
        }
      }
    },
    updateSubtitleDisplays: function(val){
      this.each(this.subtitleDisplays, function(disp){
        disp.innerHTML = val;
      });
    }
  }
);

////////////////////////////////////////////////////////////////////////////////
// Convenience Functions (mini library)
// Functions not specific to video or VideoJS and could probably be replaced with a library like jQuery
////////////////////////////////////////////////////////////////////////////////

VideoJS.extend({

  addClass: function(element, classToAdd){
    if ((" "+element.className+" ").indexOf(" "+classToAdd+" ") == -1) {
      element.className = element.className === "" ? classToAdd : element.className + " " + classToAdd;
    }
  },
  removeClass: function(element, classToRemove){
    if (element.className.indexOf(classToRemove) == -1) { return; }
    var classNames = element.className.split(/\s+/);
    classNames.splice(classNames.lastIndexOf(classToRemove),1);
    element.className = classNames.join(" ");
  },
  createElement: function(tagName, attributes){
    return this.merge(document.createElement(tagName), attributes);
  },

  // Attempt to block the ability to select text while dragging controls
  blockTextSelection: function(){
    document.body.focus();
    document.onselectstart = function () { return false; };
  },
  // Turn off text selection blocking
  unblockTextSelection: function(){ document.onselectstart = function () { return true; }; },

  // Return seconds as MM:SS
  formatTime: function(secs) {
    var seconds = Math.round(secs);
    var minutes = Math.floor(seconds / 60);
    minutes = (minutes >= 10) ? minutes : "0" + minutes;
    seconds = Math.floor(seconds % 60);
    seconds = (seconds >= 10) ? seconds : "0" + seconds;
    return minutes + ":" + seconds;
  },

  // Return the relative horizonal position of an event as a value from 0-1
  getRelativePosition: function(x, relativeElement){
    return Math.max(0, Math.min(1, (x - this.findPosX(relativeElement)) / relativeElement.offsetWidth));
  },
  // Get an objects position on the page
  findPosX: function(obj) {
    var curleft = obj.offsetLeft;
    while(obj = obj.offsetParent) {
      curleft += obj.offsetLeft;
    }
    return curleft;
  },
  getComputedStyleValue: function(element, style){
    return window.getComputedStyle(element, null).getPropertyValue(style);
  },

  round: function(num, dec) {
    if (!dec) { dec = 0; }
    return Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
  },

  addListener: function(element, type, handler){
    if (element.addEventListener) {
      element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
      element.attachEvent("on"+type, handler);
    }
  },
  removeListener: function(element, type, handler){
    if (element.removeEventListener) {
      element.removeEventListener(type, handler, false);
    } else if (element.attachEvent) {
      element.detachEvent("on"+type, handler);
    }
  },

  get: function(url, onSuccess){
    if (typeof XMLHttpRequest == "undefined") {
      XMLHttpRequest = function () {
        try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
        try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (f) {}
        try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (g) {}
        //Microsoft.XMLHTTP points to Msxml2.XMLHTTP.3.0 and is redundant
        throw new Error("This browser does not support XMLHttpRequest.");
      };
    }
    var request = new XMLHttpRequest();
    request.open("GET",url);
    request.onreadystatechange = function() {
      if (request.readyState == 4 && request.status == 200) {
        onSuccess(request.responseText);
      }
    }.context(this);
    request.send();
  },

  trim: function(string){ return string.toString().replace(/^\s+/, "").replace(/\s+$/, ""); },

  // DOM Ready functionality adapted from jQuery. http://jquery.com/
  bindDOMReady: function(){
    if (document.readyState === "complete") {
      return VideoJS.onDOMReady();
    }
    if (document.addEventListener) {
      document.addEventListener("DOMContentLoaded", VideoJS.DOMContentLoaded, false);
      window.addEventListener("load", VideoJS.onDOMReady, false);
    } else if (document.attachEvent) {
      document.attachEvent("onreadystatechange", VideoJS.DOMContentLoaded);
      window.attachEvent("onload", VideoJS.onDOMReady);
    }
  },

  DOMContentLoaded: function(){
    if (document.addEventListener) {
      document.removeEventListener( "DOMContentLoaded", VideoJS.DOMContentLoaded, false);
      VideoJS.onDOMReady();
    } else if ( document.attachEvent ) {
      if ( document.readyState === "complete" ) {
        document.detachEvent("onreadystatechange", VideoJS.DOMContentLoaded);
        VideoJS.onDOMReady();
      }
    }
  },

  // Functions to be run once the DOM is loaded
  DOMReadyList: [],
  addToDOMReady: function(fn){
    if (VideoJS.DOMIsReady) {
      fn.call(document);
    } else {
      VideoJS.DOMReadyList.push(fn);
    }
  },

  DOMIsReady: false,
  onDOMReady: function(){
    if (VideoJS.DOMIsReady) { return; }
    if (!document.body) { return setTimeout(VideoJS.onDOMReady, 13); }
    VideoJS.DOMIsReady = true;
    if (VideoJS.DOMReadyList) {
      for (var i=0; i<VideoJS.DOMReadyList.length; i++) {
        VideoJS.DOMReadyList[i].call(document);
      }
      VideoJS.DOMReadyList = null;
    }
  }
});
VideoJS.bindDOMReady();

// Allows for binding context to functions
// when using in event listeners and timeouts
Function.prototype.context = function(obj){
  var method = this,
  temp = function(){
    return method.apply(obj, arguments);
  };
  return temp;
};

// Like context, in that it creates a closure
// But insteaad keep "this" intact, and passes the var as the second argument of the function
// Need for event listeners where you need to know what called the event
// Only use with event callbacks
Function.prototype.evtContext = function(obj){
  var method = this,
  temp = function(){
    var origContext = this;
    return method.call(obj, arguments[0], origContext);
  };
  return temp;
};

// Removeable Event listener with Context
// Replaces the original function with a version that has context
// So it can be removed using the original function name.
// In order to work, a version of the function must already exist in the player/prototype
Function.prototype.rEvtContext = function(obj, funcParent){
  if (this.hasContext === true) { return this; }
  if (!funcParent) { funcParent = obj; }
  for (var attrname in funcParent) {
    if (funcParent[attrname] == this) {
      funcParent[attrname] = this.evtContext(obj);
      funcParent[attrname].hasContext = true;
      return funcParent[attrname];
    }
  }
  return this.evtContext(obj);
};

// jQuery Plugin
if (window.jQuery) {
  (function($) {
    $.fn.VideoJS = function(options) {
      this.each(function() {
        VideoJS.setup(this, options);
      });
      return this;
    };
    $.fn.player = function() {
      return this[0].player;
    };
  })(jQuery);
}


// Expose to global
window.VideoJS = window._V_ = VideoJS;

// End self-executing function
})(window);;
/**
 * @license 
 * jQuery Tools @VERSION Scrollable - New wave UI design
 * 
 * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
 * 
 * http://flowplayer.org/tools/scrollable.html
 *
 * Since: March 2008
 * Date: @DATE 
 */
(function($) { 

	// static constructs
	$.tools = $.tools || {version: '@VERSION'};
	
	$.tools.scrollable = {
		
		conf: {	
			activeClass: 'active',
			circular: false,
			clonedClass: 'cloned',
			disabledClass: 'disabled',
			easing: 'swing',
			initialIndex: 0,
			item: '> *',
			items: '.items',
			keyboard: true,
			mousewheel: false,
			next: '.next',   
			prev: '.prev', 
			size: 1,
      itemsPerFrame: 1,
			speed: 400,
			vertical: false,
			touch: true,
			wheelSpeed: 0
		} 
	};
					
	// get hidden element's width or height even though it's hidden
	function dim(el, key) {
		var v = parseInt(el.css(key), 10);
		if (v) { return v; }
		var s = el[0].currentStyle; 
		return s && s.width && parseInt(s.width, 10);	
	}

	function find(root, query) { 
		var el = $(query);
		return el.length < 2 ? el : root.parent().find(query);
	}
	
	var current;		
	
	// constructor
	function Scrollable(root, conf) {   
		
		// current instance
		var self = this, 
			 fire = root.add(self),
			 itemWrap = root.children(),
			 index = 0,
			 vertical = conf.vertical;
				
		if (!current) { current = self; } 
		if (itemWrap.length > 1) { itemWrap = $(conf.items, root); }
		
		
		// in this version circular not supported when size > 1
		if (conf.size > 1) { conf.circular = false; } 
		
		// methods
		$.extend(self, {
				
			getConf: function() {
				return conf;	
			},			
			
			getIndex: function() {
				return index;	
			}, 

			getSize: function() {
				return self.getItems().size();	
			},

			getNaviButtons: function() {
				return prev.add(next);	
			},
			
			getRoot: function() {
				return root;	
			},
			
			getItemWrap: function() {
				return itemWrap;	
			},
			
			getItems: function() {
				return itemWrap.find(conf.item).not("." + conf.clonedClass);	
			},
							
			move: function(offset, time) {
				return self.seekTo(index + offset, time);
			},
			
			next: function(time) {
				return self.move(conf.size, time);	
			},
			
			prev: function(time) {
				return self.move(-conf.size, time);	
			},
			
			begin: function(time) {
				return self.seekTo(0, time);	
			},
			
			end: function(time) {
				return self.seekTo(self.getSize() -1, time);	
			},	
			
			focus: function() {
				current = self;
				return self;
			},
			
			addItem: function(item) {
				item = $(item);
				
				if (!conf.circular)  {
					itemWrap.append(item);
					next.removeClass("disabled");
					
				} else {
					itemWrap.children().last().before(item);
					itemWrap.children().first().replaceWith(item.clone().addClass(conf.clonedClass)); 						
				}
				
				fire.trigger("onAddItem", [item]);
				return self;
			},
			
			
			/* all seeking functions depend on this */		
			seekTo: function(i, time, fn) {	
				
				// ensure numeric index
				if (!i.jquery) { i *= 1; }
				
				// avoid seeking from end clone to the beginning
				if (conf.circular && i === 0 && index == -1 && time !== 0) { return self; }
				
				// check that index is sane				
				if (!conf.circular && i < 0 || i > self.getSize() || i < -1) { return self; }
				
				var item = i;
			
				if (i.jquery) {
					i = self.getItems().index(i);	
					
				} else {
					item = self.getItems().eq(i);
				}  
				
				// onBeforeSeek
				var e = $.Event("onBeforeSeek"); 
				if (!fn) {
					fire.trigger(e, [i, time]);				
					if (e.isDefaultPrevented() || !item.length) { return self; }			
				}
				
				var lefty = item.position().left;
				if (lefty == 223) lefty = 850;
	
				var props = vertical ? {top: -item.position().top} : {left: -lefty};  
				
				index = i;
				current = self;  
				if (time === undefined) { time = conf.speed; }   
				
				itemWrap.animate(props, time, conf.easing, fn || function() { 
					fire.trigger("onSeek", [i]);		
				});	 
				
				return self; 
			}					
			
		});
				
		// callbacks	
		$.each(['onBeforeSeek', 'onSeek', 'onAddItem'], function(i, name) {
				
			// configuration
			if ($.isFunction(conf[name])) { 
				$(self).bind(name, conf[name]); 
			}
			
			self[name] = function(fn) {
				if (fn) { $(self).bind(name, fn); }
				return self;
			};
		});  
		
		// circular loop
		if (conf.circular) {
			
			var cloned1 = self.getItems().slice(-1).clone().prependTo(itemWrap),
				 cloned2 = self.getItems().eq(1).clone().appendTo(itemWrap);
      
      		// add more clones, for no gap
      		self.getItems().slice(2, conf.itemsPerFrame + 1).clone().appendTo(itemWrap).addClass(conf.clonedClass);

			cloned1.add(cloned2).addClass(conf.clonedClass);
			
			self.onBeforeSeek(function(e, i, time) {
				
				if (e.isDefaultPrevented()) { return; }
				
				/*
					1. animate to the clone without event triggering
					2. seek to correct position with 0 speed
				*/
				if (i == -1) {
					self.seekTo(cloned1, time, function()  {
						self.end(0);		
					});          
					return e.preventDefault();
					
				} else if (i == self.getSize()) {
					self.seekTo(cloned2, time, function()  {
						self.begin(0);		
					});	
				}
				
			});

			// seek over the cloned item

			// if the scrollable is hidden the calculations for seekTo position
			// will be incorrect (eg, if the scrollable is inside an overlay).
			// ensure the elements are shown, calculate the correct position,
			// then re-hide the elements. This must be done synchronously to
			// prevent the hidden elements being shown to the user.

			// See: https://github.com/jquerytools/jquerytools/issues#issue/87

			var hidden_parents = root.parents().add(root).filter(function () {
				if ($(this).css('display') === 'none') {
					return true;
				}
			});
			
			if (hidden_parents.length) {
				hidden_parents.show();
				self.seekTo(0, 0, function() {});
				hidden_parents.hide();
			}
			else {
				self.seekTo(0, 0, function() {});
			}
			
		}
		
		// next/prev buttons
		var prev = find(root, conf.prev).click(function(e) { e.stopPropagation(); self.prev(); }),
			 next = find(root, conf.next).click(function(e) { e.stopPropagation(); self.next(); }); 
		
		if (!conf.circular) {
			self.onBeforeSeek(function(e, i) {
				setTimeout(function() {
					if (!e.isDefaultPrevented()) {
						prev.toggleClass(conf.disabledClass, i <= 0);
						next.toggleClass(conf.disabledClass, i >= self.getSize() -1);
					}
				}, 1);
			});
			
			if (!conf.initialIndex) {
				prev.addClass(conf.disabledClass);	
			}			
		}
			
		if (self.getSize() < 2) {
			prev.add(next).addClass(conf.disabledClass);	
		}
			
		// mousewheel support
		if (conf.mousewheel && $.fn.mousewheel) {
			root.mousewheel(function(e, delta)  {
				if (conf.mousewheel) {
					self.move(delta < 0 ? 1 : -1, conf.wheelSpeed || 50);
					return false;
				}
			});			
		}
		
		// touch event
		if (conf.touch) {
			var touch = {};
			
			itemWrap[0].ontouchstart = function(e) {
				var t = e.touches[0];
				touch.x = t.clientX;
				touch.y = t.clientY;
			};
			
			itemWrap[0].ontouchmove = function(e) {
				
				// only deal with one finger
				if (e.touches.length == 1 && !itemWrap.is(":animated")) {			
					var t = e.touches[0],
						 deltaX = touch.x - t.clientX,
						 deltaY = touch.y - t.clientY;
	
					self[vertical && deltaY > 0 || !vertical && deltaX > 0 ? 'next' : 'prev']();				
					e.preventDefault();
				}
			};
		}
		
		if (conf.keyboard)  {
			
			$(document).bind("keydown.scrollable", function(evt) {

				// skip certain conditions
				if (!conf.keyboard || evt.altKey || evt.ctrlKey || evt.metaKey || $(evt.target).is(":input")) { 
					return; 
				}
				
				// does this instance have focus?
				if (conf.keyboard != 'static' && current != self) { return; }
					
				var key = evt.keyCode;
			
				if (vertical && (key == 38 || key == 40)) {
					self.move(key == 38 ? -1 : 1);
					return evt.preventDefault();
				}
				
				if (!vertical && (key == 37 || key == 39)) {					
					self.move(key == 37 ? -1 : 1);
					return evt.preventDefault();
				}	  
				
			});  
		}
		
		// initial index
		if (conf.initialIndex) {
			self.seekTo(conf.initialIndex, 0, function() {});
		}
	} 

		
	// jQuery plugin implementation
	$.fn.scrollable = function(conf) { 
			
		// already constructed --> return API
		var el = this.data("scrollable");
		if (el) { return el; }		 

		conf = $.extend({}, $.tools.scrollable.conf, conf); 
		
		this.each(function() {			
			el = new Scrollable($(this), conf);
			$(this).data("scrollable", el);	
		});
		
		return conf.api ? el: this; 
		
	};
			
	
})(jQuery);;

