/*************************************************************************
 **
 ** GLOBAL DATA
 **
 ************************************************************************/

var gCurrPage           = null;
var gCurrPagePath       = null;
var gPrevPagePath       = null;
var gShowPagesTimeoutID = null;
var gShowPagesStarted   = false;
var gWaitForContent     = false;
var gFragmentRedirects  = true;
var gNormalPageHeight   = 481;
var gUtilPageHeight     = 574;
var gBlockAnimateLinks  = false;
var gAnimatingLink      = false;

/*************************************************************************
 **
 ** BODY.ONLOAD
 **
 ************************************************************************/

$( document ).ready( function () { 

    // if loading a page with a path in the fragment, immediately
    // redirect to the fragment path to resolve "inconsistent" urls like:
    //
    //   http://www.segd.org/about-us/index.html#/news/index.html
    //
    // see also hash-redirector.js, which currently preempts this with even
    // earlier hash-based redirection. this is to prevent a full load of the
    // old page followed by an immediate redirect.

    if (gFragmentRedirects) {
      var fragment = $.history.getCurrent();
      if (fragment && fragment.indexOf('/') == 0) {
          window.location = fragment;
          return true;
      }
    }

    var isIE6 = ($.browser.msie && $.browser.version < 7);
    var ajaxifyUtilityNav = false;
    var jqLogo = $( '.logo' );
    var jqBody = $( 'body' );
    var startMonitoringNow = true;
    var animated_links;

    // If the logo exists, then the homepage was loaded
    if( jqLogo.length > 0 ) {

	// When site first loads, you just see the logo in center of screen
	// If user clicks that logo, then minimize it and show the pages of
	// the site
	$( '.logo a' ).click( function () { 
	    if( !gShowPagesStarted ) 
		showAllPages( 900 );
	    
	    return false;
	} );

	// Once all of the pages are shown, if a page is clicked by the user
	// then expand the page
        animated_links = $( '#pages a');
	
	// Start the intro animation which moves the logo to the center of 
	// the screen
	playIntro( false );

	ajaxifyUtilityNav = true;
        startMonitoringNow = false;
    }
    else if( jqBody[0].id != 'utilityFolder' ) { 
	// if no logo, then this is an inside page

	// Set current page
	gCurrPage = $( '#pages .openFolder' );

        // If there is an open folder, prepare to animate between pages
        if (!gCurrPage.length) gCurrPage = null;
        else window.setTimeout(preparePagesForAnimation, 300);
	
	// Setup page to page animation
        animated_links = $( '#pages h2 a' );
        animated_links = animated_links.add( '#pages ul.nav a' );  // sidenav
        animated_links = animated_links.add( '.mainContent .fast' );

	ajaxifyUtilityNav = true;
    }
    else {
        // This is a utility page

	// Set current page
	gCurrPage = $( '#pages .openFolder' );
	
	// Prepare pages for possible animation
	window.setTimeout(preparePagesForAnimation, 300);

	// Setup page to page animation
	animated_links = $( '#pages h2 a' );

	if( isIE6 ) // If IE6, then remove all links
	    animated_links = animated_links.filter( function () { return false; } );

        // Shop subnav links should not use dynamic hash navigation
	if( !jqBody.hasClass( 'shop' ) )
          animated_links = animated_links.add( '#pages ul.nav a' );

	animated_links = animated_links.add( '.mainContent .fast' );

	ajaxifyUtilityNav = true;
    }

    // Add back to top link
    addBackToTopLink();

    // Animate SEGD logo
    animated_links = animated_links.add( '#masthead #branding h1 a' );

    // Animate/ajaxify utility nav
    if( ajaxifyUtilityNav && !isIE6 ) {
	animated_links = animated_links.add( '#utility a.content' );
    }

    // Animate footer links (but not for ie6 - they're utility folder links)
    if ( !isIE6 )
      animated_links = animated_links.add( '#footer a' );

    // Animate wysiwyg content links
    animated_links = animated_links.add( '.wysiwyg a' );

    // Set up link animation
    animated_links.each( function() { animateLink(this) } );

    // For IE6, use javascript to apply a css class on hover over
    if ( isIE6 )
      hoverizeAll();

    // poll for changes to the url fragment ('#' and stuff beyond).
    // intro page will start monitoring once animation finishes.

    if (startMonitoringNow)
        monitorAddressBar();

    // If there were errors from submitting a form, and they're not visible,
    // scroll the browser there
    var formerrors = $('div.error, dd.error, span.error');

    if (formerrors.length > 0) {
      var pos = formerrors.offset();

      if (pos.top > $(window).height() - 100) {
        pos.top -= 100;
        if (pos.top < 0) pos.top = 0;
        window.scrollTo(pos.left, pos.top);
      }
    }

    // If there is a place for member info, then get it
    var memberInfo = $( '#util .sidenav .memberInfo' );
    if( memberInfo.length > 0 )
    {
	memberInfo.load( '/services/member-info.html' );
    }

    return true;
} ); // ready

function animateLink(clickable) {

    // Do not animate links in preview mode
    if ($('body').hasClass('preview'))
      return;

    // Allow "fast" links for BUTTON or A tags.  If it is a BUTTON tag
    // then it is assumed that that button contains an A tag, which is where
    // the link is grabbed from.  SideNote: We need to put the class="fast" on
    // the BUTTON tag because the A tag's onclick will not execute when the A
    // tag resides within a BUTTON tag and the button is clicked (FF3).
    var tagName = clickable.tagName.toUpperCase();
    var link    = tagName == "BUTTON" ? $( 'a', clickable )[0]
                : tagName == "A"      ? clickable
                :                       null
                ;

    if ( link == null ) 
      return;

    var origin = window.location.protocol + '//' + window.location.host;
    var path;
    var query = '';
    var fragment = '';

    if ( link.href.indexOf(origin) == 0 )
      path = link.href.substr( origin.length );
    else if ( link.href.indexOf("/") == 0 )
      path = link.href;

    // Link must be site-relative or same origin to animate
    if ( path == null ) 
      return;

    // Further uri parsing - separate path, query and fragment
    var i;

    if ( (i = path.indexOf('#')) >= 0 ) {
      fragment = path.substr( i+1 );
      path = path.substr( 0, i );
    }

    if ( (i = path.indexOf('?')) >= 0 ) {
      query = path.substr( i+1 );
      path = path.substr( 0, i );
    }

    // Link with path in fragment, e.g. #/home.html - use fragment as target
    if ( fragment.indexOf('/') == 0 ) {
      path = fragment;
      fragment = '';
    }

    // Site-relative link that's not in sitemap - don't animate.
    // The most common case is an uninitialized ruby link ("/content/").
    if ( siteFolder(path) == null )
      return;

    // Of the shop section pages, only /shop/index.html can be animated to
    if ( path.indexOf('/shop/') == 0 && path != '/shop/' && path != '/shop/index.html' )
      return;

    // Conversely, if we're in the shop section but not /shop/index.html,
    // nothing should animate
    var cpath = currentPagePath();
    if ( cpath.indexOf('/shop/') == 0 && cpath != '/shop/' && cpath != '/shop/index.html' )
      return;

    // Can't animate to members area links from non-ssl pages - members area is requiressl
    if ( path.indexOf('/members-area/') == 0 && window.location.protocol != 'https:' )
      return;

    // Compute file extension
    var parts = path.split('/');
    var last = parts.length > 0 ? parts.pop() : '';
    parts = last.split('.');
    last = parts.length > 0 ? parts.pop() : '';

    // Exclude links with non-.html file extensions from animation
    if ( last != '' && last != 'html')
      return;

    var onclick = pagelinkClicked;

    // If a link references a named anchor on this page, simulate browser scroll.
    // If it references a named anchor on another page, don't animate at all.
    if ( fragment.length > 0 )
      if ( path == cpath )
        onclick = namedAnchorClicked;
      else
        return;

    // If a link is a "back" button, it should simulate a browser back button click
    if ($(clickable).hasClass('back-button'))
      onclick = backlinkClicked;

    $(clickable).unbind( 'click' );
    $(clickable).unbind( 'keypress' );
    $(clickable).click( onclick );
    $(clickable).keypress( onclick );
}

// Simulate a browser back button click

function backlinkClicked() {

    var previous = $.history.getPrevious();

    if (previous == null)
      window.history.go(-1);
    else
      $.history.add(previous);

    return false;
}

// Simulate browser scroll to named anchor

function namedAnchorClicked() {

    // Clicked link must reference named anchor on current page

    var origin = window.location.protocol + '//' + window.location.host;
    var cpath = origin + currentPagePath();
    var href = this.href;

    if (href.indexOf(cpath+'#') != 0)
      return true;

    href = href.substr(cpath.length+1);

    // Find target anchor and scroll there

    var target = $('a[name="' + href + '"]');

    if (target.length > 0) {
      var pos = $(target[0]).offset();
      window.scrollTo(pos.left, pos.top);
    }

    return false;
}

// client-side navigation via url fragment (aka "hash").
// #include jquery.history.js

