/*
 * The Institute
 *
 */


//return false;

//optional param #2 = tag
var d = function( msg ) {
    var h = 'p';
    if ( arguments.length === 2 ) {
        h = arguments[1];
    }
    $('div#debug').html(
        $('div#debug').html() + "\n" +
        '<' + h + '>' + msg + '</' + h + '>'
    );
};

var settings = {
    
    global: {
        /* cookie name for favorites and other settings */
        cookieName: 'tifavs',
        /* interval to rotate background image on (in MS) */
        rotateBackgroundInterval: 10000,
        /* TI's public Twitter ID */
        twitterID: '121546688',
        /* faux IDs for news and other pages without media IDs (for favoriting) */
        staticIDs: {
            news: -1,
            about: -2,
            contact: -3,
            directors: -4
        }
    },
    
    actions: {
        expandedOffset:  0,
        collapsedOffset: -76,
        animateTwitterMarquee: false,
        preloadAllGalleryBackgrounds: false
    },
    
    // smaller viewport for netbooks, etc. (3 rows in browse, instead of 4)
    smallViewportHeight: 302 /*352,*/,
    
    // normal viewport size, for browsers with verticle available screen
    // realestate equal or larger to settings.switchViewportHeight
    //429 on static first load, fyi
    normalViewportHeight: 444 /*449*/,
    
    // the height at which the viewport switches from normal (4 rows)
    // to small (3 rows) if > or < respectively
    switchViewportHeight: 688,
    
    // different video dimensions depending on size of viewport
    video: {
        smallVideo: {
            width: 533,
            height: 300
        },
        normalVideo: {
            width: 704,
            height: 396
        }
    }
    
};


var session = {
    
    /* set at runtime, this will be "news", "directors", etc. */
    pageType: '',
    
    /* human readable page title (mostly for sharing, etc.) */
    pageTitle: 'The Institute',
    
    pageWidth: -1,
    pageHeight: -1,
    contentHeight: -1,
    
    /* REQUIRED so the jScrollPane reinit doesn't create an infinite loop and destroy you */
    viewportResizing: false,
    
    /* gallery array for rotating background images */
    backgroundGallery: [],
    
    /* cache vector to increase entropy in choosing a random gallery image */
    backgroundGalleryCache: [],
    
    /* current gallery index */
    currentBackgroundIndex: -1,
    
    /* don't allow growls to double up when background is faking viewport size */
    backgroundRotationInProgress: false,
    
    /* whether or not to rotate the background image (useful for debugging) */
    /*rotateBackground: true,*/
    /*debug*/rotateBackground: function( /* boolean */ ) {
        if ( window.location.href.indexOf('http://localhost') >= 0 ) {
            //trace('rotateBackground: block #01, false');
            return false;
        }
        else {
            //trace('rotateBackground: block #02, waiting...');
            if ( arguments.length === 1 ) {
                //trace('rotateBackground: block #02a, ' + ((arguments[0] == true)?'true':'false'));
                return ( arguments[0] === true );
            }
            else {
                //trace('rotateBackground: block #02b, false');
                return false;
            }
        }
    },
    
    /* internal; prevents animation overlap for actions/buzz bar */
    actionsAnimating: false,
    
    /* internal; temporarily pauses animation (when mouseOver, for instance) */
    pauseTwitterMarquee: false,
    
    /* TI pulled in tweets */
    tweets: [],
    
    /* prevent buzz from freaking out by making a delayed hover */
    buzzHoverShowDelayEnabled: false,
    
    /* global access to the currently playing video */
    currentVideo: null,
    
    /* keeps track of the last video thumbnail link clicked on, enabling circular playlist */
    currentVideoIndex: 0,
    
    /* where you started the playlist from (i.e., if there are 4 vids and you start at #2, it plays 3-4, then #1) */
    videoPlaylistIndex: 0,
    
    /* global access to the html5 player */
    html5player: null,
    
    /* current clip's ID */
    clipID: null,
    
    /* current person who did this media's name */
    creatorName: null,
    
    /* global collection of gallery images from browse or directors */
    galleryImages: [],
    
    /* original, current page URL - for easily setting page+hash URLs */
    currentPageURL: window.location.href.toString()
    
};


var timers = {
    /* directors' info hover bubble */
    directorInfo: -1,
    /* buzz bar slim twitter slider */
    twitterMarquee: -1,
    /* prevent buzz from freaking out by making a delayed hover */
    buzzHoverShowDelay: -1,
    /* keep share this drop visible for a tiny bit after hover-out */
    socialDropSticky: {
        myFavorites: -1,
        shareThis: -1,
        search: -1
    }
};


/* generic Trace function, similar to AS
   (hidden second param = force alert on error */
var trace = function( m /* (bool) force = false */ ) {
    var show_ts = true; // timestamps??
    if ( show_ts ) {
        var d = new Date();
        m = (
            '[' +
            d.getHours() + ':' +
            d.getMinutes() + ':' +
            d.getSeconds() +
            '] ' + m
        );
    }
    try { console.log( m ); }
    catch (e) {
        if ( arguments.length >= 2 ) {
            if ( arguments[1] ) {
                alert( 'DEBUG/TRACE MESSAGE' + "\n\n" + m );
            }
        }
    }
};




var print_r = function( theObj ) {
    var s = '';
    if (theObj.constructor === Array || theObj.constructor == Object) {
        s += "\n";
        for (var p in theObj) {
            if (theObj[p].constructor === Array || theObj[p].constructor === Object) {
                s += ("\n[" + p + "] => " + typeof(theObj));
                s += "\n";
                s += print_r( theObj[p] );
                s += "\n";
            } else {
                s += ("\n[" + p + "] => " + theObj[p]);
            }
        }
        s += "\n";
    }
    return s;
};

var print_r_html = function( theObj ) {
    if (theObj.constructor === Array || theObj.constructor === Object) {
        document.write("<ul>");
        for (var p in theObj) {
            if (theObj[p].constructor === Array || theObj[p].constructor === Object) {
                document.write("<li>[" + p + "] => " + typeof(theObj) + "</li>");
                document.write("<ul>");
                print_r_html(theObj[p]);
                document.write("</ul>");
            } else {
                document.write("<li>[" + p + "] => " + theObj[p] + "</li>");
            }
        }
        document.write("</ul>");
    }
};

/* NOTE: THESE PROBABLY WILL FAIL IN CHROME... AND IE of course /// update: not using prototype anymore =( */
// trim left spaces
/*String.prototype.*/var ltrim = function(s) {
    return /*this*/s.replace(/^\s+/, "");
};

// trim right spaces
/*String.prototype.*/var rtrim = function(s) {
    return /*this*/s.replace(/\s+$/, "");
};

// trim left and right spaces
/*String.prototype.*/var trim = function(s) {
    return /*this*/s.replace(/^\s+|\s+$/g, "");
};

// trim all whitespace (including: spaces, tabs and returns)
/*String.prototype.*/var trimAll = function(s) {
    return /*this*/s.replace( /(?:(?:^|\n)\s+|\s+(?:$|\n))/g, "" );
};





if ( $.browser.msie ) {
    if ( Array.indexOf == undefined ) {
        Array.prototype.indexOf = function( s ) {
            for ( var i = 0; i < this.length; i++ ) {
                if ( this[i] == s ) {
                    return i;
                }
            }
            return -1;
        };
    }
}


/*
 * wrapper for window.location.href = xxx
 * triggers any hashed requests, etc.
 * @param url {string} URL to change the page location to
 */
var setWindowURL = function( url ) {
    
    window.location = url;
    window.location.href = url;
    
    // triggers
    handleHashedURL();
    
};



// for quicktime support, since jQuery doesn't play nice
var addEventClassic = function( obj, evt, handler, captures ) {
    if ( document.addEventListener ) {
        trace( 'safari/ff/chrome/opera: using addEventListener()' );
        obj.addEventListener( evt, handler, captures );
    }
    else { /* IE */
        obj.attachEvent( ('on' + evt), handler );
    }
};


var playVideo = function( videoURL, width, height, autoPlay ) {
    //trace( 'playVideo() : init / dimensions @ ' + width + 'x' + height );
    $('div#player').empty();
    //if ( $(window).height() < settings.switchViewportHeight ) {
    $('div#player').width( width ).height( height );
    //trace( 'loading video ' + videoURL );
    flowplayer( 'player', {src: 'js/flowplayer/flowplayer.commercial-3.2.4.swf', wmode: 'opaque'}, {
        key: '#$0006bd5108184f5bf19',
        play: {opacity: 0},
        logo: {
            url: '/images/ti_logo.png',
            /*top: 20,
            right: 20,
            opacity: 0.4,
            width: '6.5%',
            height: '6.5%',*/
            fullscreenOnly: true,
            displayTime: 2000
	},
        contextMenu: [
	    'The Institute . player build 1.0.0',
	],
        clip: {
            url: videoURL,
            autoPlay: autoPlay,
            autoBuffering: true,
            bufferLength: 6/*,*/ /* seconds */
            /*live: false,*/
            /*
            onStart: function(){},
            onBegin: function(){},
            onResume: function(){},
            
            onPause: function(){},
            onFinish: function(){},
            onStop: function(){}
            */
            ,onBegin: function () {
                // always reinstate the play button
                this.getPlugin("play").css({opacity: 1});
            }
            ,onFinish: function() {
                // unpause slideshow
                session.backgroundRotationInProgress = false;
                // hide "play again" button
                this.getPlugin("play").css({opacity: 0});
                //this.getPlugin('play').css({opacity: 0});
                if ( session.pageType == 'directors' ) {
                    playNextVideo( true );
                }
                else {
                    closeWithDelay();
                }
            }
        },
        /*playlist: [{
            url: 'images/video.png',
            scaling: 'orig',
        }, {
            url: videoURL,
            autoPlay: autoPlay,
            autoBuffering: true
        }],*/
        plugins: {
            controls: {
                url: 'js/flowplayer/flowplayer.controls-3.2.2.swf',
                bottom: 0,
                opacity: 0.85,
                fullscreen: true,
                autoHide: 'always',
                hideDelay: 1000,
                playlist: false,
                backgroundGradient: 'low',
                fastForward: false,
                fastBackward: false,
                slowFoward: false,
                slowBackward: false
            }
        },
        onLoad: function() {
            this.setVolume( 90 );
        }
    });
    session.currentVideo = document.getElementById('player');
};


// all except autoPlay should be strings; autoPlay is boolean
var playVideoQuicktime = function( url, width, height, autoPlay ) {
    
    //QT_WriteOBJECT(
    //    url, '100%', '100%', '',
    //    'AUTOPLAY', 'True', 'SCALE', 'Aspect'
    //);
    
    var vw = 541;
    var vh = 422;
    
    if ( $(window).height() <= settings.switchViewportHeight ) {
        if ( [/*'directors', */'browse'].indexOf(session.pageType) >= 0 ) {
            vw = settings.video.smallVideo.width;
            vh = settings.video.smallVideo.height;
        }
        else {
            vw = settings.video.normalVideo.width;
            vh = settings.video.normalVideo.height;
        }
    }
    else {
        vw = settings.video.normalVideo.width;
        vh = settings.video.normalVideo.height;
    }
    
    var w = ( (width == '') ? vw.toString() : width ); /* actual width 579 - player controls bar */
    var h = ( (height == '') ? vh.toString() : height ); /* actual height 450 */
    
    trace( 'using video dims: ' + w + '/' + h );
    
    var params = [
        url, w, h, '',
        'autoplay', (autoPlay ? 'true' : 'false'),
        'scale', 'aspect', /*aspect, tofit*/
        'autohref', 'true',
        'kioskmode', 'false',
        'BGCOLOR', '#000000',
        'postdomevents', 'true'
    ];
    
    if ( arguments.length > 4 ) {
        for ( var i = 0; i < arguments.length; i++ ) {
            params.push( arguments[i] );
        }
    }
    
    var code = _QTGenerate( 'QT_WriteOBJECT_XHTML', true, params );
    
    $('div#player').empty().html( code );
    
    // allow the player to be accessed via JS
    $('div#player object').attr('id', 'videoQT');
    $('div#player embed').attr('name', 'videoQT');
    
    // update global access to current video
    getVideoObject( 'videoQT' );
    
    if ( session.pageType == 'directors' ) {
        
        $('object, embed').height( $('#playerContainer').height() );
        
        // start circular playlist
        $(session.currentVideo).ready( function() {
            
            //trace( 'quicktime is ready, adding events' );
            addEventClassic( session.currentVideo, 'qt_ended', function() {
                
                // unpause slideshow
                session.backgroundRotationInProgress = false;
                
                //trace( 'video finished' );
                playNextVideoQuicktime();
                
            }, false );
            
        });
        
    }
    else {
        
        // hide player container after video ends
        $(session.currentVideo).ready( function() {
            
            //trace( 'quicktime is ready, adding events' );
            addEventClassic( session.currentVideo, 'qt_ended', function() {
                
                // unpause slideshow
                session.backgroundRotationInProgress = false;
                
                // wait a second
                window.setTimeout( function() {
                    
                    // simulate clicking close button
                    closeWithDelay();
                    
                }, 1200 );
                
            }, false );
            
        });
        
    }
    
};