function pagelinkClicked() {

    // mimic same origin policy to determine whether or not
    // we should do client-side navigation on this link click.

    var origin = window.location.protocol + '//' + window.location.host;

    // Allow "fast" links for BUTTON or A tags.  If it is a BUTTON tag
    // then it is assumed that that button contains an A tag, which is where
    // the link is grabbed from.  SideNote: We need to put the class="fast" on
    // the BUTTON tag because the A tag's onclick will not execute when the A
    // tag resides within a BUTTON tag and the button is clicked (FF3).  Using
    // an A tag within the BUTTON tag is beneficial because it will make 
    // relative links absolute when accessed via the A tag's href attribute
    // (although, not true in IE7)0
    var tagName = this.tagName.toUpperCase();
    var url     = tagName == "BUTTON" ? $( 'a', this )[0].href
                : tagName == "A"      ? this.href
                :                       ""
                ;

    // A tag within BUTTON tag in IE7 will not make links absolute
    if( url.indexOf( '/' ) == 0 ) {
	url = origin + url;
    }

    if (0 == url.indexOf(origin)) {

        if (gBlockAnimateLinks)
          return false;
 
        var url_relative = url.substr(origin.length);

        // HACK: short-circuit animated link if it matches current url -
        // jquery.history will not fire an event otherwise, and gBlockAnimateLinks
        // will end up stuck in the on position

        if (url_relative == $.history.getCurrent())
          return false;

        // block animated links; cleared when transition is finished
        gBlockAnimateLinks = true;

        $.history.add(url_relative);

        // track new location with google analytics
        if (typeof(pageTracker) != 'undefined')
          pageTracker._trackPageview(url_relative);

        return false;
    }

    return true;
}

function monitorAddressBar() {

  // initially, set current page to base uri, ignoring any url fragment.
  // but see [1] below.

  gCurrPagePath = currentBasePath();

  // event: programmatic history changes ($.history.add)

  $(window).historyadd(function(e, currentHash, previousHash) {
    addressBarChanged( previousHash, currentHash );
  });

  // event: browser history changes (back & forward buttons)

  $(window).history(function(e, currentHash, previousHash) {
    addressBarChanged( previousHash, currentHash );
  });

  // [1] initially, if there is a fragment and it doesn't match the
  // base uri path, transition to the page given by the fragment.
  // NOTE: this code only takes effect if gFragmentRedirects is false.

  var hash = $.history.getCurrent();

  if (hash && gCurrPagePath != hash) {
    addressBarChanged( gCurrPagePath, hash );
  }
}

function addressBarChanged( oldPagePath, newPagePath ) {

  if (gAnimatingLink)
    return;

  // If it's a named anchor hash like #foo, the browser has scrolled now.
  // Restore the old hash without firing another event. FIXME: this has
  // the side effect of leaving #foo in the history, preventing browser back.

  if (newPagePath.length > 0 && newPagePath.indexOf('/') < 0) {
    var maskevent = 1;
    $.history.add(gCurrPagePath, maskevent);
    return;
  }

  if (oldPagePath == '' || oldPagePath == '#') {
    oldPagePath = currentBasePath();    
  }

  if (newPagePath == '' || newPagePath == '#') {
    newPagePath = currentBasePath();    
  }

  gPrevPagePath = oldPagePath;
  gCurrPagePath = newPagePath;

  var oldFolder = siteFolder( gPrevPagePath );
  var newFolder = siteFolder( gCurrPagePath );

  gAnimatingLink = true;

  if ($.browser.msie && $.browser.version < 7)
    dehoverizeAll();

  if ( newFolder == 'util' ) {
    showUtilityPage( 1000, gCurrPagePath );
  }
  else if ( newFolder == 'intro' ) {
    showIntro( 1000 );
  }
  else {
    // dynamically transition to regular content page
    $( '#pages #'+newFolder ).each(
      function() {
        showPage( 1000, $( this ), gCurrPagePath );
      }
    );
  }
}

function onAnimationDone() {

  // The gAnimatingLink flag protects us from concurrent link animations
  // triggered by things like the browser back button. While we can suppress
  // the animation itself, we can't prevent browser back from changing the
  // address bar (unlike the case for links). The inconsistent address bar
  // can be reset after the original animation finishes - but when we do
  // this we must avoid firing an event that kicks off another animation.

  var hash = $.history.getCurrent();

  if (hash && gCurrPagePath != hash) {
    var maskevent = 1;
    $.history.add(gCurrPagePath, maskevent);
  }

  if ($.browser.msie && $.browser.version < 7)
    hoverizeAll();

  gBlockAnimateLinks = false;
  gAnimatingLink = false;
}

/*************************************************************************
 **
 ** INTRO ANIMATION
 **
 ************************************************************************/

function playIntro( doAnimation )
{
    // Sleep for a bit before starting animation
    if(  !doAnimation ) {

	// Set height of animation div, so that it seems like boxes come from 
	// just outside the bottom of the window
	var windowHeight   = document.documentElement.clientHeight;
	var topMargin      = 40; // set in div#container within main.css
	var mastheadHeight = $( '#masthead' ).outerHeight() 
	                   + 32 // bottom margin set in div#masthead
	                   ;

	var logo       = $( '.logo' );
	var logoHeight = windowHeight - topMargin - mastheadHeight;
	logo.css( 'height', logoHeight + 'px' );

	// Change the top of the logo letters from 100% to logo height
	// They produce the exact same effect, the letters do not appear on the
	// screen, but the 100% doesn't work right in Safari
	$( '.logo a' ).css( 'top', logoHeight + 'px' );

	window.setTimeout( function() { playIntro( true ) }, 10 );
	return;
    }    

    // Start by animating the G
    animateCSSRule(
	2000,
	[
	    [ $( '.logoG' ), '.centeredLogo a.logoG' ],
	    [ 
		$( '.logoG img' ),
		'.centeredLogo .logoG img',
		null,
		function () { 
		    $( '#branding h2' ).show();
		    if( !gShowPagesStarted ) {
			gShowPagesTimeoutID 
			    = window.setTimeout( function () { showAllPages( 900 ) }, 3000 );
		    }
		}
	    ]
	]
    );

    // Then animate the E
    window.setTimeout( 
	function () {
	    animateCSSRule( 
		1500,
		[
		    [ $( '.logoE' ), '.centeredLogo a.logoE' ],
		    [ $( '.logoE img' ), '.centeredLogo .logoE img' ]
		]
	    );
	},
	500
    );

    // Then animate the D
    window.setTimeout(     
	function () {
	    animateCSSRule( 
		1300,
		[
		    [ $( '.logoD' ), '.centeredLogo a.logoD' ],
		    [ $( '.logoD img' ), '.centeredLogo .logoD img' ]
		]
	    );
	},
	700
    );

    // Then animate the S
    window.setTimeout(
	function () {
	    animateCSSRule( 
		1100,
		[
		    [ $( '.logoS' ), '.centeredLogo a.logoS' ],
		    [ $( '.logoS img' ), '.centeredLogo .logoS img' ]
		]
	    );
	},
	900
    );
    
    return;
} // playIntro

function showAllPages( duration )
{
    gShowPagesStarted = true;
    window.clearTimeout( gShowPagesTimeoutID );
    
    // Get height of logo animation box (factors in browser height)
    var animationHeight = parseInt( $( '.logo' ).css( 'height' ) );

    // Get pages
    var folders    = $( '#pages .folder' );
    var folderImgs = $( '#pages .folder img' );

    // Make pages look like they are very close
    folders.setZoom( '250%' );
    folderImgs.setZoom( '250%' );   
    
    // Center pages
    folders.css( 'left', '250px' );
    
    // Prepare surrouding box for page animation and unhide it
    var folderBox = $( '#pages' );
    folderBox
	.addClass( 'animate' )
	.css( 'height', animationHeight + 'px' )
	.show()
    ;

    // Start the "minimize logo" animation
    minimizeLogo( duration );
    
    /***********************
     * Start page animation
     ***********************/
    
    // Execute the following code when page animation finishes
    var cback = function () { 
	// Reset folder box back to normal
	folderBox
	    .css( 'height', '' )
	    .removeClass( 'animate' )
	;

	// Reset z-index and animation properties on all pages
	folders
	    .css( 'zIndex', '' )
	    .css( 'left', '' )
	    .css( 'top', '' )
	;
	
	// Replace title image with text and background image
	folderImgs.remove();
	folders.removeClass( 'blank' );

	// Show utility nav & footer
	$( '#utility' ).css( 'visibility', 'visible' );
	$( '#footer' ).show();

        var path = window.location.pathname;
        var fragment = $.history.getCurrent();

        // Monitor address bar for changes to url fragment ('#' and beyond).
        // If there's a fragment now, this kicks off a transition to that page.

        monitorAddressBar();

        // The animation finished on the intro page and there was no fragment
        // to transition to, so navigate to #/home.html to record this page
        // layout as a new history entry. Browsing away and then back here
        // will skip the animation.

        if ((path == '/' || path == '/index.html') && fragment == "")
          $.history.add('/home.html');

    } // cback

    // Figure out final coords for each page/folder // TODO: Pull from stylesheet
    var finalCoords = [
	[ '71px', '0px'    ], // top, left
	[ '23px', '157px'  ],
	[ '0px',  '314px', ],
	[ '71px', '472px', ],
	[ '23px', '629px', ],
	[ '0px',  '786px', ]
    ];

    // Loop through each page, in a specific order
    var folderOrder = [ 3, 0, 4, 1, 5, 2 ];
    for( var i = 0; i < folderOrder.length; i++ ) {
	if( i > 0 )
	    cback = null;
	
	// Get page
	var folderNum = folderOrder[i];
	var folder    = folders.eq( folderNum );
	var folderImg = folderImgs.eq( folderNum );

	// Stack page before animating it
	folder
	    .css( 'top', (animationHeight + (i*30)) + 'px' )
	    .css( 'zIndex', i+1 )
	    .animateZoom( 
		'100%',
		duration,
		null,
		cback,
		{
		    top  : finalCoords[folderNum][0],
		    left : finalCoords[folderNum][1]
		}
	    )
	;
	folderImg.animateZoom( '100%' );
    } // for
	
    return false;
} // showAllPages