// gets the controllable video object (cross browser)
var getVideoObject = function( elementName ) {
    var v = document.getElementById( elementName );
    if ( typeof v == 'object' ) {
        return v;
    }
    else {
        if ( document.getElementsByName ) {
            return document.getElementsByName('videoQT')[0];
        }
        else {
            // OLD school
            var e = document.getElementsByTagName('embed')[0];
            for ( var i = 0; i < e.length; i++ ) {
                if ( e[i].name ) {
                    if ( e[i].name == 'videoQT' ) {
                        v = e[i];
                    }
                }
                else if ( e[i].getAttribute('name') ) {
                    if ( e[i].getAttribute('name') == 'videoQT' ) {
                        v = e[i];
                    }
                }
                else {
                    if ( e[i].getPropertyValue('name') == 'videoQT' ) {
                        v = e[i];
                    }
                }
            }
        }
    }
    return v;
    //return ( window[elementName] ? window[elementName] : document[elementName] );
};



var playNextVideo = function() {
    
    var circular = ( arguments[0] || false );
    
    var videos = $('div#videoGallery ul li a.videoLink');
    
    session.currentVideo = null;
    session.currentVideoIndex++;
    
    // enable circular playback
    if ( session.currentVideoIndex >= videos.length ) {
        session.currentVideoIndex = 0;
    }
    
    
    if ( session.currentVideoIndex == session.videoPlaylistIndex ) {
        
        if ( circular ) {
            
            session.currentVideoIndex = 0;
            
        }
        else {
            
            // stop and hide the video player
            //alert( 'end of the line buddy!' );
            closeWithDelay();
            
            // stop further videos from playing
            return;
            
        }
        
    }
    
    
    //playVideoQuicktime( $(videos[session.currentVideoIndex]).attr('href') );
    //$(videos[session.currentVideoIndex]).trigger( 'click' );
    
    if ( session.pageType != 'directors' ) {
        videoClickHandlerA( videos[session.currentVideoIndex], false );
    }
    else if ( session.pageType == 'directors' ) {
        videoClickHandlerB( videos[session.currentVideoIndex], false );
    }
    
    
};
// alias for legacy support aka too busy to refactor
var playNextVideoQuicktime = playNextVideo;



var updatePageTitle = function( clipTitle, director, executiveProducer ) {
    var newTitle = 'The Institute';
    if ( (clipTitle != '') && ((director != '') || (executiveProducer != '')) ) {
        newTitle = (
            ((director != '') ? director : executiveProducer) +
            ' - ' + clipTitle + ' @ theinstitute.tv'
        );
    }
    trace( 'updating document/meta titles to "' + newTitle + '"' );
    // update the document's title attribute
    try {
        $('title').text( newTitle );
    }
    catch (e) {
        document.title = newTitle;
    }
    // update the document's meta title attribute (which FB uses for sharing)
    $('meta[name="title"]').attr('content', newTitle);
};


var playPreviousVideo = function() {
    
    var circular = ( arguments[0] || false );
    var videos = $('a.videoLink');
    
    session.currentVideo = null;
    session.currentVideoIndex--;
    
    // if circular and going backwards and we hit the first video,
    // jump to the last video and start playing backwards from there
    if ( circular ) {
        
        // if we're at the last one, going back one, is -1, so make it the last vid
        if ( session.currentVideoIndex < 0 ) {
            session.currentVideoIndex = ( videos.length - 1 );
        }
        
    }
    else {
        
        if ( session.currentVideoIndex < 0 ) {
            
            // stop and hide the video player
            //alert( 'end of the line buddy!' );
            closeWithDelay();
            
            // stop further videos from playing
            return;
            
        }
        
    }
    
    trace( 'session.currentVideoIndex = ' + session.currentVideoIndex );
    
    //playVideoQuicktime( $(videos[session.currentVideoIndex]).attr('href') );
    //$(videos[session.currentVideoIndex]).trigger( 'click' );
    
    trace( 'vid prev / ' + session.currentVideoIndex + ' ' + videos[session.currentVideoIndex] + ' / ' + $(videos[session.currentVideoIndex]).attr('href') );
    
    if ( session.pageType != 'directors' ) {
        videoClickHandlerB( videos[session.currentVideoIndex], false );
    }
    else if ( session.pageType == 'directors' ) {
        videoClickHandlerB( videos[session.currentVideoIndex], false );
    }
    
    
};
// alias for legacy support aka too busy to refactor
var playPreviousVideoQuicktime = playPreviousVideo;

var playVideoHTML5 = function( url, width, height, autoplay ) {
    
    height = $('div#player').height();
    
    if ( width == undefined ) {
        if ( height <= 301 ) {
            // small
            width = settings.video.smallVideo.width;
        }
        else {
            // normal
            width = settings.video.normalVideo.width;
        }
    }
    
    if ( $('video').height() < ($('div#playerContainer').height() - 4) ) {
        
        if ( $(window).height() < settings.switchViewportHeight ) {
            //trace( 'adjusting the actual player size - SMALL' );
            width = settings.video.smallVideo.width;
            height = settings.video.smallVideo.height;
            $('video').width( width ).height( height );
        }
        else {
            //trace( 'adjusting the actual player size - NORMAL' );
            width = settings.video.normalVideo.width;
            height = settings.video.normalVideo.height;
            $('video').width( width ).height( height );
        }
        
    }
    
    var baseVideoURL = url.split('/');
    baseVideoURL.pop();
    baseVideoURL = baseVideoURL.join('/');
    baseVideoURL = '';
    
    //trace( 'playVideoHTML5() : base video URL @ ' + baseVideoURL );
    //trace( 'loading video dimensions @ ' + width + 'x' + height );
    //trace( 'playVideoHTML5() : playing ' + url );
    
    $('#player').empty().html(
        '<video id="html5player" class="video-js" width="' + width + '" height="' + height + '" controls preload>' +
        '    <source src="' + url + '" type=\'video/mp4; codecs="avc1.42E01E, mp4a.40.2"\'>' +
        '    <!--source src="' + url + '" type="video/webm; codecs="vp8, vorbis""-->' +
        '    <!--source src="' + url + '" type="video/ogg; codecs="theora, vorbis""-->' +
        '    <!-- flash fallback. Use any flash video player here. Make sure to keep the vjs-flash-fallback class. -->' +
        '       <object width="' + width + '" height="' + height + '" id="undefined" name="undefined"' +
        '           data="http://releases.flowplayer.org/swf/flowplayer-3.2.4.swf"' +
        '           type="application/x-shockwave-flash">' +
        '          <param name="movie" value="http://releases.flowplayer.org/swf/flowplayer-3.2.4.swf" />' +
        '          <param name="allowfullscreen" value="true" />' +
        '          <param name="allowscriptaccess" value="always" />' +
        '          <param name="flashvars" value=\'config={"clip":{"baseUrl":"' + baseVideoURL + '","url":"' + url + '"}}\' />' +
        '   </object>' +
        '   <p class="vjs-no-video"><strong>Download Video:</strong>' +
        '       <a href="' + url + '">MP4</a>,' +
        '       <!--a href="http://video-js.zencoder.com/oceans-clip.webm">WebM</a-->,' +
        '       <!--a href="http://video-js.zencoder.com/oceans-clip.ogg">Ogg</a--><br>' +
        '   </p>'
    );
    
    session.html5player = VideoJS.setup("html5player");
    
    session.html5player.play(); // Starts playing the video for this player.
    
    session.currentVideo = session.html5player;
    
    // on-finish
    $(session.currentVideo).ready( function() {
        $('#html5player').bind( 'ended', {}, function() {
            // unpause slideshow
            session.backgroundRotationInProgress = false;
            if ( session.pageType == 'directors' ) {
                playNextVideo( true );
            }
            else {
                closeWithDelay();
            }
        });
    });
    
};


// default video playback in Flash
var watchVideo = playVideo;

// just triggers the close video player function, but with a delay (2nd param is seconds, defaults to 1)
var closeWithDelay = function( /* seconds */ ) {
    var d = 1;
    if ( arguments.length == 1 ) {
        if ( parseInt(arguments[0]) >= 1 ) {
            d = parseInt( arguments[0] );
        }
    }
    d = ( d * 1000 ); // sec to ms
    window.setTimeout( function() {
        $('a[rel="close"]').trigger( 'click' );
    }, d );
};

// detect browser/os and which player to use
// NOTE: this is not "real" detection, but rather what
// we decided was best supported on each platform
var detectPlatform = function() {
    var watchVideoEx = playVideo;
    var ua = navigator.userAgent.toString().toLowerCase();
    if ( (ua.indexOf('ipad') >= 0) || (ua.indexOf('ipod') >= 0) || (ua.indexOf('iphone') >= 0) ) {
        // iOS device, use QT
        watchVideoEx = playVideoQuicktime;
    }
    else if ( (ua.indexOf('webkit') >= 0) || (ua.indexOf('safari') >= 0) || (ua.indexOf('chrome') >= 0) || (ua.indexOf('chromium') >= 0) || (ua.indexOf('google') >= 0) ) {
        // webkit, use HTML5
        watchVideoEx = playVideoHTML5;
    }
    else {
        // gecko/other, use Flash
        watchVideoEx = playVideo;
    }
    watchVideo = function( url, width, height, autoplay ) {
        session.backgroundRotationInProgress = true;
        if ( navigator.userAgent.indexOf('android') >= 0 ) {
            setWindowURL( url );
        }
        else {
            watchVideoEx( url, width, height, autoplay );
        }
    };
};

// abstraction for a.click event to play videos
var videoClickHandlerA = function( anchor ) {
    
    trace( 'videoClickHandlerA() : ' );
    
    var me = $(anchor);
    var url = $(anchor).attr('href');
    
    // update the current title
    session.pageTitle = $('img', anchor).attr('alt');
    
    // save the current gallery item index for continuous playback
    session.currentVideoIndex = $(anchor).parent('li').prevAll().length;
    
    if ( arguments.length == 2 ) {
        if ( arguments[1] == true ) {
            // save the playlist starting point for circular playback
            session.videoPlaylistIndex = session.currentVideoIndex;
        }
    }
    
    //var clipID = parseInt( $('.clipID', $(anchor)).text() );
    var clipID = parseInt( $('span.clipID', $(me)).text() );
    var directorID = parseInt( $('span.clipDirectorID', $(me)).text() );
    var directorName = $('span.clipDirector', $(me)).text();
    var clipClient = $('span.clipClient', $(me)).text();
    
    //trace( 'videoGallery click handler : setting session clip ID to ' + clipID );
    
    // save the current clip's ID for favoriting
    session.clipID = clipID;
    
    // update the current title
    session.pageTitle = $('img', anchor).attr('alt');
    
    // update actual page title so social share works better
    updatePageTitle( session.pageTitle, directorName, clipExecutiveProducer );
    
    playVideoQuicktime( $(anchor).attr('href'), '', '', true );
    
};