function minimizeLogo( duration )
{
    var logoBox = $( '.logo' );

    // Intro animation done, so reset logo box height back to default
    logoBox.css( 'height' , '' );

    // Make sure logo knows it's destined to be small
    logoBox.addClass( 'smallLogo' );

    // Replace separate S E G D letters with large image, for a smooth shrinking experience
    logoBox.html('<div class="logo-large"><img src="/images/SEGD-logo-large.png" /></div>');

    // Shrink and move entire logo box
    logoBox.animate( 
	{
	    top    : '-105px',
	    left   : '157px',
	    width  : '85px',
	    height : '76px' 
	},
	duration,
	null,
	function () {
	    // After logo finishes animating, swap logo HTML with logo image
	    $( '#branding h1' ).css( 'visibility', 'visible' );
	    logoBox.hide(); 
	}
    );

    // Shrink large logo to small logo
    $( '.logo img' ).animate(
	{
	    width: '84px',
	    height: '76px'
	},
	duration
    );

    $( '.logo div' ).animate(
	{
	    left: 0
	},
	duration
    );
   
} // minimizeLogo

/*************************************************************************
 **
 ** PAGE ANIMATION
 **
 ** The main function here is "showPage".  This function is called when
 ** a user clicks on a page, or a subnav link within a page.
 **
 ************************************************************************/

function showPage( duration, page, href )
{
    // Showing same page, just loading new content from a subnav link
    if ( siteFolder(gPrevPagePath) == siteFolder(gCurrPagePath) ) {
      return hidePageContent( 
          page, 
          0,
          true,
          function () { getPageContent( href, page ); }
      );
    }

    // Disable page hover and animated links until transition finishes
    togglePageHover( 'Off' );

    // Start the retrieval of the clicked page's content
    getPageContent( href, page );

    // If no current page being displayed
    if( !gCurrPage ) {
	// Then expand clicked page
	expandPage( duration, page );
    }
    // If a utility page is showing
    else if ( siteFolder(gPrevPagePath) == 'util' ) {
	hideUtilityPage( 1000, page );
    }
    // If there is a current page being displayed and its not the clicked page
    else {
	// Swap current page with clicked page
	swapPages( duration, gCurrPage, page );
    }
    
    // Set current page
    gCurrPage = page;

    return false;
} // showPage


// Next important function is showUtilityPage, called when a user clicks
// a link in the utility nav
function showUtilityPage( duration, href, state )
{
    // Default state to 1
    //   State == 1 then hide currently active page
    //   State == 2 then animate main pages and utility page
    //   State == 3 then reset state
    //   State == 4 activate utility nav link and set currpage
    if( state == null )
	state = 1;

    var jqUtil    = $( '#util' );
    var jqFolders = $( '#pages div.folder' );
    var jqContent = $( '#content' );

    if( state == 1 ) {
    
	var bodyId   = $( 'body' )[0].id;
        var openpage = $( '#pages div.openFolder' );

	// If a main page is currently open
	if( bodyId == 'viewFolder' ) {
	    // Get the open page and hide it's content, then advance to 
	    // state == 2
	    hidePageContent( 
		openpage,
		0,
		false,
		function () { showUtilityPage( duration, href, 2 ) }
	    );
	}
	// If a utility page is already showing
	else if( bodyId == 'utilityFolder' ) {
	    // Then hide the utility page's content and show page content
	    hidePageContent(
		openpage,
		0,
		true,
		function () { getPageContent( href, openpage ); }
	    );

	    // Jump to state == 4
	    state = 4;
	}
	// Otherwise, intro pages are showing
	else {
	    // So, hide the news side nav and proceeed to step 2
	    $( 'ul.nav' ).fadeOut( 
		'fast'
		/*function () { 
		    showUtilityPage( duration, href, 2  );
		}*/
	    );

	    state = 2;
	}
    } // if state == 1

    if( state == 2 ) {
	
	// Start the retrieval of the clicked page's content
	getPageContent( href, jqUtil );

	// Animate main pages to left side flank
	for( var folderIdx = 0; folderIdx < jqFolders.length; folderIdx++ )
	{
	    // folderIdx is used to access the page, while folderNum is used
	    // to find the CSS rule to animate to
	    var folderNum = folderIdx;
	    if( folderNum >= 2 )
	    {
		// When viewing a utility page, the utility page is folder2
		// while the main pages are folder0-1 and folder3-6
		folderNum++;
	    }
	    
	    // Get the main page, set it's zindex and animate it
	    var jqFolder = $( '#pages div.folder' + folderIdx );
	    jqFolder.css( 'zIndex', folderIdx );
	    animateCSSRule( 
		duration,
		[ 
		    [ 
			jqFolder,
			'body#utilityFolder div#pages div.folder' + folderNum
		    ]
		]
	    );
	} // for

	// Add closedFolder to the util page, so that it has a correct initial
	// width/height/position
	jqUtil.addClass( 'closedFolder' );

	// Make the util page invisible before showing it
	jqUtil.setZoom( '0%' );
	jqUtil.show();

	// Animate the util page by having it grow to 100% from the center
	// of the screen
	jqUtil
	    .css( 'marginLeft', '518px' )
	    .css( 'top', '287px' )
	;

	animateCSSRule( 
	    duration,
	    [
		[
		    jqContent,
		    'body div#content.withUtilHeight'
		]
	    ]
	);

	jqUtil.animateZoom( 
	    '100%', 
	    duration,
	    null,
	    // After util page finishes animating, call again with state == 3
	    function () { showUtilityPage( duration, href, 3 ) },
	    {
		top : 0,
		marginLeft : '250px'
	    }
	);
    } // IF state == 2
			
    if( state == 3 ) { 

	// Reset zIndex and mark all folders as closed
	jqFolders
	    .css( 'zIndex', '' )
	    .removeClass( 'openFolder' )
	    .addClass( 'closedFolder' )
	    ;

	// Reorder page indexes so that the util page can become folder2
	for( var i = 5; i >= 2; i-- )
	{
	    var jqFolder = $( 'div.folder' + i );
	    jqFolder.removeClass( 'folder' + i );
	    jqFolder.addClass( 'folder' + (i+1) );
	}

	// Make the util page folder2
	jqUtil.addClass( 'folder' );
	jqUtil.addClass( 'folder2' );

	// Show the util page content
	showPageContent( jqUtil );

	state = 4;
    } // if state == 3
    
    if( state == 4 ) {
	// Inactive any currently active utility nav links
	$( '#utility ul li' ).removeClass( 'active' );

	// Activate this utility nav link
	var link = $( "#utility ul li a[href='"+href+"']" );
	link.parent( 'li' ).addClass( 'active' );
	
	// Set current page
	gCurrPage = jqUtil;
    }
    
    return false;
} // showUtilityPage

function showIntro( duration, state )
{
    var bodyId = $( 'body' )[0].id;

    // Do nothing is already showing intro
    if( bodyId == 'folderNav' ) {
        onAnimationDone();
	return false;
    }

    var isUtil = bodyId == 'utilityFolder'; 
    
    // Get page in center
    var jqPage = isUtil ? $( '#util' ) : getPageInCenter();

    // Default state to 1
    //  If state == 1 then hide center page's content
    //  If state == 2 then animate pages back to intro state
    //  If state == 3 then reset page state as if loaded directly
    if( state == null )
	state = 1;

    // Get all folders and, specifically, the news folder
    var jqNews    = $( '#news' );

    if( state == 1  ) // if first time called
    {
	// Hide center page's content
	if( isUtil ) {
	    hideUtilityPage( 
		duration,
		jqPage,
		null,
		function () {
		    collapsePages( duration );
		} 
	    );
	}
	else {
	    hidePageContent( 
		jqPage,
		0,
		false,
		// Call collapsePage again with state == 2 
		// when animation finishes
		function () {
                  collapsePages( duration );
                }
	    );
	}
    } // if state == 1

    return false;
} // showIntro

function hideUtilityPage( duration, jqPage, state, mainPagesAniFunc )
{
    if( state == null )
	state = 0;

    // Get utility page
    var jqUtil    = $( '#util' );
    var jqContent = $( '#content' );

    if( state == 0 ) {
	// Hide utility page's content
	hidePageContent( 
	    jqUtil,
	    0,
	    false,
	    function () {
		hideUtilityPage( duration, jqPage, 1, mainPagesAniFunc );
	    }
	);
    }
    else if( state == 1 ) { // (state == 1)
	
	// Reset page indexes back to normal
	for( var i = 0; i < 6; i++ ) {
	    var idx = i;
	    if( i >= 2 )
		idx++;
	    
	    setPageIndex( $( '.folder' + idx ), i );
	}
	
	$( 'body' )[0].id = 'viewFolder'; // TODO: Keep here?

	jqUtil.removeClass( 'folder2' );
	
	animateCSSRule( 
	    duration,
	    [ 
		[ jqContent, 'body.siteSection div#content.withNormalHeight' ]
	    ]
	);
	
	// Expand clicked page
	if( mainPagesAniFunc ) {
	    mainPagesAniFunc();
	} else {
	    expandPage( duration, jqPage );
	}
	
	// Animate the util page by having it shrink to 0% into the center
	// of the screen
	jqUtil.css( 'zIndex', 1 ); // TODO: Do we need?
	jqUtil.animateZoom( 
	    '0%',
	    duration,
	    null,
	    function () { 
		hideUtilityPage( duration, jqPage, 2, mainPagesAniFunc )
	    },
	    {
		top        : '287px',
		marginLeft : '518px'
	    }
	);

    } // else (state == 1 )
    else if( state == 2 ) {
	// Remove active status from utility nav link
	$( '#utility ul li' ).removeClass( 'active' );

	// Remove any member info html
	$( '.memberInfo', jqUtil ).html( '' );
	
	// Reset jqUtil back to normal state
	jqUtil
	    .removeClass( 'folder' )
	    .removeClass( 'folder2' )
	    .css( 'zIndex', '' )
	    .hide()
	;
    }

    return false;
} // hideUtilityPage