// abstraction for a.click event to play other gallery videos
var videoClickHandlerB = function( anchor ) {
    
    //trace( 'videoClickHandlerB() : init' );
    
    var me = $(anchor);
    var url = $(anchor).attr('href');
    
    //trace( 'videoClickHandlerB()' );
    
    if ( ['directors', 'browse'].indexOf(session.pageType) >= 0 ) {
        
        // save the current gallery item index for continuous playback
        session.currentVideoIndex = $(anchor).parent('li').prevAll().length;
        
        if ( arguments.length == 2 ) {
            if ( arguments[1] == true ) {
                // save the playlist starting point for circular playback
                session.videoPlaylistIndex = session.currentVideoIndex;
            }
        }
        
        // get the clip's ID
        var clipID = parseInt( $('span.clipID', $(me)).text() );
        var directorID = parseInt( $('span.clipDirectorID', $(me)).text() );
        var directorName = $('span.clipDirector', $(me)).text();
        var clipClient = $('span.clipClient', $(me)).text();
        var clipExecutiveProducer = $('span.clipExecutiveProducer', $(me)).text();
        
        // update current name of who did this work (could be director, exec prod, etc.)
        session.creatorName = ( (directorName.length >= 1) ? directorName : clipExecutiveProducer );
        
        // update the current title
        session.pageTitle = $('img', anchor).attr('alt');
        
        // update actual page title so social share works better
        updatePageTitle( session.pageTitle, directorName, clipExecutiveProducer );
        
        // reuse
        var playerVideoInfo = $('dl#playerVideoInfo');
        
        //trace( 'videoClickHandlerB() : session.pageTitle updated to "' + session.pageTitle + '"' );
        
        //trace( 'videoGallery click handler : setting session clip ID to ' + clipID );
        
        // save the current clip's ID for favoriting
        session.clipID = clipID;
        
        // show the director's name
        $('dd.directorName a', playerVideoInfo)
            .attr('href', ('directors.php?id=' + directorID))
            .text( directorName )
            .unbind( 'click ');
        
        // update the link to the director's page
        $('a#moreFromThisDirector', playerVideoInfo).attr(
            'href', ('directors.php?id=' + directorID)
        ).unbind('click');
        
        // show the clip title
        var useClipTitle = $('img', $(me)).attr('alt');
        
        $('dd.clipTitle', playerVideoInfo).text(
            /*$('img', $(me)).attr('alt')*/
            useClipTitle
        );
        
        // update the client view
        $('dd.clipClient', playerVideoInfo).text(
            clipClient
        );
        
        $('dd.clipExecutiveProducer', playerVideoInfo).text(
            clipExecutiveProducer
        );
        
        // show/hide fields if they do/not have content
        
        // clip client
        if ( clipClient.length >= 1 ) {
            $('dd.clipClient').prev('dd.type').show();
        }
        else {
            $('dd.clipClient').prev('dd.type').hide();
        }
        
        // clip director
        if ( directorName.length >= 1 ) {
            $('dd.directorName').prev('dd.type').show();
        }
        else {
            $('dd.directorName').prev('dd.type').hide();
        }
        
        // clip exec prod
        if ( clipExecutiveProducer.length >= 1 ) {
            $('dd.clipExecutiveProducer').prev('dd.type').show();
        }
        else {
            $('dd.clipExecutiveProducer').prev('dd.type').hide();
        }
        
        // show social share buttons, but after the container drops, to reduce flicker
        window.setTimeout( function() {
            $('div#playerSocial').fadeIn( 1000 );
        }, 1000 );
        
    }
    
    // elements to dim when player slides down
    var dimmableItems = 'div#videoGallery, div#browseFilterControlsContainer, div#videoInfo';
    
    // animate the player viewport down (into view)
    $(dimmableItems).fadeTo( 400, 0.6, function() {
        $('div#playerContainer').animate({
            opacity: '1.0',
            filter: 'alpha(opacity=100)',
            top: '0px'
        }, 600, 'easeOutCirc', function() {
            // play the video
            // delayed by 1s to reduce the "video starts playing
            // before animation completes" syndrome
            window.setTimeout( function() {
                
                if ( ['directors', 'browse'].indexOf(session.pageType) >= 0 ) {
                    if ( $(window).height() < settings.switchViewportHeight ) {
                        watchVideo(
                            url, settings.video.smallVideo.width.toString(),
                            settings.video.smallVideo.height.toString(), true
                        );
                    }
                    else if ( $(window).height() >= settings.switchViewportHeight ) {
                        watchVideo(
                            url, settings.video.normalVideo.width.toString(),
                            settings.video.normalVideo.height.toString(), true
                        );
                    }
                }
                
            }, 900 );
        });
    });
    
    updateURLHash( me );
    
};



// preload an image
var failed_preload_images = [],
    failed_preload_images_items = [];
var preloadImage = function( src, callback ) {
    var img = new Image();
    img.onerror = function() {
        trace( 'Error loading image ' + src );
        failed_preload_images.push( {url: src, element: null } );
        trace( '---> ' + failed_preload_images[failed_preload_images.length - 1].url );
        callback();
    };
    img.onload = function() {
        callback();
        //trace( "\tpreload of " + src + ' finished' );
    };
    img.src = src;
};


// call this onresize
// aligns the director's menu and the buzz bar relative to eachother
// optional callback function
var alignDirectorsBuzz = function( /* optional callback */ ) {
    var buzzOffsetLeft = ( parseInt($('div#directors').width()) / 2 );
    var buzzOffsetBottom = ( $('div#buzz').height() + parseInt($('div#buzz').css('bottom')) + 14 );
    // for some reason $.css() wasn't properly forcing these values into place
    // $.animate() seems to do the trick. might be a bug in 1.4
    $('div#directors').animate({
        marginLeft: ('-' + buzzOffsetLeft.toString()),
        bottom: buzzOffsetBottom
    }, 1);
    if ( arguments.length == 1 ) {
        arguments[0]();
    }
    // align the growl message above it
    $('div#growl').animate({
        bottom: ($('div#buzz').height() + $('div#directors').height() + 25) + 'px'
    }, 1000 );
};


// basic slider animation
// first param is step
// note: only goes right->left!
var twitterMarqueeEx = function() {
    // if session is paused, dont stop timer, but skip actual animation
    if ( session.pauseTwitterMarquee ) {
        return;
    }
    var step = 1;
    if ( arguments.length == 1 ) {
        step = arguments[0];
    }
    var span = $('div#buzz ul li#twitter span');
    var leftOffset = parseInt( $(span).css('marginLeft') );
    // reset slider if it reaches the end
    if ( leftOffset <= parseInt('-' + $(span).width()) ) {
        // TODO: maybe this should be "auto" ??
        $(span).css('marginLeft', ((parseInt($(span).width()) + 10) + 'px'));
    }
    // need to recalculate offset now
    leftOffset = parseInt( $(span).css('marginLeft') );
    $('div#buzz ul li#twitter span').css(
        'marginLeft',
        ( (leftOffset - step) + 'px' )
    );
};

// starts the twitter scrolling marquee
// TODO: sliding whole words into view is a little choppy;
//       maybe set the width explicitly to it's container's width??
var startTwitterMarquee = function() {
    // prevent twitter marquee from doubling up
    window.clearInterval( timers.twitterMarquee );
    //trace( 'twitter timer cleared (' + timers.twitterMarquee + ')' );
    // hide UL and show expanded span with no linebreaks
    $('div#buzz ul li#twitter ul').stop(true, true).fadeOut( 100, function() {
        window.clearInterval( timers.twitterMarquee );
        //trace( 'twitter timer cleared (' + timers.twitterMarquee + ')' );
        timers.twitterMarquee = window.setInterval( function() {
            twitterMarqueeEx(1);
        }, 40 );
        $('div#buzz ul li#twitter span').stop(true, true).fadeIn( 100 );
    });
    //debug( 'started twitter marquee : ' + timers.twitterMarquee );
    /*d*//*trace( 'twitterMarquee started' );*/
};



// toggle the Buzz bar to "slim" mode
// hidden param is callback
var toggleBuzzBarSlim = function( /* callback() */ ) {
    
    // prevent any concurrent animation
    session.actionsAnimating = true;
    
    // cache the jQuery query for better performance
    var buzz = $('div#actions div#buzz');
    
    // hide the directors' info bubble (or it will look funny)
    $('div#directorInfo').fadeOut( 100 );
    
    $('div#actions').animate({
        
        bottom: settings.actions.collapsedOffset + 'px'
        
    }, 300, function() {
        
        // flip the toggle button, all sexy like
        $('a#buzzToggle').animate({
            backgroundPosition: '0px 0px'
        }, 200 );
        
        // hide recent news, videos, etc.
        $('li#recentNews, li#featuredVideos', buzz).fadeOut( 200, function() {
            
            // expand the twitter area wider
            $('li#twitter', buzz).animate({
                width: '615px' /*640px*/
            }, {
                queue: true,
                duration: 300,
                complete: function() {
                    
                    $(this).find('h4').fadeOut(200, function() {
                        
                        // DEBUG DEBUG
                        $('li#recentNews, li#featuredVideos', $('div#buzz ul')).fadeOut( 200 );
                        
                        // turn ON twitter marquee goodness
                        startTwitterMarquee();
                        
                        // allow animations again
                        session.actionsAnimating = false;
                        
                        // run the callback function, if exists
                        //if ( arguments.length == 1 ) {
                        //    if ( (typeof arguments[0]) == 'function' ) {
                        //        arguments[0]();
                        //    }
                        //}
                        
                    });
                    
                }
            });
            
        });
        
    });
    
};//toggleBuzzBarSlim()


// toggle the Buzz bar to "full" mode
// hidden param is callback
var toggleBuzzBarFull = function( /* callback() */ ) {
    
    // prevent any concurrent animation
    session.actionsAnimating = true;
    
    var buzz = $('div#actions div#buzz');
    
    // hide the directors' info bubble (or it will look funny)
    $('div#directorInfo').fadeOut( 200 );
    
    // try to stop twitter marquee goodness
    window.clearInterval( timers.twitterMarquee );
    
    //$('li#twitter span', buzz).css('marginLeft', '0px');
    
    // shrink the twitter area back to the list view
    $('li#twitter', buzz).stop(true, false).animate({
        
        width: '25%',
        marginLeft: '0px'
        
    }, {
        queue: true,
        duration: 200,
        complete: function() {
            
            // show the "Twitter" label again
            $(this).find('h4').fadeIn(200, function() {
                
                // show recent news, videos, etc.
                $('li#recentNews, li#featuredVideos', buzz).fadeIn( 200, function() {
                    
                    $('div#actions').animate({
                        
                        // make buzz bar larger (full view)
                        bottom: ( settings.actions.expandedOffset + 'px' )
                        
                    }, 300, function() {
                        
                        // flip the toggle button, all sexy like
                        $('a#buzzToggle').animate({
                            
                            backgroundPosition: '0px -9px'
                            
                        }, 200, function() {
                            
                            window.clearInterval( timers.twitterMarquee );
                            
                            // DEBUG DEBUG
                            $('li#recentNews, li#featuredVideos', $('div#buzz ul')).fadeIn( 200 );
                            
                            // allow animations again
                            session.actionsAnimating = false;
                            
                            // run the callback function, if exists
                            //if ( arguments.length == 1 ) {
                            //    if ( (typeof arguments[0]) == 'function' ) {
                            //        arguments[0]();
                            //    }
                            //}
                            
                        });
                    });
                    
                });
                
            });
            
            // fade out expanded text
            $('div#buzz ul li#twitter span').fadeOut( 200 );
            
            $('div#buzz ul li#twitter ul').fadeIn( 200 );
            
        }
    });
    
};//toggleBuzzBarFull()



//
// cookie management
// gratiously borrowed from http://www.quirksmode.org/js/cookies.html
//
var setCookie = function( name, value, days ) {
    if ( days ) {
        var date = new Date();
        date.setTime( date.getTime() + (days * 24 * 60 * 60 * 1000) );
        var expires = '; expires=' + date.toGMTString();
    }
    else var expires = '';
    document.cookie = name + '=' + value + expires + '; path=/';
};

var getCookie = function( name ) {
    var nameEQ = name + '=';
    var ca = document.cookie.split(';');
    for ( var i = 0; i < ca.length; i++ ) {
        var c = ca[i];
        while ( c.charAt(0) == ' ' ) c = c.substring( 1, c.length );
        if ( c.indexOf(nameEQ) == 0 ) return c.substring( nameEQ.length, c.length );
    }
    return null;
};

var deleteCookie = function( name ) {
    setCookie( name, '', -1 );
};





//
// finds the current page ID from the URL
//
var currentPageID = function() {
    
    var url = window.location.href;
    
    //trace( 'currentPageID() : page URL is ' + url );
    
    var id = -1;
    
    /*if ( (session.pageType == 'browse') && (window.location.href.indexOf('#play:') >= 1) ) {
        id = window.location.href.split('#play:')[1];
        // in case of multiple hash params
        id = ( (id.indexOf('&') >= 0) ? id.split('&')[0] : id );
    }
    else*/ if ( url.indexOf('id=') >= 1 ) {
        id = parseInt( url.split('id=')[1] );
    }
    
    if ( id < 0 ) {
        
        // try to get clipID from session
        id = ( (session.clipID == null) ? -1 : session.clipID );
        
    }
    
    trace( 'currentPageID() : page ID is ' + ( parseInt(id) || -1 ) );
    
    return id;
    
};




//
// adds current page/media item to user's favorites cache
//
var favorite = function() {
    
    /*
        potential things to add:
            [DONE] human readable "title"
            [DONE] video or news ID
            [DONE] current page URL
            [KINDA] maybe director info from below playlist thumbs?
    */
    
    // get existing favorites
    var cf = getCookie( settings.global.cookieName );
    
    // make an empty array or one of existing favorites
    var cfs = (
        (cf == null) ?
        (new Array()) : cf.split('||')
    );
    
    // force check that we have a page title!
    session.pageTitle = ( (session.pageTitle == '') ? document.title : session.pageTitle );
    
    var mediaID = session.clipID;
    var directorID = -1;
    
    if ( session.pageType == 'directors' ) {
        directorID = currentPageID();
    }
    
    //trace( 'initially, mediaID is ' + mediaID );
    
    if ( (mediaID == null) || (mediaID <= 0) ) {
        //trace( 'media is null or not set (' + mediaID + '), setting it to cpid (' + currentPageID() + ')' );
        // this is probably a news page, so just use the URL's ID
        mediaID = currentPageID();
    }
    
    //trace( "mediaID:\t" + mediaID );
    //trace( "directorID:\t" + directorID );
    
    
    // set up our new favorite
    // format is mediaID, directorID, title, type, URL
    var nf = (
        mediaID + ',' +
        directorID + ',' +
        getContentTitle() + ',' +
        /* if a video is playing, even if it's on a directors page, it's a browse type */
        ((session.currentVideo == null) ? session.pageType : 'browse') + ',' +
        encodeURIComponent(window.location.href)
    );
    
    cfs.push( nf );
    
    // save the actual cookie
    setCookie( settings.global.cookieName, cfs.join('||'), 30 );
    
    trace( 'favorite added!' );
    
    trace( 'updating ti UI to reflect changed favorites list...' );
    
    // update the UI to reflect changes
    updateFavoritesMenu();
    
};