function getClickedPage( jqLink )
{
    return jqLink.parents( '.folder' );
} // getClickedPage

function isPageInCenter( jqPage )
{
    return jqPage.hasClass( 'folder2' ) ? true : false;
} // isPageInCenter

function arePagesEqual( jqPage1, jqPage2 )
{
    return jqPage1[0].id == jqPage2[0].id ? true : false;
} // arePagesEqual

function getPageInCenter()
{
//    var idx    = $( 'body' )[0].id == 'utilityFolder' ? 2 : 3;
    var idx = 2;
    var jqPage = $( 'div.folder' + idx );
    
    return jqPage;
} // getPageInCenter

function getPageURL( link )
{
    var noScheme = link.replace( /^https?:\/\//, '' );
    var pieces   = noScheme.split( '/' );
    pieces.shift();

    var path = '/' + pieces.join( '/' );
    
    return path;
} // getPageURL

function preparePageForContent( jqPage )
{
    // Get content div
    var pageContentDiv = $( '.mainContent', jqPage );

    // Create content div if it doesn't exist
    if( pageContentDiv.length == 0 ) {
	var newDiv = document.createElement( 'DIV' );
	newDiv.className = 'mainContent pageContent';
	newDiv.style.display = 'none';
	
	// Also create BR used to clear the float
	var newClear = document.createElement( 'BR' );
	newClear.style.clear = 'both';
	
	// Add them to the end of the page
	jqPage[0].appendChild( newDiv );	
	jqPage[0].appendChild( newClear );	
	
	pageContentDiv = $( '.mainContent', jqPage );
    }

    // Get sidenav UL
    var sidenavUL = $( '.sidenav ul.nav', jqPage );
    
    // Create sidenav URL if it doesn't exist
    if( sidenavUL.length == 0 ) {
	var newUL = document.createElement( 'UL' );
	newUL.className     = 'nav';
	newUL.style.display = 'none';

	$( '.sidenav', jqPage )[0].appendChild( newUL );
	
	sidenavUL = $( '.sidenav ul.nav', jqPage );
    }

    // Get sponser paragraph
    var sponsorPara = $( '.sidenav p.sponsor' );
    
    // Create sponsor p tag if it doesn't exist
    if( sponsorPara.length == 0 ) {
	var newPara = document.createElement( 'P' );
	newPara.className     = 'sponsor';
	newPara.style.display = 'none';

	$( '.sidenav h2' ).after( newPara );

	sponsorPara = newPara;
    }
 
    return {
	content : pageContentDiv,
	sidenav : sidenavUL,
	sponsor : sponsorPara
    };
} // preparePageForContent

function getPageContent( link, jqPage, cback )
{
    var path = getPageURL( link );
    path     = path.replace( /\.html(\?.*)?$/, '.xml$1' );
    
    preparePageForContent( jqPage );

    var successCallback = cback;

    if( successCallback ==  null ) 
	successCallback = function (html) { 
	    showPageContent( jqPage, { 'html' : html } );
	}

    $.ajax( {
	url      : "/services/content" + path,
	type     : 'GET',
	error    : function (res) { return getPageContent('/error.html', jqPage, cback) },
	success  : successCallback
    } );

    return true;
} // getPageContent



// get the current effective uri path -
// a path in the fragment overrides any uri path component.

function currentPagePath()
{
    var path = currentFragmentPath();
    
    if (path != null)
        return path;

    return currentBasePath();
}


// get the absolute path component from the current url

function currentBasePath() {
    var loc = window.location;

    // extract uri path component + query string

    if (loc.search.length > 0)
        return loc.pathname + loc.search;

    return loc.pathname;
}


// get fragment component ('#' and beyond) from the current url

function currentFragmentPath() {
    var fragment = window.location.hash;

    if (fragment.indexOf('#') == 0)
        fragment = fragment.substr(1);

    if (fragment.length > 0)
        return fragment;
    
    return null;
}

function siteFolder(path)
{
    var folder;

    parts = path.split('/');

    if (parts.length >= 2) {

        var sitemap = {
            '': 'intro',
            'home.html': 'intro',
            'about-us': 'about',
            'conference': 'conf',
            'news' : 'news',
            'design-awards': 'awards',
            'learning': 'learn',
            'publications': 'pub',
            'members-area': 'util',
            'join-renew': 'util',
            'job-banks': 'util',
            'referrals': 'util',
            'contact-us': 'util',
            'email-updates': 'util',
            'shop': 'util',
            'accessibility.html': 'util',
            'sitemap.html': 'util',
	    'search-results': 'util'
        };

        folder = sitemap[parts[1]];
    }

    return folder;
}

function expandPage( duration, jqPage, state )
{
    // Get page in center
    var jqPageInCenter = getPageInCenter();
    
    // Expand center page if page not passed in
    if( !jqPage )
	jqPage = jqPageInCenter;

    // Default state to 1
    //   State == 1 hide news sidenav
    //   State == 2 animate clicked page and other pages
    //   State == 3 show page content
    if( state == null )
	state = 1;

    // Handle state == 1
    if( state == 1 ) {

	var newsSidenav          = $( '#news ul.nav' );
	var newsSidenavIsShowing = newsSidenav.length > 0;
	
        // If news page was not clicked and its sidenav is showing
	if( jqPage[0].id != 'news' && newsSidenavIsShowing ) {
	    // Then hide news sidenav (shown by default)
	    newsSidenav.fadeOut( 
		'fast',
		function () {
		    // After news finishes, call again with state == 2
		    expandPage( duration, jqPage, 2 )
		}
	    );
	
	    return false;
	}
	// If news page was clicked and its sidenav is showing
	else if( newsSidenavIsShowing ) {
	    // Then set width of sidenav to help things out a bit
	    newsSidenav.css( 'width', '112px' );
	    
	    // And go right to state == 2
	    state = 2
	}
	// If news sidenav not showing
	else {
	    // Then go right to state == 2
	    state = 2;
	}
    } // if state == 1
    
    if( state == 2 ) {
	
	// Figure out if we are expanding the center page or not
	var isExpandingCenterPage = jqPageInCenter[0].id == jqPage[0].id;

	// Make sure all pages have either closed/open status
	$( '.folder' ).each( 
	    function () {
		var jqElem = $( this );
		if( !jqElem.hasClass( 'openFolder' )
		    && !jqElem.hasClass( 'closedFolder' )
		    && jqElem[0].id != jqPage[0].id ) {
		    jqElem.addClass( 'closedFolder' )
		}
	    }
	);

	// Swap zindex now on clicked page & center page
	if( !isExpandingCenterPage ) {
	    var clickedPageIdx = getPageIndex( jqPage );
	    
	    setPageIndex( jqPage, getPageIndex( jqPageInCenter ) );
	    setPageIndex( jqPageInCenter, clickedPageIdx );
	}

	// Expand page
	animateCSSRule( 
	    duration,
	    [ 
		[ 
		    jqPage,
		    'body.siteSection div#content div.openFolderWithHeight',
		    null,
		    function () {
			// After animation finishes, call again with state == 3
			expandPage( duration, jqPage, 3 )
		    }
		]
	    ]
	);

	// Stack pages to the side of the page 
	// (remember clicked & center page indexes have been swapped)
	for( var i = 0; i < 6; i++ ) {

	    // Get page
	    var sidePage = $( '#pages div.folder' + i );

	    // Skip the clicked page
	    if( sidePage.length == 0 || sidePage[0].id == jqPage[0].id )
		continue;
	
	    // Animate side page
	    var cssRule = 'body#viewFolder div.folder' + i;
	    animateCSSRule( duration, [ [ sidePage, cssRule ] ] );
	} // for each page
    } // state == 2

    if( state == 3 ) { // if animation has finished

	// Show content for expanded page
	return showPageContent( jqPage )

    } // state == 3

    return false;
} // expandPage

function collapsePages( duration, state, params )
{
    if( state == null )
	state = 1;

    var jqFolders = $( '#pages .folder' );
    var jqNews    = $( '#news' );

    if( state == 1 ) // if center page's content finished hiding
    {
	// Retrieve sidenav content for news page
	getPageContent( 
	    $( '.sidenav h2 a', jqNews )[0].href,
	    jqNews,
	    function (html) {
		collapsePages( duration, 3, { 'html' : html } )
	    }
	);

	// Loop through each page
	for( var folderNum = 0; folderNum < 6; folderNum++ ) {
	    // Get page and determine css rule to animate it with
	    var folder   = jqFolders.eq( folderNum );
	    var folderId = folder[0].id;
	    var cssRule  = 'body#folderNav div#content div#' + folderId;

	    // Set zindex
	    setPageIndex( folder, folderNum );

	    // Animate page back to intro state
	    animateCSSRule( 
		duration,
		[
		    [ 
			folder,
			cssRule,
			null, 
			// Call again with state == 3 to reset page state
			folderNum == 0 ? function () { 
			                     collapsePages( duration, 2 )
			                 } 
			:                null
		    ]
		]
	    );
	} // for each folder

	return;
    } // if state == 1
    else if( state == 2 ) {
	// Reset body tag back to intro state
	var jqBody = $( 'body' );
	jqBody[0].id = 'folderNav';
	jqBody.removeClass( 'siteSection' );
	
	// News folder is neither open nor closed in the intro state
	jqNews.removeClass( 'closedFolder' );

	// News folder's sidenav is showing during intro state
	$( '.sidenav ul.nav', jqNews ).fadeIn( 'fast' );
	//showPageContent( jqNews, 'reset' ); // reset countdown

	// Reset all animation parameters for all folders
	jqFolders
	    .css( 'top', '' )
	    .css( 'left', '' )
	    .css( 'width', '' )
	    .css( 'height', '' )
	    .css( 'position', '' )
	    ;
	
	// When in intro state, there is no active page
	gCurrPage = null;
    } // if state == 2
    else if( state == 3 ) {
	// Grab sidenav HTML from params
	var jqHTML = $( params.html );

	// Create temporary div to hold new sidenav
	var tmpDiv = $( document.createElement( 'DIV' ) );
	tmpDiv.html( $( '#sidenav', jqHTML ).text() );

	// Set sidenav html and show sidenav
	var jqNewsSidenav = $( 'ul.nav', jqNews );
	jqNewsSidenav.html( $( 'ul.nav', tmpDiv ).html() );

        // Animate links in news sidenav
        $( 'a', jqNewsSidenav ).each(function() { animateLink(this) });

        // Back to /home.html animation - set document title
        document.title = 'SEGD';

        // Intro animation is done
        onAnimationDone();
    }
    
    return;
} // collapsePages

function swapPages( duration, jqPage1, jqPage2, state )
{
    if( state == null ) 
	state = 0;
    
    if( state == 0 ) {
	// Hide content
	hidePageContent( 
	    jqPage1,
	    0,
	    false,
	    function () { swapPages( duration, jqPage1, jqPage2, 1 ) }
	);
    }
    else {
	// Temporarily set the background position
	$( '.sidenav h2 em', jqPage2 ).addClass( 'highlight' );

	// Swap indexes
	var page2Idx = getPageIndex( jqPage2 );
	setPageIndex( jqPage1, page2Idx );
	setPageIndex( jqPage2, 2 );

	// Prepare to show content on clicked page
	var showContent = function () { return showPageContent( jqPage2 ) };
	animateCSSRule( 
	    duration,
	    [
		[ 
		    jqPage1,
		    'body#viewFolder div.folder' + page2Idx,
		    null,
		    // We need the line below, other wise the progress bar
		    // div extends 300px off the page
		    function () { $( '.progressBar', jqPage1 ).hide() }
		],
		[ 
		    jqPage2, 
		    'body.siteSection div#content div.openFolderWithHeight',
		    null,
		    showContent
		]
	    ]
	);
    } // ( state == 1 )

    return false;
} // swapPages

function showPageContent( jqPage, state )
{
    // When a page is clicked showPageContent gets called trice, but the
    // order of what executes when is not gauranteed:
    //   * When ajax finishes loading the page data
    //   * When all of the page animation finishes
    //   * When the progress bar appears
    // We use a countdown to ensure that the page's content is only 
    // shown on the third call to this function
    if( typeof jqPage[0].showContentCountDown == 'undefined'
	|| jqPage[0].showContentCountDown == 0 )
	jqPage[0].showContentCountDown = 3;

    // If no state was passed in, then showPageContent was called after the 
    // the page animation has finished
    if( !state ) {
	// Decrease countdown
	jqPage[0].showContentCountDown--;

	// Change how CSS is applied so that content displays correctly
	$( 'body' )[0].id = jqPage[0].id == 'util' ? 'utilityFolder' 
	                  :                          'viewFolder'
	                  ;
	$( 'body' ).addClass( 'siteSection' );
	jqPage.removeClass( 'closedFolder' );

	// When the page was animating, it was positioned absolutely, relying 
	// on css left and top;  Lets reset it back to relative positioning
	// with no left or top set (all defined in the openFolder class)
	// This will allow the automatic and correct layout of the foooter
	jqPage.css( 'position', "" );
	jqPage.css( 'top', "" );
	jqPage.css( 'left', "" );
	jqPage.css( 'height', gNormalPageHeight + 'px' ); // Why do we need?  Isn't height defined in the CSS or is just min-height?
	jqPage.addClass( 'openFolder' );

	// openFolder contains 24px of right padding, so we need to decrease
	// the width by 24 px
	jqPage.css( 'width', (parseInt(jqPage.css('width')) - 24) + 'px' );

	// Reset outer content height, now that this page isn't absoultely positioned
	// it will push down the footer
	$( '#content' ).css( 'height', '' );

	// Show progress bar (progress animation)
	toggleProgressBar( 'show', jqPage );
    }
    else if( typeof state == "object" ) {
	// If state was passed in and its an object, then showPageContent was
	// called after the page content finished loading via Ajax; the object
	// within state contains the page HTML via state.html
	
	// Decrease countdown
	jqPage[0].showContentCountDown--;
	
	// Setup jquery objects
	var jqHTML    = $( state.html );
	var jqContent = $( '.mainContent', jqPage );
	var jqSidenav = $( 'ul.nav', jqPage );
	var jqSponsor = $( '.sidenav p.sponsor', jqPage );
	
	// Create temporary div to hold new sidenav
	var tmpDiv = $( document.createElement( 'DIV' ) );
	tmpDiv.html( $( '#sidenav', jqHTML ).text() );

	// Set page content & sidenav from passed in html
	jqContent.html( $( '#content', jqHTML ).text() );
	jqSidenav.html( $( 'ul.nav', tmpDiv ).html() || '' );
	jqSponsor.html( $( '#sponsor', jqHTML ).text() );

	document.title = $( '#title', jqHTML ).text();
	
	// Change section title image if supplied
	var jqSectionTitleHTML = $( '#section-title', jqHTML );
	if( jqSectionTitleHTML.length == 1 ) {
	    $( '.sidenav h2', jqPage ).html( jqSectionTitleHTML.text() );
	}

	// Change template class in body tag
	updateBodyTemplateClass( $( '#template', jqHTML ).text() );

	// Get select content links to load via ajax
	// Get sidenav links to load content via ajax
        $( 'a', jqContent ).each(function() { animateLink(this) });
        $( 'button.fast', jqContent ).each(function() { animateLink(this) });
        $( 'a', jqSidenav ).each(function() { animateLink(this) });

        // Update utility nav link css classes: highlight current page's
        // utility link, unhighlight all others
        var section = '';
        var parts = gCurrPagePath.split('/');
        if (parts.length >= 2)
          section = parts[1];

        $( 'div#utility li' ).each(function() {
          if ($(this).attr('id') == 'util-'+section)
            $(this).addClass('active');
          else
            $(this).removeClass('active');
        });

	// Handle any other dynamic situations with the new content
	new Join();
	new Renew();
	
    } // ( state is an object )
    else if( state == 1 ) {
	// If state was passed in and equals "1", then showPageContent was 
	// called after the progress bar appeared

	// Decrease countdown
	jqPage[0].showContentCountDown--;
    } // ( state == 1 )
    else if( state == -1 ) {
	// Special case when state is -1.  This means showPageContent was called
	// when the user clicked a link in the side nav and the page content
	// has been hidden.

	// We'll want to decrease the count down twice, because
	// showPageContent is only called twice when a sidenav link is clicked
	jqPage[0].showContentCountDown -= 2;
    } // ( state == -1 )

    // If countdown is down to zero, then we can finally show the content
    if( jqPage[0].showContentCountDown == 0 ) {
	// Reset the background position for the title
	$( '.sidenav h2 em', jqPage ).removeClass( 'highlight' );

	// Setup jquery objects	
	var jqContent = $( '.mainContent', jqPage );
	var jqSidenav = $( 'ul.nav', jqPage );
	var jqSponsor = $( '.sidenav p.sponsor', jqPage );

	// Set the width of the sidenav, so that we can calculate 
	// the appropriate outsideHeight
	jqSidenav.css( 'width', '112px' );
	
	// Animate the page to the height of its content
	var contentHeight = jqContent.outerHeight();
	var sidenavHeight = jqSidenav.outerHeight() + 85;

	// Reset the sidenav with to auto
	jqSidenav.css( 'width', '' );

	var newHeight = contentHeight > sidenavHeight ? contentHeight
	              :                                 sidenavHeight
	              ;

	var body = $( 'body' );
	
	var minHeight = gNormalPageHeight;
	if( body[0].id == 'utilityFolder' || body.hasClass( 'tmp-award' ) ) {
	    minHeight = gUtilPageHeight;
	}

	if( newHeight < minHeight ) {
	    newHeight = minHeight;
	}

	if( newHeight > (minHeight*2) ) {
	    addBackToTopLink( $( '#pages .openFolder' ) );
	    newHeight = jqContent.outerHeight();	    
	}
	
	jqPage.animate( 
	    { height : newHeight + 'px' },
	    800, // define seconds
	    null,
	    function () {
		togglePageHover( 'Standby', jqPage );
		if( !$( 'body' ).hasClass( 'tmp-awards_list' ) )
		    $( 'a.toTop' ).show();
	    }
	);

	// Show subnav
	$( 'ul.nav', jqPage ).fadeIn( 'fast' ); // define seconds?
	$( '.sidenav p.sponsor', jqPage ).fadeIn( 'fast' );

	// Hide progress bar, while showing content
	toggleProgressBar( 'hide', jqPage );

    } // ( countdown == 0 )

    return false;
} // showPageContent

function toggleProgressBar( mode, jqPage )
{
    // Get progress bar 
    var jqProgress = $( '.progressBar', jqPage );

    var progressHTML = '<div class="loading"></div>'; //<img src="/images/loading-page.gif" width="32" height="32" alt="loading..." style="margin: 230px auto 0 auto;display: block;" />';
    
    if( mode == 'show' ) {

	// Make sure progress bar is visible
	// (color should match main div and there should be no content)
	jqProgress.show();

	// Now fade out progress bar to reveal white background image of
	// main div
	jqProgress.fadeOut( 
	    'fast', // define seconds?
	    function () { 
		// After fade out, switch bgcolor to white and load the
		// actual progress bar (or text or animation, as it may be)
		jqProgress.css( 'background-color', '#ffffff' );
		jqProgress.html( progressHTML );

		// Show the actual progress bar
		jqProgress.show();
		
		// Try to show the page's content
		showPageContent( jqPage, 1 );
	    } // callback
	); // fadeOut
    } // ( mode == 'show' )
    else if( mode == 'hide' ) {
	// Fade out the progress bar (at this point the bgcolor should be white
	// and the progres bar (text/animation) should be showing
	jqProgress.fadeOut( 
	    350, // define seconds?
	    function () {
		// After fade out, reset bgcolor and content to main div's color
		// and empty, respectfully
		jqProgress.css( 'background-color', '' );
		jqProgress.html( '' );
		
		// Now fade in main page's content
		var jqContent = $( '.mainContent', jqPage );
		jqContent.fadeIn( 650, // define seconds
                  function() { onAnimationDone(); }
                );

		$( 'body' ).removeClass( 'animating' );
	    }
	); // fadeout

    } // ( mode == 'hide' )
    else if( mode == 'reset' ) {
	// Fade in on progress bar 
	// (color should match main div and there should be no content)
	jqProgress.fadeIn( 'fast' ); // define seconds?
    }
    else if( mode == 'subnav' ) {

	// When subnav link clicked, switch bgcolor to white and load the
	// actual progress bar (or text or animation, as it may be)
	jqProgress.css( 'background-color', '#ffffff' );
	jqProgress.html( progressHTML );
	
	// Now fade in the progress bar to show the actuall progress bar
	jqProgress.fadeIn( 
	    'fast', // define seconds?
	    function () { 
		// Try to show the page's content
		showPageContent( jqPage, -1 );
	    } // callback
	); // fadeOut
    } // ( mode == 'subnav' )

    return false;
} // toggleProgressBar

function hidePageContent( jqPage, state, subnavFlag, cback )
{
    // TODO: Throw error if state is null

    if( subnavFlag ) {
	// Figure out the height of the content
	var jqContent     = $( '.mainContent', jqPage );
	var contentHeight = jqPage.innerHeight();
	
	// Set height of main div, so that it doesn't abruptly collapse
	// when the content fades out
	jqPage.css( 'height', contentHeight + 'px' );
	
	// Set height of the content div; this is neccessary for design awards
	// pages with black background so that it doesn't flash white
	jqContent.css( 'height', contentHeight + 'px' );

	// Add animating class to body (primarily used by awards pages)
	$( 'body' ).addClass( 'animating' );
	
	// Fade out main content
	$( '.toTop' ).remove();
	jqContent.fadeOut( 
	    400, // define seconds ?
	    function () {
		// Reset height of content div, otherwise it won't expand
		jqContent.css( 'height', '' );
		toggleProgressBar( 'subnav', jqPage );
		if( cback ) cback();
	    }
	);

	return false;
    }
    
    if( state == 0 ) { // first time called
	// Fade out main content
	$( '.toTop' ).remove();
	var jqContent  = $( '.mainContent', jqPage );
	jqContent.fadeOut( 400 ); // define seconds ?

	var heightToAnimateTo = gNormalPageHeight;
	var body = $( 'body' );
	if( body[0].id == 'utilityFolder' || body.hasClass( 'tmp-award' ) ) {
	    heightToAnimateTo = gUtilPageHeight;
	}

	// Animate main div back to base height (481)
	jqPage.animate( 
	    { height : heightToAnimateTo + 'px' }, 
	    780, // define seconds?
	    null,
	    function () { hidePageContent( jqPage, 1, subnavFlag, cback ) } // call again
	);
    }
    else if( state == 1 ) { // second time called
	// Hide white background
	toggleProgressBar( 'reset', jqPage );

	// Hide sidenav
	$( '.sidenav p.sponsor', jqPage ).fadeOut( 'fast' );
	var sidenavs = $( 'ul.nav', jqPage ); // cart has two ul.nav
	for( var sideIdx = 0; sideIdx < sidenavs.length; sideIdx++ ) {
	    var afterFadeOut = null;

	    if( sideIdx == 0 ) {
		afterFadeOut = function () {
		    // call again
		    hidePageContent( jqPage, 2, subnavFlag, cback );
		}; // cback
	    }

	    sidenavs.eq( sideIdx ).fadeOut( 
		'fast', // define seconds
		afterFadeOut
	    );
	} // foreach sidenav
    }
    else { // ( state == 2 )
	// Prepare main div for animation by absolutely positioning it and
	// setting top/left and changing its class
	if( jqPage[0].id == 'util' ) {
	    jqPage.css( 'position', 'relative' );
	    jqPage.css( 'top', 0 );
	    jqPage.css( 'marginLeft', '250px' );
	    //jqPage.css( 'padding', '50px' );
	}
	else {
	    jqPage.css( 'position', 'absolute' );
	    jqPage.css( 'top', 0 );
	    jqPage.css( 'left', '159px' );
	}

	jqPage.removeClass( 'openFolder' );
	jqPage.addClass( 'closedFolder' );

	// Add 24px to width because openFolder had 24px of padding-right, while
	// closedFolder doesn't
	if( jqPage[0].id != 'util' )
	    jqPage.css( 
		'width', 
		(parseInt( jqPage.css( 'width' ) ) + 24) + 'px'
	    );

	// Add 48px to height to make up for 24px top/bottom border in openFOlder
	jqPage.css( 'height', (parseInt( jqPage.css( 'height' ) ) + 48) + 'px' );

	// Now that the page is absolutely positioned, the outer content div's height
	// is messed up, so set the height of outer content div,
	// so that footer doesn't collapse
	$( '#content' ).css( 'height', jqPage.css( 'height' ) );

	// Finally, call the callback function
	if( cback ) 
	    cback();
    }
    
    return false;
} // hidePageContent

function togglePageHover( mode, jqPage )
{
    var jqBody = $( 'body' );

    if( mode == 'Off' ) {
	$( '#pages .openFolder' ).unbind( 'mouseover', turnPageHoverOn );
	if( !jqBody.hasClass( 'inProgress' ) ) {
	    jqBody.addClass( 'inProgress' );
	}
    }
    else if( mode == 'Standby' && jqPage && jqBody.hasClass( 'inProgress' ) ) {
	jqPage.mouseover( turnPageHoverOn );
    }
    else if( mode == 'On' && jqPage && jqBody.hasClass( 'inProgress' ) ) {
	jqBody.removeClass( 'inProgress' );
	jqPage.unbind( 'mouseover' );
    }
    
    return false;
} // togglePageHover

function turnPageHoverOn() {
  $(this).mouseover( function () { togglePageHover( 'On', $(this) ) } );
}

function getPageIndex( jqFolder )
{
    var classes = jqFolder[0].className.split( /\s+/ );

    var idx;

    for( var i = 0; i < classes.length; i++ ) {
	if( classes[i].match( /^folder\d$/ ) ) {
	    idx = classes[i].substr( 6, 1 );
	}
    }

    return idx;
} // getPageIndex

function setPageIndex( jqFolder, idx ) 
{
    jQuery.each( 
	[ 0, 1, 2, 3, 4, 5, 6 ],
	function (i) {
	    jqFolder.removeClass( 'folder' + i );
	}
    );

    jqFolder.addClass( 'folder' + idx );
}

function showSubnav(evt)
{
    var link = evt.target;
    if( link.id && link.id != "" )
    {
	$( '#awards .mainContent' ).hide();
	$( '#' + link.id + '-content' ).show();
    }

    return false;
} // showSubnav

function preparePagesForAnimation()
{
    var isUtilShowing = $( 'body' )[0].id == 'utilityFolder';

    // Loop through each page
    for( var i = 0; i < 6; i++ ) {

	var folderIdx = i;
	var folderNum = i;

	if( isUtilShowing && folderIdx >= 2 ) {
	    folderIdx++; // adjust for utility numbering
	    folderNum++;
	}
	
	var jqPage = $( 'div.folder' + folderIdx );
	var page   = jqPage[0];
	
	// Determine top, left, width, height of this page
	var cssRule = 'body#viewFolder div.folder' + folderNum;

	if( isUtilShowing ) {
	    cssRule = 'body#utilityFolder div#pages div.folder' + folderNum;
	}
	else if( i == 2 ) {
	    cssRule = 'body.siteSection div#content div.openFolder';
	}
	
	// Set tlwh withing page's style
	setPageIndex( jqPage, folderNum );
	animateCSSRule( 1, [ [ jqPage, cssRule ] ] );
    } // foreach page

    return true;
} // preparePagesForAnimation

function updateBodyTemplateClass( template )
{
    var body = $( 'body' )[0];

    var classes    = body.className.split( ' ' );
    var newClasses = [];
    
    for( var i = 0; i < classes.length; i++ ) {
	var cls = classes[i];
	if( cls.indexOf( 'tmp-' ) == -1 ) {
	    newClasses.push( cls );
	}
    }

    if( template != null && template != '' ) {
	newClasses.push( 'tmp-' + template );
    }
    
    body.className = newClasses.join( ' ' );

    return false;
} // updateBodyTemplateClass

function addBackToTopLink( jqContent )
{
    var styleDisplay = 'none';

    // If content wasn't passed in
    if( jqContent == null ) {

	// Then try to get it
	var jqPage = getPageInCenter();
	if( jqPage.length > 0 ) {

	    // Figure out min height for back to top
	    var minHeight = gNormalPageHeight;
	    var body      = $( 'body' );
	    if( body[0].id == 'utilityFolder' 
		|| body.hasClass( 'tmp-award' ) ) {
		minHeight = gUtilPageHeight;
	    }
	    
	    // Figure out center page height
	    jqContent     = $( '.mainContent', jqPage );
	    var jqSidenav = $( 'ul.nav', jqPage );

	    var contentHeight = jqContent.outerHeight();
	    var sidenavHeight = jqSidenav.outerHeight() + 85;

	    var newHeight = contentHeight > sidenavHeight ? contentHeight
	                  :                                 sidenavHeight
	                  ;

	    // If page is not tall enough, then don't show link
	    if( newHeight <= (minHeight*2) ) {
		jqContent = null;
	    } // if too small
	    else {
		jqContent = jqPage;
		styleDisplay = null;
	    }
	} // if center page
    } // if no page passed in

    if( jqContent != null && jqContent.length > 0 ) {
	var style = styleDisplay != null ? ' style="display: ' 
	                                   + styleDisplay
	                                   + ';"'
	          :                        ''
	          ;  
	
	jqContent.append( '<a href="#top" class="toTop" onclick="return onBackToTop(this)" onkeypress="return onBackToTop(this)"' 
			  + style 
			  + '>Back to top</a>' );
    }
} //addBackToTopLink

function onBackToTop(link) {
  window.scroll(0, 0);
  return false;
}

/* jQuery add-ons */

jQuery.fn.animateZoom = function ( zoomPercentage, duration, easing, callback, addParams ) {

    var perc = zoomPercentage.replace( '%', '' );
    perc     = perc/100;

    for( var i = 0; i < this.length; i++ ) {
	
	var tag = this[i].tagName.toUpperCase();
	if( tag == "IMG" )
	{
	    var img  = this[i];
	    var oldW = img.originalWidth || img.width;
	    var oldH = img.originalHeight || img.height;

	    img.originalWidth = oldW;
	    img.originalHeight = oldH;

	    var newW = Math.round( oldW * perc );
	    var newH = Math.round( oldH * perc );

	    var cback = i == 0 ? callback : null;
	    
	    this.eq(i).animate( 
		{ 
		    width : newW + 'px',
		    height : newH + 'px'
		},
		duration,
		easing,
		cback
	    );
	}
	else if( tag == "DIV" )
	{
	    var div  = this[i];
	    var oldW = div.originalWidth || this.eq(i).width();
	    var oldH = div.originalHeight || this.eq(i).height();

	    div.originalWidth = oldW;
	    div.originalHeight = oldH;

	    var newW = Math.round( oldW * perc );
	    var newH = Math.round( oldH * perc );

	    var cback = i == 0 ? callback : null;

	    var params = {};
	    if( addParams ) {
		for( var key in addParams  ) {
		    params[key] = addParams[key];
		}
	    }

	    params['width'] = newW + 'px'
	    params['height'] = newH + 'px'

	    this.eq(i).animate( params, duration, easing, cback );
	}
    }
} // animateZoom

jQuery.fn.setZoom = function( zoomPercentage ) {

    var perc = zoomPercentage.replace( '%', '' );
    perc     = perc/100;

    for( var i = 0; i < this.length; i++ ) {
	
	var tag = this[i].tagName.toUpperCase();
	if( tag == "IMG" )
	{
	    var img = this[i];

	    var oldW = img.originalWidth 
                    || img.width
	            || this.eq(i).width() 
		    || jQuery.curCSS( img, 'width', true )
	            ;
	    var oldH = img.originalHeight 
		    || img.height
	            || this.eq(i).height()
	            || jQuery.curCSS( img, 'height', true )
	            ;

	    oldW = parseInt( oldW );
	    oldH = parseInt( oldH );

	    img.originalWidth = oldW;
	    img.originalHeight = oldH;

	    var newW = Math.round( oldW * perc );
	    var newH = Math.round( oldH * perc );
	    
	    this.eq( i )
	    .css( 'width', newW + 'px' )
	    .css( 'height', newH + 'px' )
	    ;
	}
	else if( tag == "DIV" )
	{
	    var div  = this[i];
	    var oldW = div.originalWidth || this.eq(i).width() || jQuery.curCSS( div, 'width', true );
	    var oldH = div.originalHeight || this.eq(i).height() || jQuery.curCSS( div, 'height', true );

	    oldW = oldW + "";
	    oldH = oldH + "";

	    oldW = oldW.replace( 'px', '' );
	    oldH = oldH.replace( 'px', '' );

	    div.originalWidth = oldW;
	    div.originalHeight = oldH;

	    var newW = Math.round( oldW * perc );
	    var newH = Math.round( oldH * perc );

	    //alert( oldW + ' x ' + oldH + ' => ' + newW + ' x ' + newH );
	    
	    this.eq( i )
	    .css( 'width', newW + 'px' )
	    .css( 'height', newH + 'px' )
	    ;
	}
    }

} // setZoom

function animateCSSRule( dur, items )
{
    var validRules = {
	top    : true,
	left   : true,
	right  : true,
	width  : true,
	height : true
    };

    for( var itemIdx in items ) {
	var item     = items[itemIdx];
	var jqElem   = item[0];
	var cssClass = item[1];
	var easing   = item[2];
	var cback    = item[3];
	var override = item[5];

	var ss = new Array();
	for( var i = 0; i < document.styleSheets.length; i++ ) {
	    ss.push( document.styleSheets[i] );
	}

	for( var i = 0; i < ss.length; i++ )
	{
	    var ruleFound = false;

	    if( ss[i].imports ) {
		for( j=0; j<ss[i].imports.length; j++ ) {
		    ss.push( ss[i].imports[j] );
		}
	    }
	    
	    var rules = ss[i].cssRules || ss[i].rules;
	    if( !rules )
		continue;
	    
	    for(j=0; j<rules.length; j++)
	    {
		var rule = rules[j];
		
		if( rule.type 
		    && rule.type == CSSRule.IMPORT_RULE ) {
		    if( rule.styleSheet ) 
			ss.push( rule.styleSheet );
		    continue;
		}
		else if( rule.type 
			 && rule.type != CSSRule.STYLE_RULE )
		    continue;

		var ruleList = rule.selectorText.split( /,\s+/ );
		for(k=0; k<ruleList.length; k++ ) {
		    var ruleText = ruleList[k];
		    if( ruleText.toLowerCase() == cssClass.toLowerCase() ) {
			logme( 'FOUND: ' + ruleText );
			var attrs = {};
			var attrsSet = false;
			
			if( typeof rule.style.length == "undefined" ) {
			    for( var k in rule.style ) {
				if( rule.style[k] != ""  && validRules[k] ) {
				    attrs[k] = rule.style[k];
				    attrsSet = true;
				}
			    }
			}
			else {
			    for( var keyIdx = 0; keyIdx < rule.style.length; keyIdx++ ) {
				var key = rule.style[keyIdx];
				if( validRules[key] ) {
				    var val = rule.style[key];
				    attrs[key] = val;
				    attrsSet = true;
				}
			    }
			}

			if( attrsSet ) {
			    item[4] = attrs;
			    
			    ruleFound = true;
			    break;
			}
		    }
		} // foreach rule text
		
		if( ruleFound )
		    break;
	    }

	    if( ruleFound )
		break;
	} // foreach stylesheet

	if( item[4] ) {
	    if( override ) {
		for( var key in override ) {
		    item[4][key] = override[key];
		}
	    }

	    jqElem.animate( item[4], dur, easing, cback );
	}
    } // foreach item
}

function logme( msg ) {
//    $( '#logs' ).val( $( '#logs' ).val() + "\n" + msg );
}

function handleSearchInput( el, str, bRestore )
{
    if( el ) {
	if( bRestore ) { // restore string
	    if( el.value == "" ) {
		el.value = str;
		el.style.color = "black";
	    }
	} else { // clear string
	    if( el.value == str ) {
		el.value = "";
		el.style.color = "red";
	    }
	}
    }
} // handleSearchInput


var Widgets = new Object();
Widgets.OnChange = { Swap : { AddListener : function () { } } };

/*************************************************************************
 **
 ** UTILITY FUNCTIONS
 **
 ************************************************************************/

function _blank( link ) {
    window.open( link.href );
    return false;
} // _blank

/*************************************************************************
 **
 ** JOIN FORM FUNCTIONS
 **
 ************************************************************************/

$( document ).ready( function () {
    new Join();
} );

function Join() {
    this.initialize();
    return this;
}

Join.prototype = {
    
    join_form : null,

    initialize : function () {
	var jqJoinForm = $( 'form#new_membership' );
	if( jqJoinForm.length == 1 ) {
	    
	    var joinForm = jqJoinForm[0];
	    joinForm.joinObj = this;

	    this.join_form = joinForm;

	    var doUpdate = function () {
		return joinForm.joinObj.updateCosts();
	    };
	    
	    $( joinForm.elements['country'] ).change( doUpdate );
	    
	    $( joinForm.elements['membership_type_fk'] ).change( doUpdate );

	    $( joinForm.elements['str_1'] ).change( doUpdate );

	    this.updateCosts();
	    
	} // if found form
    }, // initialize

    updateCosts : function () {

	var joinForm = this
	
	// Get form elements that determine costs
	var membershipType = this.join_form.elements['membership_type_fk'];
	var country        = this.join_form.elements['country'];
	var appFee         = this.join_form.elements['str_1'];

	var resetCost  = true;
	var resetTotal = true;
	
	var totalCost = $( '#total-cost' );
	var memCost   = $( '#membership-cost' );

	var selectedType = gMembershipTypes[membershipType.value];
	if( selectedType ) {
	    var selectedCountry = country.value;

	    if( selectedCountry ) {
		
		var cost = selectedCountry == 'US' ? selectedType.domestic_price
	                 : selectedCountry == 'CA' ? selectedType.canada_price
                         :                           selectedType.intl_price
	                 ;

		cost = Tools.ParseMoney( cost );
		
		var membershipName = selectedType.name
	                           + ' - '
	                           + ( selectedCountry == 'US'  ? 'Domestic'
	                              : selectedCountry == 'CA' ? 'Canada' 
	                              :                           'International' )
	                           + ' '
	                           + Tools.FormatMoney( cost, true )
	                           ;
	        
		if( typeof memCost[0].prevHTML == 'undefined' )
		    memCost[0].prevHTML = memCost.html();
		memCost.html( membershipName );

		resetCost = false;

		var selectedFee = null;
		for( var i = 0; i < appFee.length; i++ ) {
		    if( appFee[i].checked ) {
			selectedFee = appFee[i].value;
			break;
		    }
		}

		if( selectedFee ) {
		    var fee = selectedFee == 'prof' ? 40.00
	                    :                         15.00
	                    ;

		    var total = parseFloat( cost ) + parseFloat( fee );

		    if( typeof totalCost[0].prevHTML == 'undefined' )
			totalCost[0].prevHTML = totalCost.html();
		    totalCost.html( Tools.FormatMoney( total, true ) );

		    resetTotal = false;
		} // if fee was selected
	    } // if country was selected
	} // if type was selected

	if( resetCost && typeof memCost[0].prevHTML != 'undefined' )
	    memCost.html( memCost[0].prevHTML );

	if( resetTotal && typeof totalCost[0].prevHTML != 'undefined' )
	    totalCost.html( totalCost[0].prevHTML );
	
    } // updateCosts

    
} // JOIN.Initialize

function toggleStudioMembers(memDropdown) {

	var memDropdown = document.getElementsByName(memDropdown)[0];
	var memType = memDropdown.options[memDropdown.selectedIndex].value;
	var studioDiv = document.getElementById("studio_members");

	if (memType == 2 || memType == 7) {
		studioDiv.style.display = "block";	
	} else {
		studioDiv.style.display = "none";
	}
} //toggleStudioMembers

/*************************************************************************
 **
 ** RENEW FORM FUNCTIONS
 **
 ************************************************************************/

$( document ).ready( function () {
    new Renew();
} );

function Renew() {
    this.initialize();
    return this;
}

Renew.prototype = {
    
    renew_form : null,

    initialize : function () {
		var jqRenewForm = $( 'form#renew_membership' );
		if( jqRenewForm.length == 1 ) {
		    
		    var renewForm = jqRenewForm[0];
		    renewForm.renewObj = this;
	
		    this.renew_form = renewForm;
	
		    var doUpdate = function () {
				return renewForm.renewObj.updateCosts();
		    };
		    
		    $( renewForm.elements['country'] ).change( doUpdate );
		    
		    $( renewForm.elements['membership_type_fk'] ).change(
		    											function() {
															if ( this.value == 'prorated' )
																$('#prorated_amount_field').fadeIn();
															else if ( $('#prorated_amount_field').is(':visible') )
																$('#prorated_amount_field').fadeOut();
																
		    												doUpdate();
		    										
		    											}
		 											 );
	
		    $( renewForm.elements['additional_membership_type_fk'] ).change( doUpdate );
	
		    $( renewForm.elements['prorated_amount'] ).change( doUpdate );
	
		    this.updateCosts();
		    
		} // if found form
    }, // initialize

    updateCosts : function () {

		var renewForm = this;
		
		// Get form elements that determine costs
		var membershipType = this.renew_form.elements['membership_type_fk'];
		var country        = this.renew_form.elements['country'];
		var proratedAmt    = this.renew_form.elements['prorated_amount'].value;

		var additionalType = this.renew_form.elements['additional_membership_type_fk'];
	
		var resetTotal = true;
		
		var totalCost = $( '#total-cost' );
	
		var selectedType = gMembershipTypes[membershipType.value];
		var selectedAddl = gMembershipTypes[additionalType.value];

		if( selectedType || membershipType.value == 'prorated' ) {

		    var selectedCountry = country.value;
		    if( selectedCountry ) {
			
				var cost = selectedType == null    ? null
				         : selectedCountry == 'US' ? selectedType.domestic_price
			                 : selectedCountry == 'CA' ? selectedType.canada_price
		                         :                           selectedType.intl_price
			                 ;
				if( cost != null )
				    cost = Tools.ParseMoney( cost );
				
				var addlCost 
				    = selectedAddl == null    ? null
				    : selectedCountry == 'US' ? selectedAddl.domestic_price
			            : selectedCountry == 'CA' ? selectedAddl.canada_price
		                    :                           selectedAddl.intl_price
			            ;
		
				if( addlCost != null )
				    addlCost = Tools.ParseMoney( addlCost );
				else
				    addlCost = 0;

				if( cost != null) {
				    var total = parseFloat( cost ) + parseFloat( addlCost );
				    
				    if( typeof totalCost[0].prevHTML == 'undefined' )
						totalCost[0].prevHTML = totalCost.html();
						
				    totalCost.html( Tools.FormatMoney( total, true ) );
				    
				    resetTotal = false;
				}
				else if ( proratedAmt != null && proratedAmt != '' ) {
				    proratedAmt = Tools.ParseMoney( proratedAmt );
				    
				    var total = parseFloat( addlCost ) + parseFloat( proratedAmt );
					
				    if( typeof totalCost[0].prevHTML == 'undefined' )
						totalCost[0].prevHTML = totalCost.html();
						
				    totalCost.html( Tools.FormatMoney( total, true ) );
				    
				    resetTotal = false;
					 
				}
		    } // if country was selected
	} // if type was selected

	if( resetTotal && typeof totalCost[0].prevHTML != 'undefined' )
	    totalCost.html( totalCost[0].prevHTML );
    
	return;
    } // updateCosts

    
} // RENEW.Initialize




/*************************************************************************
 **
 ** SHOPPING CART - FORGOT PASSWORD
 **
 ************************************************************************/

$( document ).ready( function () { ForgotPassword.Initialize() } );

var ForgotPassword = new Object();

ForgotPassword.Initialize = function () {
    var forgot = $( '#forgot-form' );
    
    if( forgot.length > 0 ) {
	new MiniForm(
	    forgot,
	    {
		success     : ForgotPassword.OnSuccess
	    }
	);
    }

    return;
} // Initialize

ForgotPassword.OnSuccess = function (xml, confirmId) {
    
    if( !confirmId )
	confirmId = 'forgotPasswordConfirm';

    var conf = $( '#' + confirmId );

    Tools.ReplaceData( xml, conf );

    conf.slideDown( 'normal' )

    return false;
} // ForgotPassword.onSuccess

/*************************************************************************
 **
 ** SHOPPING CART - FORGOT USERNAME
 **
 ************************************************************************/

$( document ).ready( function () { ForgotUsername.Initialize() } );

var ForgotUsername = new Object();

ForgotUsername.Initialize = function () {
    var forgot = $( '#forgot-username-form' );
    
    if( forgot.length > 0 ) {
	new MiniForm(
	    forgot,
	    {
		success     : ForgotUsername.OnSuccess
	    }
	);
    }

    return;
} // Initialize

ForgotUsername.OnSuccess = function (xml, confirmId) {
    
    if( !confirmId )
	confirmId = 'forgotPasswordConfirm';

    var conf = $( '#' + confirmId );

    Tools.ReplaceData( xml, conf );

    conf.slideDown( 'normal' )

    return false;
} // ForgotUsername.onSuccess


// Add special "-hoverized" classes for ie6, which doesn't have :hover
// pseudoclasses for non-anchor elements.


function hoverizeAll() {

  var selectors = [
    'div.closedFolder',
    'div.folder0',
    'div.folder1',
    'div.folder2',
    'div.folder3',
    'div.folder4',
    'div.folder5',
    'li.awardsGridItem'
  ];

  for (i in selectors) {
    var s = selectors[i];
    $(s).each(function() {
      hoverize($(this));
    });
  }
}

function dehoverizeAll() {
  $('.hoverized').each( function() { dehoverize($(this)) } );
} 

function hoverize(elem) {
  elem.bind('mouseenter', onHoverOver);
  elem.bind('mouseleave', onHoverOut);
  elem.addClass('hoverized');
}

function dehoverize(elem) {
  elem.unbind('mouseenter', onHoverOver);
  elem.unbind('mouseleave', onHoverOut);
  removeHoverClasses(elem);
  elem.removeClass('hoverized');
}

function onHoverOver() {
  addHoverClasses($(this));
}

function onHoverOut() {
  removeHoverClasses($(this));
}

function addHoverClasses(elem) {
  var classes = elem.attr('class').split(' ');
  var hasclass = {};

  for (var i in classes) {
    hasclass[classes[i]] = 1;
  }

  // on rollover, add a css class "xyz-hover" for every css class "xyz".
  // remove any stale "xyz-hover" classes if "xyz" is no longer applied.

  for (var i in classes) {
    var c = classes[i];
    var i = c.indexOf('-hover');

    if (i < 0 && c != 'hoverized') 
      elem.addClass(c+'-hover');
    else if (i > 0 && !hasclass[c.substr(0, i)]) {
      elem.removeClass(c);
    }
  }
}

function removeHoverClasses(elem) {
  var classes = elem.attr('class').split(' ');

  // on rollout, remove all ".*-hover" classes.

  for (var i in classes) {
    var c = classes[i];

    if (c.indexOf('-hover') > 0) 
      elem.removeClass(c);
  }
}



function activateNone() {
	$('.concurrent-radios').attr('disabled', 'disabled');
	$('.workshops-radios').attr('disabled', 'disabled');
}
function activateConcurrent() {
	$('.concurrent-radios').attr('disabled', 'disabled');
	$('.workshops-radios').removeAttr('disabled');
}
function activateWorkshops() {
	$('.workshops-radios').attr('disabled', 'disabled');
	$('.concurrent-radios').removeAttr('disabled');
}