// optional 2nd param is hold duration
var growl = function( message ) {
    //if ( !session.backgroundRotationInProgress ) {
        var hold = 3000;
        if ( arguments.length == 2 ) {
            hold = parseInt( arguments[1] );
        }
        var el = $('div#actions div#growl');
        el.html( message );
        el.fadeIn( 300, function() {
            window.setTimeout( function() {
                $('div#actions div#growl').fadeOut( 300 );
            }, hold );
        });
    //}
};


// DEBUG - attempts to get the title of the media you're on
// based on your context, rather than just the page title
// which atm doesnt change much!
var getContentTitle = function() {
    
    var contentTitle = '';
    
    switch ( session.pageType ) {
        
        case 'news':
            trace( 'getContentTitle() : news page found' );
            contentTitle = 'The Institute - News';
            break;
        
        case 'article':
            trace( 'getContentTitle() : news article page found' );
            contentTitle = trim( $('div#newsHeader h1').text() );
            break;
        
        case 'browse':
        case 'directors':
            trace( 'getContentTitle() : browse page found' );
            // this is auto set when a video plays
            // if they haven't played a video, default to 'The Institute - Video Gallery'
            if ( session.currentVideo == null ) {
                // just get director's name
                contentTitle = getCurrentDirector();
            }
            else {
                // get the current video and director's name
                contentTitle = /*session.currentVideo*/ /*session.pageTitle*/ (
                    (session.pageTitle == 'The Institute') ?
                    'The Institute - Video Gallery' : (getCurrentDirector() + ' - ' + session.pageTitle)
                );
            }
            break;
        
        default:
            //return session.pageTitle;
            break;
        
    }
    
    // DEBUG force "the institute" before all titles?
    //if ( contentTitle != '' ) {
    //    if ( contentTitle.substring(0, 'The Institute'.length) != 'The Institute' ) {
    //        contentTitle = ('The Institute - ' + contentTitle );
    //    }
    //}
    
    trace(
        'getContentTitle() : content title is "' +
        ( (contentTitle != '') ? contentTitle : session.pageTitle ) + '"'
    );
    
    return ( (contentTitle != '') ? contentTitle : session.pageTitle );
    
};


// IF a video is playing, scrapes the current director info from the info area
var getCurrentDirector = function() {
    
    var d = trim( $(
        'div#content div#playerContainer ' +
        'dl#playerVideoInfo dd.directorName'
    ).text() );
    
    return ( (d != '') ? d : trim($('h1.sectionTitle').text()) );
    
};


//
// removes selected page/media item from user's favorites cache
//
var unfavorite = function( link ) {
    
    // get favorite index from anchor's rel attribute
    var fid = parseInt( $(link).attr('rel') );
    
    // make sure it's a valid number
    if ( isNaN(fid) || (fid <= -1) ) {
        return;
    }
    
    // remove favorite
    var favs = favorites();
    
    //trace( "removing favorite:\n" + favs[fid].split(',').join("\n") );
    
    favs.splice( fid, 1 );
    
    //if ( window.location.href.toString().toLowerCase().indexOf('jsdebug=true') >= 1 ) {
    //    alert( favs.join("\n") );
    //}
    
    setCookie( 'tifavs', favs.join('||'), 30 );
    
    // remove the item from display
    $(link)
        .parent('li')
        .css('backgroundColor', '#ff0000')
        .fadeOut(250)
        .remove();
    
    // update the summary view
    updateFavoritesMenu();
    
};


//
// list current favorites
//
var favorites = function() {
    
    // get existing favorites
    var cf = getCookie( settings.global.cookieName );
    
    //trace( 'fn.favorites : cookie current: ' + cf );
    
    // make an empty array or one of existing favorites
    return ( (cf == null) ? [] : cf.split('||') );
    
};


var saveFavorites = function() {
    
    $.get( prefixURL + 'favorites.php', {
        ajax: 'true',
        action: 'save'
    }, function(response) {
        response = eval('(' + response + ')');
        if ( response.result != true ) {
            growl( response.message );
        }
        else {
            growl( response.message + '... You can now share them via email.' );
            window.setTimeout( function() {
                $('a#favoritesSendEmail').trigger( 'click' );
            }, 400 );
        }
        
    }, 'text/html' );
    
};

var updateFavoritesMenu = function() {
    
    var favs = favorites();
    var news = [];
    var videos = [];
    var directors = [];
    
    if ( favs.length >= 1 ) {
        
        //trace( 'found ' + favs.length + ' favorites' );
        
        // go in reverse so newest favs are @ top
        for ( var i = (favs.length - 1); i > -1; i-- ) {
            
            //trace( 'favs[' + i + ']: ' + favs[i] );
            //s += ( "\n" + ff[1] );
            
            var ff = favs[i].split(',');
            
            //trace( 'updateFavorites - type found: ' + ff[3] );
            
            if ( (ff[3] == 'news') || (ff[3] == 'article') ) {
                news.push( ff );
                //trace( 'pushed ' + ff[1] + ' to news' );
            }
            else if ( (ff[3] == 'directors') ) {
                directors.push( ff );
            }
            else if ( ff[3] == 'browse' ) {
                videos.push( ff );
                //trace( 'pushed ' + ff + ' to videos' );
            }
            else {
                trace( 'unknown fav: ' + favs[i] );
            }
            
        }
        
        // populate hover drop
        var fs = $('ul#social li#favorites div#favoritesSummary');
        var fs_videos =  $('ul#favoritesSummaryVideos', fs);
        var fs_news = $('ul#favoritesSummaryNews', fs);
        var fs_directors = $('ul#favoritesSummaryDirectors', fs);
        var fs_viewAllVideos = $('span#viewAllVideos a span.allNum', fs);
        var fs_viewAllNews = $('span#viewAllNews a span.allNum', fs);
        var fs_viewAllDirectors = $('span#viewAllDirectors a span.allNum', fs);
        
        // clear current summary
        fs_videos.empty();
        fs_news.empty();
        fs_directors.empty();
        fs_viewAllVideos.empty();
        fs_viewAllNews.empty();
        fs_viewAllDirectors.empty();
        
        for ( var i = 0; i < videos.length; i++ ) {
            if ( i < 3 ) {
                fs_videos.html(
                    fs_videos.html() +
                    '<li><a href="' + unescape(videos[i][4]) + '">' + videos[i][2] + '</a></li>'
                );
            }
        }
        
        for ( var i = 0; i < news.length; i++ ) {
            if ( i < 3 ) {
                fs_news.html(
                    fs_news.html() +
                    '<li><a href="' + unescape(news[i][4]) + '">' + news[i][2] + '</a></li>'
                );
            }
        }
        
        for ( var i = 0; i < directors.length; i++ ) {
            if ( i < 3 ) {
                fs_directors.html(
                    fs_directors.html() +
                    '<li><a href="' + unescape(directors[i][4]) + '">' + directors[i][2] + '</a></li>'
                );
            }
        }
        
        // update the totals count
        fs_viewAllVideos.html( (videos.length >= 4) ? videos.length : '' );
        fs_viewAllNews.html( (news.length >= 4) ? news.length : '' );
        fs_viewAllDirectors.html( (directors.length >= 4) ? directors.length : '' );
        
        //trace( 'populated favorites summary list' );
        
    }
    
};



//
// import tweets from a Twitter feed (this starts the process)
//
// @param (hidden) (int) max number of tweets to pull in (defaults to 5)
//
var importTweets = function( /* limit */ ) {
    
    // default limit
    var limit = 5;
    
    if ( arguments.length >= 1 ) {
        limit = parseInt( arguments[1] );
        limit = ( (limit > 0) ? limit : 5 );
    }
    
    var script = document.createElement( 'script' );
    
    script.setAttribute(
        'src', 'http://www.twitter.com/statuses/user_timeline/' +
        settings.global.twitterID + '.json?callback=twitterCallback&count=' + limit + '&cb=' + Math.random()
    );
    
    // when this script initializes, it will call the callback function 'twitterCallback'
    document.getElementsByTagName('body')[0].appendChild( script );
    
};




/*
 * resize dimensions, keeping aspect ratio
 * leave out either nw or nh to calculate that dimension
 */
var resizeKeepAspectRatio = function( ow, oh , nw, nh ) {
    var aspectRatio = ( ow / oh );
    if ( nw > nh ) {
        // alter the height; the width stays the same
        nh = Math.round( nw * (1 / aspectRatio) );
    }
    else {
        // alter the width; the height stays the same
        nw = Math.round( nh * aspectRatio );
    }
    return {
        width: nw,
        height: nh
    };
};


//
// callback for pulling in TI feed from Twitter
//
// @param tweetsJSON (JSON data) array of tweets (Twitter's API fills this in automatically)
//
// @notes - 121546688 TI's code (public)
//
var twitterCallback = function( tweetsJSON ) {
    
    // alert( tweets.length + ' tweets loaded' );
    
    for ( var i = 0; i < tweetsJSON.length; i++ ) {
        //session.tweets.push( tweetsJSON[i].text );
        session.tweets.push( tweetsJSON[i].text.substring(0, 50) + '...' );
    }
    
    /*alert(
        session.tweets.length +
        ' tweets loaded' + "\n\n" +
        session.tweets.join("\n")
    );*/
    
    // add the tweets to the buzz bar
    $('div#buzz ul li#twitter').html(
        '<h4>TWITTER <a href="http://www.twitter.com/theinstitutela" target="_blank">VIEW ALL</a></h4>' + "\n" +
        "<ul>\n\t<li>" +
        session.tweets.join("</li>\n<li>")
        + "</li>\n</ul>\n" +
        /* same content, no breaks - for "slim" buzz bar scroller */
        '<span>' + session.tweets.join('&nbsp;&nbsp;&nbsp;&nbsp;') + '</span>'
    ).find('span').hide();
    
};


//
// just a wrapper for setting height & applying jScrollPane
//
var enableCustomScrollbars = function() {
    
    /*
        optional parameters (from http://www.kelvinluck.com/assets/jquery/jScrollPane/jScrollPane.html)
        
        * scrollbarWidth [int] - the width of the created scrollbar in pixels (defaults to 10)
        * scrollbarMargin [int] - the margin to leave to the left of the scrollbar in pixels (defaults to 5)
        * wheelSpeed [int] - controls how fast the mouse wheel makes the content scroll in pixels (defaults to 18)
        * showArrows [boolean] - controls whether to display arrows for the user to scroll with (defaults to false)
        * arrowSize [int] - the height of the arrow buttons if showArrows=true (calculated from CSS if not provided)
        * animateTo [boolean] - whether to animate when calling scrollTo and scrollBy (defaults to false)
        * dragMinHeight [int] - the minimum height to allow the drag bar to be (defaults to 0)
        * dragMaxHeight [int] - the maximum height to allow the drag bar to be (defaults to 99999!)
        * animateInterval [int] - The interval in milliseconds to update an animating scrollPane (default 100)
        * animateStep [int] - The amount to divide the remaining scroll distance by when animating (default 3)
        * maintainPosition [boolean] - Whether you want the contents of the scroll pane to maintain it's position when you re-initialise it - so it doesn't scroll as you add more content (default true)
        * scrollbarOnLeft [boolean] - Whether the scrollbar should appear on the left hand side of the panes content (make sure your CSS also reflects this)
        * reinitialiseOnImageLoad [boolean] - Whether the jScrollPane should automatically re-initialise itself when any contained images are loaded (defaults to false)
    */

    
    // force container's height to match actual content height
    //$('.scrollable').height( $('div#stage').height() );
    
    // enable scrollbars!
    
    // quick sanity check to make sure there are enough elements in the list - only 1 will break!
    //if ( $('div#videoGallery ul li a.videoLink').length >= 2 ) {
        $('.scrollable').jScrollPane({
            showArrows: true,
            scrollbarWidth: 10,
            scrollbarMargin: 5
        }/*, function() { trace('jscroll callback!'); }*/);
        
        // DEBUG - browse thumbs not loading until resize event.. so do this???
        //$(window).resize();
        
    //}
    //else {
    if ( $('div#videoGallery ul li a.videoLink').length <= 1 ) {
        
        // this is a little kitchy but helps for directors with only 1 clip
        if ( session.pageType == 'directors' ) {
            $('div#videoGallery ul').css('marginLeft', '12px');
            $('div.jScrollPaneContainer').css('height', '145px !important');
        }
        
    }
    
};



var reinitializeCustomScrollbars = function() {
    
    if ( !session.viewportResizing ) {
        session.viewportResizing = true;
        dynamicHeighten();
        if ( (session.pageType == 'browse') || ($('div#videoGallery ul li a.videoLink').length >= 2) ) {
            $('.scrollable').jScrollPane();
        }
        session.viewportResizing = false;
    }
    
};


var dynamicHeighten = function() {
    
    //trace(
    //    'dynamicHeighten():' + "\n" +
    //    'current window height: ' + $(window).height() + "\n" +
    //    'current stage height: ' + $('div#stage').height() + "\n" +
    //    'switchViewportHeight: ' + settings.switchViewportHeight + "\n" +
    //    'smallViewportHeight: ' + settings.smallViewportHeight + "\n" +
    //    'normalViewportHeight: ' + settings.normalViewportHeight
    //);
    
    // adjust the main content area's size for tiny screens
    if ( ['directors', 'browse'].indexOf(session.pageType) >= 0 ) {
        
        //v1: var dse = $('div#stage, div#browseWrapper, div#playerContainer'); // dynamically sized elements
        //v2: var dse = $('div#stage, div.jScrollPaneContainer, div#playerContainer'); // dynamically sized elements
        //v3:
        var dse = $('div#stage'); // dynamically sized elements
        if ( session.pageType == 'directors' ) {
            dse = $('div#stage, div#playerContainer');
        }
        else {
            dse = $('div#stage, div.jScrollPaneContainer, div#playerContainer');
        }
        
        if ( $(window).height() < settings.switchViewportHeight ) {
            
            //trace( 'dynamicHeighten() : 01' );
            
            // to prevent recursion and reapplying the same CSS values,
            // only change the size of the viewport if it's not already above/below it's appropriate value
            if ( $('div#stage').height() > settings.smallViewportHeight ) {
                
                //trace( 'dynamicHeighten() : 01-A' );
                
                //trace( 'switching to small viewport, height: ' + settings.smallViewportHeight );
                
                //session.contentHeight = settings.smallViewportHeight;
                dse.height( settings.smallViewportHeight );
                
                // adjust the actual video player size
                //var playerW = $('object, embed').width();
                //var playerH = $('object, embed').height();
                //var playerSize = resizeKeepAspectRatio( playerW, playerH, 0, settings.video.smallVideo.height
                //$('object, embed, video, div#player')
                //    .width(settings.video.smallVideo.width)
                //    .height(settings.video.smallVideo.height);
                //$('object, embed')
                $('object, embed, video, div#player')
                    .width(settings.video.smallVideo.width)
                    .height(settings.video.smallVideo.height);
                //// reposition video, since resizing it will cause it to jump up and hide
                //$('div#playerContainer').css('top', '0px');
                
                // reinit html5 player
                if ( session.html5player != null ) {
                    /*session.html5player = */VideoJS.setup("html5player");
                    //session.currentVideo = session.html5player;
                }
                
                // jscroll needs just a little less height than the real content so the scrollbars stay within the container
                $('div.jScrollPaneContainer').height( settings.smallViewportHeight - 15 );
                $('div#playerContainer')
                    .height( settings.smallViewportHeight + 10 )
                    .stop( true, true )
                    .css( 'top', ((session.currentVideo == null) ? '-600px' : '0px') );
                    //.css( 'top', '-500px' );
                
                $('div#player').css('marginTop', '0px');
                
                $('dl#playerVideoInfo').css({
                    width: '195px',
                    bottom: '15px'
                });
                $('div#playerSocial').css({
                    bottom: '20px',
                    width: '195px'
                });
                
                // reinitialize jScrollPane
                //enableCustomScrollbars();
                reinitializeCustomScrollbars();
                
            }
            
        }
        else if ( $(window).height() >= settings.normalViewportHeight ) {
            
            //trace( 'dynamicHeighten() : 02' );
            
            if ( $('div#stage').height() < settings.normalViewportHeight ) {
                
                //trace( 'dynamicHeighten() : 02-A' );
                
                //trace( 'switching to normal viewport, height: ' + settings.normalViewportHeight );
                
                dse.height( settings.normalViewportHeight );
                
                // jscroll needs just a little less height than the real content so the scrollbars stay within the container
                $('div.jScrollPaneContainer').height( settings.normalViewportHeight - 15 );
                $('div#playerContainer')
                    .height( settings.normalViewportHeight + 15 )
                    .stop( true, true )
                    .css( 'top', ((session.currentVideo == null) ? '-600px' : '0px') );
                
                // adjust the actual video player size
                //$('object, embed, video, div#player')
                //    .width( settings.video.normalVideo.width )
                //    .height( $('#playerContainer').height() - 4 );
                //$('object, embed')
                $('object, embed, video, div#player')
                    .width( settings.video.normalVideo.width )
                    .height( settings.video.normalVideo.height );
                    //.height( $('#playerContainer').height() - 4 );
                
                $('div#player').css('marginTop', '48px');
                
                $('dl#playerVideoInfo').css({
                    width: '120px',
                    bottom: '46px'
                });
                $('div#playerSocial').css({
                    width: '120px',
                    bottom: '51px'
                });
                
                // reinit html5 player
                if ( session.html5player != null ) {
                    /*session.html5player = */VideoJS.setup("html5player");
                    //session.currentVideo = session.html5player;
                }
                
                // reinitialize jScrollPane
                //enableCustomScrollbars();
                reinitializeCustomScrollbars();
                
            }
            //else if ( $('div#player').height() < ($('div#playerContainer').height() - 4) ) {
            //    trace( 'adjusting the actual player size' );
            //    // adjust the actual video player size
            //    //$('object, embed, video, div#player')
            //    //    .width( settings.video.normalVideo.width )
            //    //    .height( $('#playerContainer').height() - 4 );
            //    var ar = resizeKeepAspectRatio(
            //        settings.video.normalVideo.width,
            //        settings.video.normalVideo.height, 704, -1
            //    );
            //    $('video').width(ar.width).height(ar.height);
            //}
            
        }
        
    }
    
};


// start preloading ALL feature backgrounds to speed things up
var preloadAllGalleryBackgrounds_RunOnce = false;
var preloadAllGalleryBackgrounds = function() {
    if ( !preloadAllGalleryBackgrounds_RunOnce && settings.actions.preloadAllGalleryBackgrounds ) {
        //trace( session.backgroundGallery.length + ' background gallery images found.' );
        for ( var i = 0; i < session.backgroundGallery.length; i++ ) {
            //trace(
            //    'preloading background image (' + i + '/' +
            //    session.backgroundGallery.length + '): '
            //    + prefixURL + 'features/' + session.backgroundGallery[i]
            //);
            preloadImage( prefixURL + 'features/' + session.backgroundGallery[i], function() {
                // nada
            } );
        }
    }
    preloadAllGalleryBackgrounds_RunOnce = true;
};


var getRandomGalleryImage = function() {
    
    // if the cache is full, we've shown every image once
    // so flush the cache and start the loop over
    if ( session.backgroundGalleryCache.length >= session.backgroundGallery.length ) {
        session.backgroundGalleryCache = [];
    }
    
    // choose a random image
    var randomIndex = Math.round( Math.random() * session.backgroundGallery.length );
    
    // make sure we don't use a previously shown image
    while ( session.backgroundGalleryCache.indexOf(randomIndex) >= 0 ) {
        // choose a different image
        randomIndex = Math.round( Math.random() * session.backgroundGallery.length );
    }
    
    // cache the image so we don't use it again for this loop
    session.backgroundGalleryCache.push( randomIndex );
    
    return randomIndex;
    
};





var preloadGalleryRecursive = function( index, callback ) {
    //trace( 'preloadGalleryRecursive() : preloading gallery (' + session.galleryImages.length + ')' );
    //trace( "\t[" + index + '] ' + $(session.galleryImages[index]).attr('src') );
    preloadImage( $(session.galleryImages[index]).attr('src'), function() {
        if ( index >= (session.galleryImages.length - 1) ) {
            //trace( 'finished preloading gallery images' );
            //trace( 'running callback...' );
            callback();
        }
        else {
            //trace( 'preloading gallery image: ' + $(session.galleryImages[index]).attr('src') );
            preloadGalleryRecursive( (index + 1), callback );
        }
    });
};


var windowResizeCallback = function() {
    
    //trace( 'windowResizeCallback() : init' );
    
    // change this to affect how far from the top it can go
    var maxTopOffset = 200;
    
    // change this to affect the offset from "true centering" for visual appeal
    //var voffset = 0;//now in settings
    var voffset = (
        (session.pageType == 'directors') ? 0 : 0
    );
    
    // calculate new margin
    var newMargin = ( (($(window).height() / 2) - $('div#stage').height() / 2) - voffset );
    
    //trace( 'windowResizeCallback() : new margin @ ' + newMargin );
    
    // the stage, when browser is large or fullscreen, will never fade in the main content
    //trace( 'stage top is @ ' + parseInt($('div#stage').css('marginTop')) );
    //trace( ' // ' + (parseInt($('div#stage').css('marginTop')) <= -1000)?'fadein':'allOK' );
    //if ( parseInt($('div#stage').css('marginTop')) <= -1000 ) {
    //    trace( 'fading in started || $("div#stage").css( "marginTop", ("'+newMargin+'px'+'") ).fadeIn(1500);' );
    //    // the page must be in maximized view, so force the main content to show
    //    $('div#stage').fadeOut(1, function() {
    //        //$('div#stage').css( 'marginTop', (newMargin + 'px') ).fadeIn(1500);
    //        $('div#stage').css( 'marginTop', (newMargin + 'px') ).animate({
    //            opacity: '1.0'
    //        }, 1500 );
    //    });
    //}
    //else {
    //    trace( 'windowResizeCallback() : stage doesn"t need to be moved' );
    //}
    
    // center the main content container, but don't let it go
    // down too far in the page (past maxTopOffset)
    //if ( (newMargin < maxTopOffset) || (parseInt($('div#stage').css('marginTop')) < newMargin) ) {
    
    //if ( newMargin < maxTopOffset ) {
        
        //trace( 'windowResizeCallback() : setting new marginTop @ ' + newMargin + 'px' );
        $('div#stage').css( 'margin-top', (newMargin + 'px') );
        
        // tried this with animate, and while it's much smoother, it KEEPS animating and doubling up
        //$('div#stage').animate({
        //    marginTop: (newMargin + 'px')
        //}, 200 );
        
    //}
    
    // dynamically adjust the height of the main content container to accomodate smaller screens. yes, really.
    dynamicHeighten();
    
};
var assignWindowResizeEvent = function() {
    
    $(window).resize(function() {
        windowResizeCallback();
    });
    
};







// handle ajax-style hashed URLs if applicable
var handleHashedURL = function() {
    
    //trace( 'handleHashedURL() : init "' + window.location.href + '"' );
    
    if ( window.location.href.indexOf('#') ) {
        
        // get the last hashed thing, in case of multiple hashes
        var hash = window.location.href.split('#').pop();
        
        // only use the first hashed command for now
        var action = hash.split('&')[0];
        var target = action.split(':');
        
        // EXAMPLE
        // given the url http://.../#play=5
        // action would now == [play=5]
        // target would now == [play, 5]
        
        action = target[0];
        target = target[1];
        
        // EXAMPLE
        // action would now == 'play'
        // target would now == '5'
        
        switch ( action ) {
            
            case 'play':
                if ( parseInt(target) >= 1 ) {
                    trace( 'handleHashedURL() : URL hash says play this video: ' + target );
                    if ( session.clipID == target ) {
                        trace( 'handleHashedURL() : that video is already playing; nevermind' );
                    }
                    else {
                        // find all videos on the page
                        $('a.videoLink').each( function() {
                            // find the video requested, by ID
                            if ( trim($('span.clipID', $(this)).text()) == target ) {
                                // grab the video URL
                                var fauxLink = $(this);
                                // wait for the page to finish being rendered
                                $('div#stage').ready( function() {
                                    // wait yet a tiny bit more, to make sure things are layed out properly
                                    window.setTimeout( function() {
                                        trace( 'playing vid auto via hash : ' + $(fauxLink).attr('href') );
                                        videoClickHandlerB( fauxLink );
                                    }, 1000 );
                                });
                                // stop looping
                                return false;
                            }
                        });
                    }
                };
                break;
            
            
        }
        
        
    }
    
}; //hashed URL


/*
 * called on click to update window URL, social share icons, etc.
 * @param anchor {DOMElement A | null} anchor clicked to play video or null for default
 *
 */
var updateURLHash = function( anchor ) {
    
    if ( anchor === null ) {
        
        // just update to the default URL (no clip ID, etc.)
        //if ( session.currentPageURL.indexOf('play=') >= 0 ) {
        //    var uurl = session.currentPageURL.split('play=');
        //    if ( uurl[1].indexOf('&') >= 0 ) {
        //        uurl[1] = uurl[1].substring( uurl[1].indexOf('&') );
        //    }
        //    else if ( uurl[1].indexOf('#') >= 0 ) {
        //        uurl[1] = uurl[1].substring( uurl[1].indexOf('#') );
        //    }
        //    session.currentPageURL = uurl.join('');
        //}
        //
        //trace( 'page url updated to ' + session.currentPageURL );
        
        window.location = session.currentPageURL + '#';
        setWindowURL( session.currentPageURL + '#' );
        
        updateSocialSharingButtons( session.currentPageURL + '#' );
        
    }
    else {
        
        var link = $(anchor);
        var hash = '#';
        
        //trace( 'updateURLHash() : link @ ' + link );
        //trace( 'updateURLHash() : link has class? ' + (link.hasClass('videoLink')?'yes':'no') );
        
        if ( link.hasClass('videoLink') ) {
            
            var clipID = trim( $('span.clipID', link).text() );
            
            if ( (clipID.length >= 1) && (parseInt(clipID) >= 1) ) {
                
                hash += ( 'play:' + clipID );
                
                link = ( session.currentPageURL + hash );
                
                // update the page URL
                window.location = link;
                setWindowURL( link );
                
                updateSocialSharingButtons( link );
                
            }
            
        }
        
    }
    
};


var updateSocialSharingButtons = function( url ) {
    
    /* twitter sample html
      <a href="http://twitter.com/share" class="twitter-share-button"
        data-url="http://www.theinstitute.tv/browse.php"
        data-via="twitterapi"
        data-text="The Institute"
        data-related="anywhere:The Javascript API"
        data-count="horizontal">Tweet</a> */
    
    /* facebook like sample html
      <iframe
            src="http://www.facebook.com/plugins/like.php?
                href=http%3A%2F%2Fwww.theinstitute.tv%2F
                &amp;layout=button_count
                &amp;show_faces=false
                &amp;width=100
                &amp;action=like
                &amp;font=lucida+grande
                &amp;colorscheme=dark
                &amp;height=21"
            scrolling="no"
            frameborder="0"
            style="border:none; overflow:hidden; width:100px; height:21px;"
            allowTransparency="true">
        </iframe> */
    
    var fburl = ( ((url.indexOf('#play:') <= -1) && (url.indexOf('play=') <= -1)) ? url :
        ( (url.split('#play:')[0].indexOf('?') >= 0) ?
            (url.split('#play:')[0] + '&') :
            (url.split('#play:')[0] + '?')
        ) + 'play=' + url.split('#play:')[1]
    );
    //trace('fburl: ' + fburl);
    
    // facebook share this
    $(/*'a#shareFavsFacebook,*/ 'div.facebookShareIcon a[name="fb_share"]').attr(
        'href', 'http://www.facebook.com/sharer.php?u=' + encodeURIComponent(fburl) + '&src=sp'
    );
    
    // facebook LIKE
    $('div.facebookLikeIcon').empty().html(
        $('<iframe ' +
            'src="http://www.facebook.com/plugins/like.php?' +
                'href=' + encodeURIComponent(fburl) +
                '&amp;layout=standard' +
                '&amp;show_faces=false' +
                '&amp;width=50' +
                '&amp;action=like' +
                '&amp;font=lucida+grande' +
                '&amp;colorscheme=dark' +
                '&amp;height=21" ' +
            'scrolling="no" ' +
            'frameborder="0" ' +
            'style="border:none; overflow:hidden; width:50px; height:21px;" ' +
            'allowTransparency="true">' +
        '</iframe>')
    );
    
    // build the default tweet text that pops up
    // order the titles will fall back to is:
    //      Director - Clip Title
    //      Executive Producer - Clip Title
    //      News Article Title
    //      The Institute
    var shareTitle = ( (session.creatorName == null) ? 'The Institute' : session.creatorName );
    shareTitle += (
        ((session.pageTitle == null) || (session.pageTitle == 'The Institute')) ?
        '' : (' - ' + session.pageTitle)
    );
    
    if ( (session.pageType == 'news') || (session.pageType == 'article') ) {
        shareTitle = document.title;
    }
    
    // reinitialize twitter share icon
    // this MUST be done, otherwise even if the A params are changed, the
    // JS will override it - their whole library seems to need to be
    // reinstantiated each time. a performance cost, but neat title setting hack!
    $('div.twitterShareIcon').empty().html(
        $('<script src="http://platform.twitter.com/widgets.js" type="text/javascript"></script>' +
            '<div>' +
               '<a href="http://twitter.com/share" class="twitter-share-button"' +
                  'data-url="' + url + '"' +
                  /*'data-via="twitterapi"' +*/
                  'data-text="' + shareTitle + '"' +
                  'data-related="anywhere:The Javascript API"' +
                  'data-count="none">Tweet</a>' +
            '</div>'
        )
    );
    
};



/////////////////////////////////////////////////////////////////////


$(function() {
    
    trace( 'hello.' );
    
    if ( $.browser.msie ) {
        
        // NOTE: jQuery's event binding won't work here
        /*
        addEventClassic( window, 'error', function(e) {
            var s = '';
            for ( var p in e ) {
                s += "\n" + p + ' = ' + e[p];
            }
            alert( 'an error happened: ' + s );
        }, false );
        */
        
        try { window.onerror = function() { return false; }; }
        catch (woe) {}
        
        try {
            addEventClassic( window, 'error', function(e) {
                try { e.preventDefault(); }
                catch (woe2) {}
                return false;
            }, false );
        }
        catch (woe3) {}
        
    }
    
    
    /* so IE stops whining */
    sessionID = getCookie('tifavs_id');
    
    trace( 'favorites ID: ' + sessionID );
    
    
    // keep the original URL without any hashes, etc.
    if ( window.location.href.indexOf('#') >= 1 ) {
        session.currentPageURL = window.location.href.split('#')[0];
    }
    
    
    // catch-all for faux links
    $('a').each( function() {
        if ( $(this).attr('href') == '#' ) {
            $(this).click( function(e) {
                e.preventDefault();
            });
        }
    });
    
    
    // prevent freak keypress accidents
    var keys = [
        32 /* spacebar */,
        37 /* left arrow */,
        38 /* up arrow */,
        39 /* right arrow */,
        40 /* down arrow */
    ];
    var keyElementNodes = [
        'INPUT', 'TEXTAREA'
    ];
    var keyElementTypes = [
        '[object HTMLInputElement]',
        '[object HTMLTextAreaElement]'
    ];
    $(window).keydown( function(key) {
        //trace( 'altKey: ' + (key.altKey ? 'yes' : 'no') );
        // allow alt-left and alt-right for navigation!
        if ( !(key.altKey && ([37, 39].indexOf(key.keyCode) >= 0)) ) {
            if ( keys.indexOf(key.keyCode) >= 0 ) {
                //trace( 'active element: ' + document.activeElement.nodeName + '/' + document.activeElement.toString() );
                //INPUT/[object HTMLInputElement]
                // don't prevent people from typing in textboxes! haha
                if (
                    (keyElementNodes.indexOf(document.activeElement.nodeName) <= -1)
                    && (keyElementTypes.indexOf(document.activeElement.toString()) <= -1) ) {
                    key.preventDefault();
                    return false;
                }
            } //}else{trace('alt+'+((key.keyCode==37)?'left':'right')+' pressed');}
        }
        //trace( 'key pressed: ' + key.keyCode.toString() );
        return true;
    });
    
    // determine page type for later use
    session.pageType = $('body').attr('rel');
    
    session.pageWidth = $(window).width();
    session.pageHeight = $(window).height();
    
    
    // global collection of gallery images from browse or directors
    session.galleryImages = $('div#stage img' /* TODO: add directors page in here too? */ );
    
    
    // stupid browser
    if ( $.browser.msie ) {
        //$('div#stage').css('marginTop', '0px');
        //$('div#stage img').height( $('div#stage img').parent().height() );
    }
    
    
    // enable vertical auto alignment
    if ( ['news', 'article', 'directors', 'browse', 'admin'].indexOf(session.pageType) >= 0 ) {
        
        if ( session.pageType != 'browse' ) {
            
            assignWindowResizeEvent();
            
        }
        else {
            
            //
            // preload the browse page gallery view and fade it in. YES.
            //
            //trace( 'preloadGalleryRecursive() : init' );
            if ( $.browser.msie ) {
                
                assignWindowResizeEvent();
                if ( !$.browser.msie ) {
                    $('div#stage').fadeOut(1, function() {
                        $(window).trigger('resize');
                        $('img#loading').fadeOut( 1000 );
                        $('div#stage').fadeIn( 1500, function() {
                            
                            trace( 'fade in should be complete' );
                            
                            // allow ajax-style hashed URLs to playback video, etc.
                            //if ( session.hashedVideo !== null ) {
                                
                                trace( 'handling hashed video' );
                                handleHashedURL();
                                
                            //}
                            
                        });
                    });
                }
                else if ( $.browser.msie || (session.pageType == 'directors') ) {
                    $('div#stage').ready( function() {
                        handleHashedURL();
                    });
                }
                
            }
            else {
                preloadGalleryRecursive( 0, function() {
                    //trace( 'preloadGalleryRecursive() : callback triggered' );
                    // DON'T DO THIS IT WILL CAUSE THE DREADED "double bounc" !! windowResizeCallback();
                    assignWindowResizeEvent();
                    if ( !$.browser.msie ) {
                        $('div#stage').fadeOut(1, function() {
                            $(window).trigger('resize');
                            $('img#loading').fadeOut( 1000 );
                            $('div#stage').fadeIn( 1500, function() {
                                
                                trace( 'fade in should be complete' );
                                
                                // 2011-07-14 broken images coming from Simian again... trying to
                                // hide any that didn't load properly
                                $('div#browseWrapper').find('ul').each( function() {
                                    $(this).find('li').each( function() {
                                        var li = $(this);
                                        li.find('img').each( function() {
                                            var img_url = $(this).attr('src');
                                            //trace( 'checking for broken images ' + i + '/' + img.length + ' @ ' + img_url );
                                            for ( var j = 0, jm = failed_preload_images.length; j < jm; j++ ) {
                                                if ( failed_preload_images[j].url == img_url ) {
                                                    //trace( '--DEBUG-- ' + $(this).parent('li') );
                                                    trace( 'found broken image @ ' + img_url );
                                                    ////$(img[i]).hide();
                                                    //li.hide();
                                                    //trace( 'assigning ' + $(img[i]).parent('li') );
                                                    //failed_preload_images[j].element = $(img[i]).parent('li');
                                                    ////trace( li );
                                                    
                                                    //failed_preload_images[j].element = $(this).parent('li');
                                                    $(this).addClass( 'brokenimage' );
                                                    
                                                    
                                                    //for prod
                                                    $(this).parents('li').remove();
                                                }
                                            }
                                        });
                                    });
                                });
                                
                                // just a test to make sure they're being removed properly
                                //window.setTimeout( function() {
                                //    trace( 'hiding broken images' );
                                //    //for ( var i = 0; i < failed_preload_images.length; i++ ) {
                                //    //    trace(
                                //    //        'hiding broken image: ' +
                                //    //        failed_preload_images[i].url +
                                //    //        ' / ' + (typeof failed_preload_images[i].element)
                                //    //    );
                                //    //    $(failed_preload_images[i].element).fadeOut('slow');
                                //    //}
                                //    //$(failed_preload_images).each( function() {
                                //    //    trace(
                                //    //        'hiding broken image: ' +
                                //    //        failed_preload_images[i].url +
                                //    //        ' / ' + (typeof failed_preload_images[i].element)
                                //    //    );
                                //    //    $(failed_preload_images[i].element).fadeOut('slow');
                                //    //});
                                //    $('img.brokenimage').each( function() {
                                //        $(this).parents('li').fadeOut('slow');
                                //    });
                                //}, 2000);
                                
                                // allow ajax-style hashed URLs to playback video, etc.
                                //if ( session.hashedVideo !== null ) {
                                    
                                    trace( 'handling hashed video' );
                                    handleHashedURL();
                                    
                                //}
                                
                            });
                        });
                    }
                    else if ( $.browser.msie || (session.pageType == 'directors') ) {
                        $('div#stage').ready( function() {
                            handleHashedURL();
                        });
                    }
                });
            }
            
        }
        
    }
    
    
    //
    // set the default title for the current page,
    // if on directors or news
    //
    // TODO: this should maybe be encapsulated somewhere
    //
    //
    
    var currentPage = $('body').attr('rel');
    var currentPageTitle = undefined;
    
    
    // determine which player to use for video playback
    detectPlatform();
    
    // slide in the news article title from the top
    if ( ['news', 'article'].indexOf(currentPage) ) {
        $('div#newsHeader')
            .fadeOut(1, function() {
                $(this).animate({
                    top: ('-' + $('div#newsHeader').height())
                }, 1, 'easeOutCirc', function() {
                    $(this).fadeIn(1, function() {
                        $(this).animate({top: '0px'}, 3000);
                    });
                });
            });
    }
    
    
    if ( currentPage == 'news' ) {
        trace( 'page is News' );
        // find the first news item's title
        currentPageTitle = $('ul#newsBrowse li:first-child a').attr('alt');
        trace( 'push page title == ' + currentPageTitle );
    }
    else if ( currentPage == 'article' ) {
        trace( 'page is a News Article' );
        // find the first news item's title
        currentPageTitle = $('div.articleContent h1').text();
        trace( 'push page title == ' + currentPageTitle );
    }
    else if ( currentPage == 'directors' ) {
        trace( 'page is Directors' );
        // find the first news item's title
        currentPageTitle = trim( $('h1.sectionTitle').text() );
        trace( 'push page title == ' + currentPageTitle );
        //settings.normalViewportHeight = 450;
    }
    
    // make sure we have a valid title, and if so set it
    if ( (currentPageTitle != undefined) && (currentPageTitle != null) ) {
        session.pageTitle = currentPageTitle;
    }
    
    // start with the actions area open
    // but only if on homepage
    if ( $('body').attr('rel') == 'home' ) {
        window.setTimeout(function() {
            $('div#actions a#buzzToggle').trigger('click', {});
        }, 1000);
        // auto hide it
        //window.setTimeout(function(){
        //    $('div#actions a#buzzToggle').trigger('click', {});
        //}, 5000);
    }
    else {
        // not on homepage, so kick in the twitter in marquee mode
        //$('li#twitter').fadeTo( 1, 0.1 );
        //toggleBuzzBarSlim( function() {
        //    $('li#twitter').fadeTo( 1000, 1.0 );
        //});
    }
    
    
    // start video on click
    $('div#player a').click( function(e) {
        e.preventDefault();
        playVideoQuicktime( $('a', this).attr('href'), '', '', true );
        $(this).unbind('click');
    });
    
    
    // directors' page, allow 'play next' button
    $('body[rel="directors"] a.playVideoNext').click( function(e) {
        e.preventDefault();
        // clear the player & show the loading icon
        $('div#player').empty().html('<img id="loading" src="images/loading.gif" style="margin-top:10%;" />');
        // load the next video
        playNextVideoQuicktime( true /* circular playback */ );
    });
    
    // directors' page, allow 'play previous' button
    $('body[rel="directors"] a.playVideoPrev').click( function(e) {
        e.preventDefault();
        // clear the player & show the loading icon
        $('div#player').empty().html('<img id="loading" src="images/loading.gif" style="margin-top:35%;" />');
        // load the previous video
        playPreviousVideoQuicktime( true /* circular playback */ );
    });
    
    
    // play videos on thumb click on directors page
    $('div#videoGallery ul li a.videoLink').unbind('click');
    $('div#videoGallery ul li a.videoLink').click( function(e) {
        e.preventDefault();
        trace( 'video click : directors page' );
        // play video and start the playlist feature
        videoClickHandlerB( $(this), true );
    });
    
    
    // browse thumbs ui love
    //$('body[rel="browse"] a.videoLink').hover(
    //    function() {
    //        $('span.info', $(this)).fadeTo( 800, '1.0' );
    //    },
    //    function() {
    //        $('span.info', $(this)).fadeTo( 600, '0.6' );
    //    }
    //);
    
    // play videos on thumb click on browse page
    $('body[rel="browse"] a.videoLink').click( function(e) {
        e.preventDefault();
        //trace( 'video click : browse page' );
        // play video, but don't use the playlist feature
        videoClickHandlerB( $(this) );
    });
    
    
    // directors' page play all
    if ( session.pageType == 'directors' ) {
        $('a#playAll').click( function(e) {
            e.preventDefault();
            var firstVideo = $('a.videoLink');
            videoClickHandlerB( firstVideo[0], true );
        });
    }
    
    
    //
    // universal "close" button for all playing videos
    //
    $('div#playerControls a[rel="close"]').click( function(e) {
        e.preventDefault();
        if ( session.currentVideo != null ) {
            try {
                // stop the video first to help prevent flickering
                session.currentVideo.Stop();
            } catch (e) {}
        }
        // hide social share buttons
        $('div#playerSocial').fadeOut( 200 );
        $('div#player').empty();
        // wait a fraction of a second to make sure player is hidden, to reduce flicker, before animating
        window.setTimeout( function() {
            $('div#playerContainer').animate({
                top: '-600px'
            }, 500, 'easeOutCirc', function() {
                // clear the player area so it doesn't flicker and change when next vid is played
                $('div#player').empty();
                // elements to dim when player slides down
                var dimmableItems = 'div#stage, div.jScrollPaneContainer, div#videoGallery, div#content, div#videoInfo, div#browseWrapper, div#browseFilterControlsContainer';
                $(dimmableItems).fadeTo( 300, 1.0 );
                if ( $.browser.msie ) {
                    // force thumbnails back into view for IE ugh
                    trace( 'forcing thumbs back to max alpha' );
                    var container = (
                        (session.pageType == 'directors') ?
                        'div#videoGallery a' : '.jScrollPaneTrack, div#browseWrapper ul li a'
                    );
                    $(container).each( function() {
                        $(this).children().each( function() {
                            $(this).css( 'filter', 'alpha(opacity=100)' );
                        });
                    });
                }
            });
        }, 100 );
        // remove global access to the video now that it's unloaded
        session.currentVideo = null;
        session.html5player = null;
        session.clipID = null;
        session.creatorName = null;
        session.pageTitle = '';
        // update actual page title so social share works better
        //document.title = 'The Institute';
        updatePageTitle( '', '', '' );
        updateURLHash( null );
    });
    
    
    // pretty huge rotating background gallery images!
    $.fn.fullscreenr({
        width:      974,
        height:     600,
        bgID:       'img#canvas'
    });
    
    
    // load the background images list via ajax
    if ( session.pageType != 'admin' ) {
        try {
            $.get(
                prefixURL + 'inc/featuredImages2JSON.inc.php', {urlprefix: '../'}, function( json ) {
                    try {
                        
                        // parse the list of gallery images
                        session.backgroundGallery = eval( json );
                        
                        /* *this is being handled by PHP now* -- if ( (session.rotateBackground(true) != false) && (session.pageType != 'admin') && (session.pageType != 'directors') ) {
                            // set the first image immediately
                            session.currentBackgroundIndex = getRandomGalleryImage();
                            preloadImage( (prefixURL + 'features/' + session.backgroundGallery[session.currentBackgroundIndex]), function() {
                                $('img#canvas')
                                    .attr( 'src', (prefixURL + 'features/' + session.backgroundGallery[session.currentBackgroundIndex]) )
                                    .fadeIn( 500 );
                                $(window).resize();
                            });
                        }*/
                        $(window).resize();
                        
                        // preload/cache-ahead all gallery images
                        preloadAllGalleryBackgrounds();
                        
                    }
                    catch (e) {}
                }, 'text/javascript'
            );
        }
        catch (e) {}
    }
    
    // rotate background image
    if ( (session.rotateBackground(true) != false) && !session.backgroundRotationInProgress && (session.pageType != 'admin') && (session.pageType != 'directors') /*&& (session.pageType != 'browse')*/ ) {
        
        //trace( 'starting slideshow' );
        //trace( 'gallery images (' + session.backgroundGallery.length + ')' );
        //trace( 'gallery index (' + session.currentBackgroundIndex + ')' );
        
        window.setInterval( function() {
            
            session.backgroundRotationInProgress = true;
            
            session.currentBackgroundIndex = getRandomGalleryImage();
            
            //trace( 'loading background gallery image: ' + session.backgroundGallery[session.currentBackgroundIndex] );
            
            preloadImage( (prefixURL + 'features/' + session.backgroundGallery[session.currentBackgroundIndex]), function() {
                $('img#canvas').fadeOut(500, function() {
                    $('img#canvas')
                        .attr( 'src', (prefixURL + 'features/' + session.backgroundGallery[session.currentBackgroundIndex]) )
                        .fadeIn( 500, function() {
                            session.backgroundRotationInProgress = false;
                        });
                    $(window).resize();
                });
            });
            
        }, 10000 );
        
    }
    
    
    
    
    // directors hover
    $('div#directors ul li a').mouseenter( function() {
        
        // kill any timer waiting to hide popup
        window.clearTimeout( timers.directorInfo );
        
        var link = $(this).parent();
        
        var top_offset = parseInt( '-' + Math.round(
            $('div#directors').position().top + $('div#directorInfo').height() -
            $('div#directors ul').height() + /* account for arrow */ /*24*/ /*-11*/ -23
        ));
        
        var left_offset = Math.round(
            $(link).offset().left -
            ( $('#directorInfo').width() / 2 ) +
            /* math is f'd up! */ 12
        );
        
        // find the current index to pull the director's info
        // FYI jQuery is AMAZING for doing this... !
        var currentIndex = ( $(this).parent().prevAll().length );
        //trace( 'hovering on index #' + currentIndex );
        
        // show popup
        $('div#directorInfo').html(directorPopups[currentIndex]).fadeIn(100).animate({
            //top:    top_offset  + 'px',
            top:    /*'-122px',*/'-111px',
            left:   left_offset + 'px'
        }, {
            queue: false,
            duration: 100
        });
        
    });
    
    $('div#directors').mouseleave( function() {
        // hide popup
        window.clearTimeout( timers.directorInfo );
        timers.directorInfo = window.setTimeout( function() {
            $('div#directorInfo').fadeOut(50);
        }, 1000 );
    } );
    
    $('div#directorInfo').mouseenter( function() {
        // hide popup
        window.clearTimeout( timers.directorInfo );
        $(this).mouseleave( function() {
            timers.directorInfo = window.setTimeout( function() {
                $('div#directorInfo').fadeOut(50);
            }, 500 );
        } );
    } );
    
    
    alignDirectorsBuzz( /*function() {
        // after the alignment, show the initial animation for buzz
        $('div#buzz, div#directors').animate({
            bottom: '+25px'
        }, 1000 );
    } */);
    
    
    // show buzz bar on hover
    $('div#buzz').hover(
        function() {
            if ( !session.actionsAnimating && !session.buzzHoverShowDelayEnabled ) {
                // wait 1 second before animating to prevent flickering
                session.buzzHoverShowDelayEnabled = true;
                window.clearTimeout( timers.buzzHoverShowDelay );
                timers.buzzHoverShowDelay = window.setTimeout( function() {
                    session.buzzHoverShowDelayEnabled = false;
                }, 1000 );
                // toggle
                toggleBuzzBarFull();
            }
        },
        function() {
            if ( !session.actionsAnimating && !session.buzzHoverShowDelayEnabled ) {
                // wait 1 second before animating to prevent flickering
                session.buzzHoverShowDelayEnabled = true;
                window.clearTimeout( timers.buzzHoverShowDelay );
                timers.buzzHoverShowDelay = window.setTimeout( function() {
                    session.buzzHoverShowDelayEnabled = false;
                }, 1000 );
                // toggle
                toggleBuzzBarSlim();
            }
        }
    );
    
    // toggle buzz bar visibility
    $('div#buzz a#buzzToggle').click( function(e) {
        
        // don't follow faux anchor link
        e.preventDefault();
        
        // prevent doubling up animation
        if ( !session.actionsAnimating ) {
            
            // determine actions/buzz bar's current state
            if ( parseInt($('div#actions').css('bottom')) >= settings.actions.expandedOffset ) {
                
                // hide the actions area
                toggleBuzzBarSlim();
                
            }
            else {
                
                // show the actions area
                toggleBuzzBarFull();
                
            }
            
        }
        
        // remove focus rect from link
        $(this).blur();
        
    }); // buzz toggle
    
    
    // temporarily pause twitter marquee on hover
    $('li#twitter').hover(
        function() {
            session.pauseTwitterMarquee = true;
        },
        function() {
            session.pauseTwitterMarquee = false;
        }
    );
    
    
    //
    // horizontal scroller for director's page video thumbnails
    //
    $('body[rel="directors"] div.hscroll').jCarouselLite({
        btnNext: ".next",
        btnPrev: ".prev",
        mouseWheel: true,
        visible: 4,
        scroll: 4
    });
    
    $('body[rel="directors"] div.hscroll').mouseenter( function() {
        toggleBuzzBarSlim();
    });
    
    
    
    //
    // ability to favorite things
    //
    $('a.shareheart').click( function(e) {
        e.preventDefault();
        favorite();
    });
    
    
    // populate summary with favorites content from cookies
    updateFavoritesMenu();
    
    // hover state for showing delete option on favorites view
    $('li.favoriteItem').hover(
        function() {
            $('a.deleteFavorite', $(this)).show( /*100*/ );
        },
        function() {
            $('a.deleteFavorite', $(this)).hide( /*100*/ );
        }
    );
    // ability to remove favorites
    $('a.deleteFavorite').click( function(e) {
        // unfavorite item clicked
        unfavorite( $(this) );
    });
    
    
    // favorites summary list actions
    var favoritesSummaryActions = $('ul#social li#favorites ul#favoritesSummaryActions');
    
    // set the share link to the current page's favorites ID
    $('li#favorites div#favoritesSummaryShare input#favoritesShareLink').val(
        'http://www.theinstitute.tv/?favoriteid=' + sessionID
    );
    // set the fb/twitter my favs share links correctly
    $('a#shareFavsTwitter').attr(
        'href', 'http://twitter.com/home?status=' +
        encodeURIComponent('http://www.theinstitute.tv/?favoriteid=')
        + sessionID + '%20@theinstituteLA'
    );
    $('a#shareFavsFacebook').attr(
        'href', 'http://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.theinstitute.tv%2F%3ffavoriteid='
        + sessionID + '&t=My%20Favorites%20@%20theinstitute.tv'
    );
    
    // let the favorites share links with hash tags play videos when clicked
    $('div#favoritesSummaryOverview a').click( function() {
        // this will set the window.location + trigger hash handlers
        setWindowURL( $(this).attr('href') );
    });
    
    // switch back to favs summary view
    $('div#favoritesSummary div#favoritesSummaryShare a.showFavorites').click( function(e) {
        e.preventDefault();
        var favoritesSummary = $('ul#social li#favorites div#favoritesSummary');
        $('div#favoritesSummaryShare', favoritesSummary).fadeOut( 200, function() {
            $('div#favoritesSummaryOverview', favoritesSummary).fadeIn( 200 );
        });
    });
    // save
    $('a#favoritesSave', favoritesSummaryActions).click( function(e) {
        e.preventDefault();
        var favoritesSummary = $('ul#social li#favorites div#favoritesSummary');
        $('div#favoritesSummaryShare', favoritesSummary).fadeOut( 200, function() {
            $('div#favoritesSummaryOverview', favoritesSummary).fadeIn( 200 );
        });
        saveFavorites();
    });
    
    // send via email
    $('a#favoritesSendEmail', favoritesSummaryActions).click( function(e) {
        e.preventDefault();
        var favoritesSummary = $('ul#social li#favorites div#favoritesSummary');
        var fsOverview = $('div#favoritesSummaryOverview', favoritesSummary);
        var fsShare = $('div#favoritesSummaryShare', favoritesSummary);
        var fsShareRealHeight = fsShare.height();
        fsOverview.fadeOut( 200, function() {
            fsShare
                /*.css( 'overflow', 'hidden' )*/
                .height( fsOverview.height() )
                .fadeIn( 200 )
                .animate({
                    height: fsShareRealHeight
                }, 400, function() {
                    fsShare.css({
                        height: 'auto',
                        overflow: 'auto'
                    });
                });
        });
    });
    
    // handler for send via email form
    $('form#favoritesShareEmail').submit( function(e) {
        
        e.preventDefault();
        
        // validate fields
        var sender = trim( $('input#favoritesShareSender', $(this)).val() );
        var senderEmail = trim( $('input#favoritesShareSenderEmail', $(this)).val() );
        var message = trim( $('input#favoritesShareMessage', $(this)).val() );
        var recipient = trim( $('input#favoritesShareRecipient', $(this)).val() );
        
        if ( sender == '' ) {
            sender = 'The Institute';
        }
        
        if ( recipient == '' ) {
            
            recipient.css('backgroundColor', '#000000').animate({
                backgroundColor: '#ffffff'
            }, 1000);
            
            growl( 'You must specify a recipient to share favorites via email.' );
            
        }
        else {
            
            //growl( 'Saving your favorites' );
            
            saveFavorites();
            
            //growl( 'Sharing your favorites with ' + recipient + ', please wait...' );
            
            // send email via ajax
            $.get( prefixURL + 'favorites.php', {
                ajax: 'true',
                action: 'sendemail',
                sender: sender,
                senderEmail: senderEmail,
                message: message,
                recipient: recipient
            }, function(response) {
                response = eval('(' + response + ')');
                if ( response.result == true ) {
                    growl( response.message, 5000 );
                }
            }, 'text/javascript' );
            
        }
        
    });
    
    
    
    
    // handler for share page by email
    $('form#shareThisEmail').submit( function(e) {
        
        e.preventDefault();
        
        // validate fields
        var sender = trim( $('input#shareThisSender', $(this)).val() );
        var message = trim( $('input#shareThisMessage', $(this)).val() );
        var recipient = trim( $('input#shareThisRecipient', $(this)).val() );
        
        if ( sender == '' ) {
            sender = 'The Institute';
        }
        
        if ( recipient == '' ) {
            
            recipient.css('backgroundColor', '#000000').animate({
                backgroundColor: '#ffffff'
            }, 1000);
            
            growl( 'You must specify a recipient to share this page via email.' );
            
        }
        else {
            
            //growl( 'Sharing this page with ' + recipient + ', please wait...' );
            
            // send email via ajax
            $.get( prefixURL + 'favorites.php', {
                ajax: 'true',
                action: 'sharepageemail',
                sender: sender,
                message: message,
                recipient: recipient,
                url: window.location.href.toString()
            }, function(response) {
                response = eval('(' + response + ')');
                if ( response.result == true ) {
                    growl( response.message, 5000 );
                }
            }, 'text/javascript' );
            
        }
        
    });
    
    
    // show manage favorites view
    $('a#manageFavorites, a.viewAllFavorites').attr(
        'href', (
            'http://www.theinstitute.tv/' +
            ( (window.location.href.toString().indexOf('') >= 1) ? '_dev' : '' ) +
            '/?favoriteid=' + getCookie('tifavs_id')
        )
    ).unbind( 'click' );
    
    //
    // "share this" functionalities
    //
    
    // facebook
    $('ul#social a#shareFacebook').click( function(e) {
        e.preventDefault();
        saveFavorites();
        window.open(
            'http://www.facebook.com/sharer.php?u=' +
            encodeURIComponent(window.location.href) +
            '&t=' + encodeURIComponent(/*document.title*/ ((session.pageTitle=='')?document.title:session.pageTitle)),
            'tishare', 'resizable=1,scrollbars=1,toolbar=0,status=0,width=626,height=436'
        );
    });
    $('ul#social a#shareFavsFacebook').click( function(e) {
        e.preventDefault();
        saveFavorites();
        window.open(
            'http://www.facebook.com/sharer.php?u=' +
            encodeURIComponent('http://www.theinstitute.tv/?favoriteid=') +
            sessionID + '&t=' + encodeURIComponent(((session.pageTitle == '') ? document.title : session.pageTitle)),
            'tishare', 'resizable=1,scrollbars=1,toolbar=0,status=0,width=626,height=436'
        );
    });
    
    // twitter
    $('ul#social a#shareTwitter').click( function(e) {
        e.preventDefault();
        saveFavorites();
        //$('a.twitter-share-button').trigger('click');
        //return;
        window.open(
            'http://www.twitter.com/home?status=@theinstituteLA+' +
            session.currentPageURL + '&t=' + ((session.pageTitle=='')?document.title:session.pageTitle),
            'sharer', 'resizable=1,scrollbars=1,toolbar=0,status=0,width=626,height=436'
        );
    });
    $('ul#social a#shareFavsTwitter').click( function(e) {
        e.preventDefault();
        saveFavorites();
        window.open(
            $(this).attr('href'),
            'sharer', 'resizable=1,scrollbars=1,toolbar=0,status=0,width=626,height=436'
        );
    });
    
    
    // set the share page text boxes
    $('input#shareThisLink').val( window.location.href );
    //$('input#favoritesShareLink').val(
    //    'http://www.theinstitute.tv' +
    //    /*debug*/
    //    ( (window.location.href.toString().indexOf('') >= 1) ? '/' : '/' ) +
    //    '?favoriteid=' + getCookie('tifavs_id')
    //);
    
    //
    // import TI Twitter feed
    // delayed, because it makes the page hang!
    //
    window.setTimeout( function() {
        importTweets( /*4*/ );
    }, 2000 );
    
    // enable nicer scrollbars (also better for cross browser)
    enableCustomScrollbars();
    
    // collapse Buzz bar on hover of main content area(s)
    // since it incessantly sticks sometimes
    $('div#stage').mouseenter( function() {
        if ( session.pageType != 'home' ) {
            toggleBuzzBarSlim();
        }
    });
    
    
    // check for kiosk video coming from featured or favorites
    if ( session.pageType == 'browse' ) {
        
        //trace( 'page type: browse' );
        
        if ( window.location.href.indexOf('kioskVideo=') >= 1 ) {
            
            //trace( 'kiosk video detected' );
            
            var videoURL = window.location.href.split('kioskVideo=')[1];
            
            if ( videoURL.indexOf('&') >= 1 ) {
                
                // trim off any trailing query strings
                videoURL = videoURL.substring( 0, videoURL.indexOf('&') );
                
            }
            
            if ( trim( videoURL ) != '' ) {
                
                $('div#stage').ready( function() {
                    
                    window.setTimeout( function() {
                        
                        //trace( 'kioskVideo found: ' + videoURL );
                        //playVideoQuicktime( videoURL, '', '', 'true' );
                        var fauxLink = document.createElement( 'a' );
                        
                        fauxLink.setAttribute( 'href', kioskVideoURL );
                        
                        videoClickHandlerB( fauxLink );
                        
                    }, 2000 );
                    
                });
                
            }
            
        }
        
    }
    
    
    
    // show/hide default search text on focus/blur
    $('form#searchForm input#query').focus( function() {
        if ( $(this).val() == 'Search for...' ) {
            $(this).val( '' );
        }
    }).blur( function() {
        if ( $(this).val() == '' ) {
            $(this).val( 'Search for...' );
        }
    });
    
    
    // pretty fade in the 2nd directors nav
    //$('a#directorList').mouseenter( function() {
    //    $('div.commDirectorList').fadeIn(10).slideDown( 200 );
    //});
    
    //$('div.commDirectorList').mouseleave( function() {
    //    $(this).fadeOut( 200 );
    //});
    
    
    // keep the social drops visible for a tiny bit after hover-out
    var socialDropParent = $('ul#social');
    
    $('li#favorites', socialDropParent).hover(
        function() {
            window.clearTimeout( timers.socialDropSticky.myFavorites );
            $('li#shareThis div#shareThisDrop, li#search div:first-child', socialDropParent).css('display', 'none');
            $('div#favoritesSummary', this).css('display', 'block');
        },
        function(e) {
            e.preventDefault();
            $('div#favoritesSummary', this).show();
            timers.socialDropSticky.myFavorites = window.setTimeout( function() {
                $('ul#social li#favorites div#favoritesSummary').hide( 200 );
            }, 1000 );
        }
    );
    
    $('li#shareThis', socialDropParent).hover(
        function() {
            window.clearTimeout( timers.socialDropSticky.shareThis );
            $('li#favorites div#favoritesSummary, li#search div:first-child', socialDropParent).css('display', 'none');
            $('div#shareThisDrop', this).css('display', 'block');
        },
        function(e) {
            e.preventDefault();
            timers.socialDropSticky.shareThis = window.setTimeout( function() {
                $('ul#social li#shareThis div#shareThisDrop').hide( 200 );
            }, 1000 );
            $('div#shareThisDrop', this).css('display', 'block');
        }
    );
    
    $('li#search', socialDropParent).hover(
        function() {
            window.clearTimeout( timers.socialDropSticky.search );
            $('li#favorites div#favoritesSummary, li#shareThis div#shareThisDrop', socialDropParent).css('display', 'none');
            $('div#searchWrap', this).show();
        },
        function(e) {
            e.preventDefault();
            $('div#searchWrap', this).show();
            timers.socialDropSticky.search = window.setTimeout( function() {
                $('ul#social li#search div#searchWrap').css('display', 'none');
            }, 1000 );
        }
    );
    // hide the social drops if other share links are hovered, to prevent double-up confusion
    //$('li#favorites a#showfavorites, li#search a', $('ul#social')).mouseenter( function() {
    //    window.clearTimeout( timers.shareThisDropSticky );
    //    $('div#shareThisDrop').hide();
    //});
    //$('li#favorites a#showfavorites, li#search a', $('ul#social')).mouseenter( function() {
    //    window.clearTimeout( timers.shareThisDropSticky );
    //    $('div#shareThisDrop').hide();
    //});
    //$('li#favorites a#showfavorites, li#search a', $('ul#social')).mouseenter( function() {
    //    window.clearTimeout( timers.shareThisDropSticky );
    //    $('div#shareThisDrop').hide();
    //});
    
    
    /*
     * this triggers the resize positioning/etc. callback
     * it will cause the stage to jump into place, so it should stay off
     * but it is good for debugging if the stage wont fade in
     */
    //windowResizeCallback();
    
    dynamicHeighten();
    reinitializeCustomScrollbars();
    
    // sometimes a double trigger helps with cross-browser compatibility
    //$(window).trigger( 'resize' );
    $(window).resize();
    
    
    
    // handle ajax-style hash URLs where applicable
    //handleHashedURL();
    
    trace( 'goodbye' );
    
    
}); // jQuery DOM-ready wrapper









