/* 
 * CaptionBox
 * Interactive Transcript jQuery Plugin
 *
 * Version 1.0.0
 * March 15, 2011
 *
 * For install help, please see http://speakertext.com/captionbox
 * For license, please see http://speakertext.com/tos#license
 *
 * Copyright (c) SpeakerText 2010-2011
 * Original Development by Dan Schultz, 2010
 */

// Constants
	var STCONST_FILENAME = "jquery.captionbox.js";

	/* Web Service Locations */
	var STCONST_WS_UPDATE_TRANSCRIPT = "/transactions/update_from_editor";
	
	/* Web Service API Keys*/
	var STCONSTS_WSCREDS_BITLY_LOGIN = "speakertext";
	var STCONSTS_WSCREDS_BITLY_APIKEY = "R_2274af29d71349021399a6ee1191ab6b";
	
	/* Social Media DOM Element Classes */
	var STCONST_CLASS_SHARE_BUTTON = "STxShare";
	var STCONST_CLASS_SHARE_FACEBOOK = "STfacebookShare";
	var STCONST_CLASS_SHARE_TWITTER = "STtwitterShare";
	var STCONST_CLASS_SHARE_URL = "STurlShare";
	
	/* WS Prefixes */
	var STCONST_WSPREFIX_TRANSCRIPTCALLBACK = "STcallback";
	
	/* Querystring Variables */
	var STCONST_QUERY_PLAYER_QUOTELINK = "STQL";
	
	/* Player Text */
	var STCONST_TEXT_BAR_SEARCH = "Search inside this video...";
	var STCONST_TEXT_BAR_LOGOLINK = "http://speakertext.com/?ref=itp";
	var STCONST_TEXT_BAR_AUTOSCROLL = "AUTO SCROLL";
	var STCONST_TEXT_BAR_SHOWTEXT = "EXPAND TRANSCRIPT";
	
	var STCONST_TEXT_EDIT_SAVE = "Save";
	var STCONST_TEXT_EDIT_CANCEL = "Cancel";
	
	var STCONST_TEXT_MESSAGE_EDIT = "<p>Just start typing to edit the transcript.</p>";
	
	var STCONST_TEXT_SHARE_UNSELECTED = "<strong>Link to a video quote</strong><br>To start, select some text from the transcript<br>";
	var STCONST_TEXT_SHARE_HIGHLIGHTED = "<strong>Share the selected quote</strong><br>The video will start playing at this quote</a><br>";
	var STCONST_TEXT_SHARE_SELECTED = "<strong>Share the current quote</strong><br>The video will start playing at this quote</a><br>";
	
	var STCONST_TEXT_SHARE_BUTTONS = "<a class='" + STCONST_CLASS_SHARE_TWITTER + " " + STCONST_CLASS_SHARE_BUTTON + "' onmousedown=\"stjQuery(this).STcaptureQuoteLink()\" onclick=\"if(stjQuery(this).data(STCONST_DATAKEY_QUOTELINK_TEXT) != '') { temp = window.open('','_blank'); stjQuery(this).STtwitterShare(temp); }\"></a><a class='" + STCONST_CLASS_SHARE_FACEBOOK + " " + STCONST_CLASS_SHARE_BUTTON + "' onmousedown=\"stjQuery(this).STcaptureQuoteLink()\" onclick=\"if(stjQuery(this).data(STCONST_DATAKEY_QUOTELINK_TEXT) != '') { temp = window.open('','_blank'); stjQuery(this).STfacebookShare(temp); }\"></a><a class='" + STCONST_CLASS_SHARE_URL + " " + STCONST_CLASS_SHARE_BUTTON + "' onmousedown=\"stjQuery(this).STcaptureQuoteLink()\" onclick=\"if(stjQuery(this).data(STCONST_DATAKEY_QUOTELINK_TEXT) != '') { stjQuery(this).STurlShare(); }\"></a><br>";
	
	var STCONST_TEXT_MESSAGE_SHAREURL_BEGIN = "<h1>";
	var STCONST_TEXT_MESSAGE_SHAREURL_END = "</h1><p>Copy and share this URL to link back to this moment of the video.</p>";
	
	var STCONST_TEXT_MESSAGE_COPY = "<strong>QuoteLink Created!</strong><p>When you paste this text, it will link back to this moment in the video. <a href='http://speakertext.com/what' target='_blank'>More&nbsp;&raquo;</a></p>";
	
	var STCONST_TEXT_MESSAGE_SAVING = "<p>Saving Transcript...</p>";
	var STCONST_TEXT_MESSAGE_SAVEOK = "<h1>Transcript Received!</h1><p>Your transcript has been queued for processing and should be visible in a few moments. <a href='/library'>Return to library &raquo</a></p>";
	var STCONST_TEXT_MESSAGE_SAVEERROR = "<h1>Error</h1><p>Your transcript could not be saved at this time. Please try again in a few moments.</p>";
	
	var STCONST_TEXT_TRANSCRIPT_LOADING = "<div>The transcript for this video is loading.</div>";
	var STCONST_TEXT_TRANSCRIPT_UNAVAILABLE = "<div>The transcript for this video is unavailable.</div>";
	
	
	/* Transcript DOM Element Prefixes */
	var  STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX = "STtranscriptContent";
	var  STCONST_PLAYER_TRANSCRIPTEMBED_PREFIX = "STtranscriptEmbed";
	
	/* Ignore threshold when seeking (in milliseconds) */
	var  STCONST_PLAYER_IGNORE_THRESHOLD = 3000;
	
	/* Core Player DOM Element Classes */
	var  STCONST_CLASS_PLAYER = "STplayer";
	var  STCONST_CLASS_UNINITIALIZED = "STplayerUninitialized";
	var  STCONST_CLASS_EMBEDDED = "STplayerEmbedded";
	var  STCONST_CLASS_NICEBUTTON = "nicebutton";
	var  STCONST_CLASS_EDITOR = "STeditor";
	
	var  STCONST_CLASS_VIDEOPLAYER = "STvideoPlayer";
	var  STCONST_CLASS_PLAYER_DISPLAYWITHTRANSCRIPT = "STdisplayWithTranscript";
	var  STCONST_CLASS_PLAYER_TRANSCRIPTPANE = "STtranscriptPane";
	var  STCONST_CLASS_PLAYER_TRANSCRIPTWRAPPER = "STtranscriptWrapper";
	var	 STCONST_CLASS_PLAYER_BAREBONES = "STplayerBarebones";
	var  STCONST_CLASS_PLAYER_SHAREPANE = "STsharePane";
	var  STCONST_CLASS_PLAYER_SHAREPANE_ACTIVE = "STsharePaneActive";
	var  STCONST_CLASS_PLAYER_SHAREPANE_HIGHLIGHT = "STsharePaneHighlight";
	var  STCONST_CLASS_PLAYER_SHAREPANE_TEXT = "STsharePaneText";
	var  STCONST_CLASS_PLAYER_COPYFEEDBACK = "STsharePaneCopyFeedback";
	var  STCONST_CLASS_PLAYER_TRANSCRIPTDISPLAY = "STtranscriptDisplay";
	var  STCONST_CLASS_PLAYER_TRANSCRIPTSTATUS = "STtranscriptStatus";
	var  STCONST_CLASS_PLAYER_TRANSCRIPT_CONTENT = "STtranscriptContent";
	var  STCONST_CLASS_PLAYER_SEARCH = "STsearch";
	var  STCONST_CLASS_PLAYER_SEARCHFIELD = "STsearchField";
	var  STCONST_CLASS_PLAYER_SEARCHPREVBUTTON = "STsearchPrevButton";
	var  STCONST_CLASS_PLAYER_SEARCHNEXTBUTTON = "STsearchNextButton";
	var  STCONST_CLASS_PLAYER_AUTOSCROLL = "STautoScroll";
	var	 STCONST_CLASS_PLAYER_SHOWTEXT = "STshowText";
	var  STCONST_CLASS_PLAYER_LOGO = "STlogo";
	var  STCONST_CLASS_PLAYER_CURRENTCONTENT = "STcurrentContent";
	var  STCONST_CLASS_PLAYER_SEARCHMATCH = "STsearchMatch";
	var  STCONST_CLASS_PLAYER_BASE =  "STplayerBase";
	var  STCONST_CLASS_PLAYER_BASELEFT =  "STplayerBaseLeft";
	var  STCONST_CLASS_PLAYER_BASERIGHT =  "STplayerBaseRight";
	
	var  STCONST_CLASS_PLAYER_HANDLE =  "STplayerHandle";
	var  STCONST_CLASS_PLAYER_SCROLLBAR = "STscrollBar";
	var  STCONST_CLASS_PLAYER_SCROLLUP = "STscrollUp";
	var  STCONST_CLASS_PLAYER_SCROLLDOWN = "STscrollDown";
	var  STCONST_CLASS_PLAYER_SCROLLVISIBLE = "STscrollVisible";
	var  STCONST_CLASS_PLAYER_SCROLLTOP = "STscrollTop";
	var  STCONST_CLASS_PLAYER_SCROLLBOTTOM = "STscrollBottom";
	var  STCONST_CLASS_PLAYER_BAR = "STbar";
	var  STCONST_CLASS_MESSAGEPANE = "STmessagePane";
	
	var  STCONST_CLASS_COPY_FEEDBACK = "STcopyFeedback";
	
	var  STCONST_CLASS_PLAYER_FONTSIZEBUTTON = "STfontSizeButton";
	
	var  STCONST_CLASS_EDIT_SAVE = "STsaveButton";
	var  STCONST_CLASS_EDIT_CANCEL = "STcancelButton";
	var  STCONST_CLASS_EDIT_EMPTY = "STemptyContentEdit";
	
	var  STCONST_CLASS_PLAYER_EMBEDOVERLAY = "SToverlay";
	var  STCONST_CLASS_PLAYER_EMBEDWRAPPER = "STembedWrapper";
	
	
	/* Core Player State Classes */
	var  STCONST_CLASS_PLAYER_AUTOSCROLL_ON = "on";
	var  STCONST_CLASS_PLAYER_AUTOSCROLL_OFF = "off";
	var  STCONST_CLASS_PLAYER_TRANSCRIPT_LOADING = "STtranscriptLoading";
	
	var  STCONST_CLASS_PLAYER_TRANSCRIPT_VISIBLE = "visibleTranscript";
	
	var  STCONST_CLASS_PLAYER_SEARCHEMPTY = "empty";
	
	var  STCONST_CLASS_PLAYER_SMALLFONT = "smallFont";
	var  STCONST_CLASS_PLAYER_MEDIUMFONT = "mediumFont";
	var  STCONST_CLASS_PLAYER_LARGEFONT = "largeFont";
	
	/* Core Player Events */
	var  STCONST_EVENT_TRANSCRIPT_LOADED = "transcriptLoaded";
	var  STCONST_EVENT_PLAYER_SHOW = "showPlayer";
	var  STCONST_EVENT_PLAYER_HIDE = "hidePlayer";
	var  STCONST_EVENT_CONTENT_CLICKED = "contentClicked";
	
	var  STCONST_EVENT_CONTENT_SELECT = "contentSelect";
	var  STCONST_EVENT_CONTENT_COPY = "contentCopy";
	var  STCONST_EVENT_CONTENT_DESELECT = "contentDeselect";
	
	var  STCONST_EVENT_PLAYER_SEARCH = "search";
	var  STCONST_EVENT_PLAYER_SEARCHNEXT = "searchNext";
	var  STCONST_EVENT_PLAYER_SEARCHPREV = "searchPrev";
	
	/* Core Player Data Keys */
	var  STCONST_DATAKEY_VIDEOPLAYERID = "STvideoplayerID";
	var  STCONST_DATAKEY_VIDEOPLAYERTYPE = "STVPtype";
	var  STCONST_DATAKEY_TRANSCRIPTID = "STtranscriptID";
	var  STCONST_DATAKEY_PLAYERQUEUE = "STplayerQueue";
	var  STCONST_DATAKEY_PLAYER_DISABLED = "STplayerDisabled";
	
	var  STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL = "STautoScroll";
	var  STCONST_DATAKEY_TRANSCRIPT_CURRENTCONTENTID = "STcurrentContentID";
	
	var  STCONST_DATAKEY_TRANSCRIPT_SEARCHMATCHES = "STsearchMatches";
	var  STCONST_DATAKEY_TRANSCRIPT_SEARCHTERMS = "STsearchTerms";
	
	var  STCONST_DATAKEY_TRANSCRIPT_IGNOREPROGRESS = "STtranscriptIgnoreProgress";
	
	var  STCONST_DATAKEY_CONFIG = "STconfig";
	var  STCONST_DATAKEY_QUOTELINK_TEXT = "STquoteLinkText";
	var  STCONST_DATAKEY_QUOTELINK_CONTENTID = "STquoteLinkContentID";
	
	var  STCONST_DATAKEY_SHAREURL_TIMEOUT = "STshareUrlTimeout";
	
	var	 STCONST_DATAKEY_EDITMESSAGE_SHOWN = "STeditMessageShown";
	
	/* Core Player Flags */
	var  STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_OFF = 0;
	var  STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_ON = 1;
	
	/* Configuration Settings */
	var STCONST_CONFIG_INITIALSTATE_OPEN = "open";
	var STCONST_CONFIG_INITIALSTATE_CLOSED = "closed";
	var STCONST_CONFIG_EDITENABLED_OFF = "off";
	var STCONST_CONFIG_EDITENABLED_ON = "on";
	var STCONST_CONFIG_EMBEDSTYLE_OVERLAY = "overlay";
	var STCONST_CONFIG_EMBEDSTYLE_EMBED = "embed";
	
// Sandbox
if( typeof( window.jQuery ) != "undefined" && (window.jQuery().jquery.indexOf("1.3") == 0 || window.jQuery().jquery.indexOf("1.4") == 0 || window.jQuery().jquery.indexOf("1.5") == 0) ) {
	window.stjQuery = window.jQuery;
} else {
	// Later on we might want to load jQuery dynamically and use a callback to execute
	// the stuff below. Especially if we eventually allow people to embed just one ST.
	//
	// This will of course require us doing all of this initialization more smartly.
	// We'll want to check whether or not jQuery has been loaded, but also whether or
	// not the SpeakerText plugin has been initialized or not...because if the plugin is
	// embedded more than once on the page, it would be bad to reinitialize.

	console.log("Must load jQuery 1.3+ before loading SpeakerText plugin!");
}


// Plugin Definition
(function($) {
	// Transcript Cache -- keys are transcript IDs
	var STtranscriptCache = Array();
	
	// Player Cache -- connects the ST players to a hash to enable communication between Video Player and the ST Player
	var STplayerCache = Array();
	
	// Player Count -- used to generate a unique player ID (when needed)
	var STplayerCount = 0;
	
	// Content Object
		function STContent() {
			this.id = 0;
			this.timestamp = 0;
			this.text = "";
		}
	
	
	// Transcript Object
		function STTranscript() {
			this.transcriptID = 0;
			this.videoID = 0;
			this.task = 0;
			this.hash = "";
			this.content = new Array();
		}
		
		STTranscript.prototype.getContentByTimestamp = function(timestamp) {
			if(this.content.length == 0)
				return null;
			
			previousContent = this.content[0];
			for (var x in this.content) {
				a = this.content[x];
				if(a.timestamp == timestamp)
					return a;
				else if(a.timestamp > timestamp)
					return previousContent;
				previousContent = a;
			}
			return previousContent;
		}
		
		STTranscript.prototype.getContentByID = function(id) {
			for (var x in this.content) {
				a = this.content[x];
				if(a.id == id)
					return a;
			}
			return null;
		}
		
		STTranscript.prototype.updateContentByID = function(id, newText) {
			for (var x in this.content) {
				a = this.content[x];
				if(a.id == id) {
					this.content[x].text = newText;
					return;
				}
			}
			return null;
		}
		
		STTranscript.prototype.search = function(string) {
			var contentArray = Array();
			string = string.toLowerCase();
			for (var x in this.content) {
				a = this.content[x];
				if(a.text.toLowerCase().search(string) != -1)
					contentArray.push(a);
			}
			return contentArray;
		}
	
	
	// ST Plugin Methods
	$.fn.extend({
		// Setup Methods
			/* Returns whether or not this item has been set up with SpeakerText */
			hasSpeakerText: function() {
				return $(this).hasClass(STCONST_CLASS_VIDEOPLAYER);
			},
			
			/* Sets up and loads a speakertext player */
			speakerText: function(playerType, settings) {
				// Set up the configuration array
				var config = {
							  minHeight: 30,
							  defaultHeight: 210,
							  videoPlayerID: "",
							  preEmbedID: "",
								transcriptPath: "",
							  initialState: STCONST_CONFIG_INITIALSTATE_OPEN,
							  editEnabled: STCONST_CONFIG_EDITENABLED_OFF,
							  embedStyle: STCONST_CONFIG_EMBEDSTYLE_EMBED};
				if(typeof(STglobalSettings) != "undefined") $.extend(config, STglobalSettings);
				if(settings) $.extend(config, settings);
				
				// Initialize these players
				this.each(function() {
					// If this item already has a ST player associated with it, don't associate a second one
					if($(this).hasSpeakerText())
						return true; // like a loop continue
						
					// Generate a unique speakertext ID
					++STplayerCount;
					var playerID;
					if(config.videoPlayerID != "")
						playerID = STCONST_CLASS_PLAYER + config.videoPlayerID;
					else if($(this).attr("id") != "")
						playerID = STCONST_CLASS_PLAYER + $(this).attr("id");
					else
						playerID = STCONST_CLASS_PLAYER + STplayerCount;
					
					// Set up the DOM (unless the player is already embedded)
					$(this).addClass(STCONST_CLASS_VIDEOPLAYER);
					
					// If the user already embedded an ST player, use the embed.  Otherwise generate one.
					if(config.preEmbedID != "")
						var STplayer = $("#" + config.preEmbedID);
					
					if(STplayer.length == 0) {
						//console.error("CaptionBox: No transcript found for video player with id " + config.videoPlayerID);
						return false;
					} else {
						
						// Remove Barebones Styling
						STplayer.removeClass(STCONST_CLASS_PLAYER_BAREBONES);
						
						// Add all the stuff that we leave out of the default embed
						var transcriptContent = STplayer.STembedWrapper().html();
						
						var h = "";
						h += "<div class='" + STCONST_CLASS_PLAYER_EMBEDWRAPPER + "'>";
						h += "	<div class='" + STCONST_CLASS_PLAYER_SHAREPANE + " " + STCONST_CLASS_PLAYER_DISPLAYWITHTRANSCRIPT + "'>";
						h += "		<span class='" + STCONST_CLASS_PLAYER_SHAREPANE_TEXT + "'>" + STCONST_TEXT_SHARE_UNSELECTED + "</span>" + STCONST_TEXT_SHARE_BUTTONS;
						h += "	</div>";
						
						h += "	<div class='" + STCONST_CLASS_PLAYER_TRANSCRIPTPANE + "'>";
						h += "		<div class='" + STCONST_CLASS_PLAYER_SCROLLBAR + "'>";
						h += "			<div class='" + STCONST_CLASS_PLAYER_SCROLLUP + "'></div>";
						h += "			<div class='" + STCONST_CLASS_PLAYER_SCROLLVISIBLE + "'>";
						h += "				<div class='" + STCONST_CLASS_PLAYER_SCROLLTOP + "'></div>";
						h += "				<div class='" + STCONST_CLASS_PLAYER_SCROLLBOTTOM + "'></div>";
						h += "			</div>";
						h += "			<div class='" + STCONST_CLASS_PLAYER_SCROLLDOWN + "'></div>";
						h += "		</div>";
						h += "  	<div class='" + STCONST_CLASS_PLAYER_TRANSCRIPTWRAPPER + "'>";
						h += "   	 <div class='" + STCONST_CLASS_PLAYER_TRANSCRIPTDISPLAY + "'>";
						h += transcriptContent;
						h += "  	  </div>";
						h += "  		<div class='" + STCONST_CLASS_PLAYER_TRANSCRIPTSTATUS + "'></div>";
						h += "		</div>";
						h += "	</div>";
						
						h += "	<div class='" + STCONST_CLASS_PLAYER_BASE + "'>";
						h += "		<div class='" + STCONST_CLASS_PLAYER_BASERIGHT + "'></div>";
						h += "		<div class='" + STCONST_CLASS_PLAYER_BASELEFT + "'></div>";
						h += "		<div class='" + STCONST_CLASS_PLAYER_HANDLE + "'></div>"
						h += "	</div>";
						
						h += "	<div class='" + STCONST_CLASS_MESSAGEPANE + "'></div>";
						
						h += "</div>";
						
						STplayer.STembedWrapper().remove(); // CSS bug due to overflow: auto not ever being removed
						STplayer.append(h);
						
						h = "";
						h += "<input type='text' class='" + STCONST_CLASS_PLAYER_SEARCHFIELD + " " + STCONST_CLASS_PLAYER_SEARCHEMPTY + "'/>";
						h += "<div class='" + STCONST_CLASS_PLAYER_SEARCHPREVBUTTON + " " + STCONST_CLASS_PLAYER_SEARCHEMPTY + " " + STCONST_CLASS_PLAYER_DISPLAYWITHTRANSCRIPT + "'></div>";
						h += "<div class='" + STCONST_CLASS_PLAYER_SEARCHNEXTBUTTON + " " + STCONST_CLASS_PLAYER_SEARCHEMPTY + " " + STCONST_CLASS_PLAYER_DISPLAYWITHTRANSCRIPT + "'></div>";
						h += "<div class='" + STCONST_CLASS_PLAYER_FONTSIZEBUTTON + " " + STCONST_CLASS_PLAYER_DISPLAYWITHTRANSCRIPT + "'></div>";
						h += "<div class='" + STCONST_CLASS_PLAYER_AUTOSCROLL + " " + STCONST_CLASS_PLAYER_DISPLAYWITHTRANSCRIPT + "'>" + STCONST_TEXT_BAR_AUTOSCROLL + "</div>";
						h += "<div class='" + STCONST_CLASS_PLAYER_SHOWTEXT + "'>" + STCONST_TEXT_BAR_SHOWTEXT + "</div>";
						STplayer.STbar().append(h);
						
						if(config.editEnabled == STCONST_CONFIG_EDITENABLED_ON) {
							h = "<a class='" + STCONST_CLASS_EDIT_SAVE + " " + STCONST_CLASS_NICEBUTTON + "' value='" + STCONST_TEXT_EDIT_SAVE + "'>" + STCONST_TEXT_EDIT_SAVE + "</a>";
							//h += "<a class='" + STCONST_CLASS_EDIT_CANCEL + " " + STCONST_CLASS_NICEBUTTON + "' value='" + STCONST_TEXT_EDIT_CANCEL + "' href=''>" + STCONST_TEXT_EDIT_CANCEL + "</a>";
							STplayer.append(h);
							
							STplayer.STtranscriptWrapper().find("." + STCONST_CLASS_PLAYER_TRANSCRIPT_CONTENT).attr("contentEditable", "true");
							
						}
					}
					
					// Set the embed style
					if(config.embedStyle == STCONST_CONFIG_EMBEDSTYLE_OVERLAY)
						STplayer.addClass(STCONST_CLASS_PLAYER_EMBEDOVERLAY);
					
					// Make sure the video player has an ID
					if(!$(this).attr("id"))
						$(this).attr("id",STCONST_CLASS_VIDEOPLAYER + STplayerCount);
					
					// Register this ST player
					STplayerCache[$(this).attr("id")] = STplayer;
					if(config.videoPlayerID == "")
						STplayer.data(STCONST_DATAKEY_VIDEOPLAYERID, $(this).attr("id"));
					else
						STplayer.data(STCONST_DATAKEY_VIDEOPLAYERID, config.videoPlayerID);
					
					STplayer.data(STCONST_DATAKEY_VIDEOPLAYERTYPE, playerType);
					
					// Load the DOM elements
					var STtranscriptDisplay = STplayer.STtranscriptDisplay();
					var STtranscriptPane = STplayer.STtranscriptPane();
					var STtranscriptWrapper = STplayer.STtranscriptWrapper();
					
					var STsharePane = STplayer.STsharePane();
					
					var STscrollVisible = STplayer.STscrollVisible();
					var STplayerHandle = STplayer.STplayerHandle();
					var STplayerBase = STplayer.STplayerBase();
					var STautoScrollButton = STplayer.STautoScrollButton();
					var STtranscriptShowButton = STplayer.STtranscriptShowButton();
					
					var STsearchField = STplayer.STsearchField();
					var STsearchNextButton = STplayer.STsearchNextButton();
					var STsearchPrevButton = STplayer.STsearchPrevButton();
					
					var STfontSizeButton = STplayer.STfontSizeButton();
					
					var STmessagePane = STplayer.STmessagePane();
					
					// Set up default values
					STsearchField.val(STCONST_TEXT_BAR_SEARCH);
					
					// Remove share pane if edit mode, fix css
					if( config.editEnabled == STCONST_CONFIG_EDITENABLED_ON ) {
						STsharePane.remove();
						STplayer.addClass(STCONST_CLASS_EDITOR);
					}
					
					// Add tabindex to transcript wrapper to enable keydown events
					STtranscriptWrapper.attr("tabindex", 100);
					
					// Trigger the content select event if content is selected
					$(STtranscriptDisplay).bind("mouseup", function(e) {
						if(STgetSelectedText() != "") {
							$(this).trigger(STCONST_EVENT_CONTENT_SELECT);
						}
					});
						
					// Override copy so that it copies a quotelink
					$(STtranscriptPane).bind("copy", function(e) {
						var STplayer = $(this).parents("." + STCONST_CLASS_PLAYER).eq(0);
						var transcript = $(STplayer).STtranscript();
						var selectedContent = null;
						
						// Wrap the selection with a QuoteLink
						if (typeof window.getSelection != "undefined") {
							var userSelection = window.getSelection();
							if (userSelection.toString()) if (typeof userSelection.setBaseAndExtent != "undefined") {
								// Safari
								var mainRange = userSelection.getRangeAt(0);
								
								// Look up the earliest selected content ID
								var tempRange = mainRange.cloneRange();
								tempRange.collapse(true);
								var selectedElement = tempRange.startContainer;
								if(typeof($(selectedElement).attr("id")) == "undefined")
									selectedElement = $(selectedElement).parent();
								var contentID = $(selectedElement).attr("id").slice(STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX.length);
								selectedContent = transcript.getContentByID(contentID);
								var transcriptID = transcript.transcriptID;
								
								var quoteLinkURL = STsetURLParameterByName(window.location.href, STCONST_QUERY_PLAYER_QUOTELINK + transcriptID, selectedContent.timestamp);
								
								var container = document.createElement("div");
								$(container).css("position","absolute");
								$(container).css("left","-10000px");
								
								var frontText = "<a href='" + quoteLinkURL + "'>";
								var backText = "</a>";
								var h = frontText + $(mainRange.cloneContents()).text() + backText;
								$(container).html(h);
								
								$(document.body).append(container);
								var copyRange = document.createRange();
								copyRange.selectNode(container);
								
								userSelection.removeAllRanges();
								userSelection.addRange(copyRange);
								
								window.setTimeout(function () {
									$(container).remove();
									window.getSelection().setBaseAndExtent(mainRange.startContainer, mainRange.startOffset, mainRange.endContainer, mainRange.endOffset);
								}, 0);
							}
							else {								
								// Firefox
								// TODO -- support Opera
								var userSelection = window.getSelection();
								var mainRange = userSelection.getRangeAt(0);
								
								// Get the ID of the selected element
								var tempRange = mainRange.cloneRange();
								tempRange.collapse(true);
								var selectedElement = tempRange.startContainer;
								if(typeof($(selectedElement).attr("id")) == "undefined")
									selectedElement = $(selectedElement).parent();
								var contentID = $(selectedElement).attr("id").slice(STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX.length);
								selectedContent = transcript.getContentByID(contentID);
								var transcriptID = transcript.transcriptID;
								
								var quoteLinkURL = STsetURLParameterByName(window.location.href, STCONST_QUERY_PLAYER_QUOTELINK + transcriptID, selectedContent.timestamp);
								
								var container = document.createElement("a");
								$(container).attr("href", quoteLinkURL);
								$(container).text($(mainRange.cloneContents()).text());
								
								$(document.body).append(container);
								var copyRange = document.createRange();
								copyRange.selectNode(container);
								
								userSelection.removeAllRanges();
								userSelection.addRange(copyRange);
								
								window.setTimeout(function () {
									$(container).remove();
									userSelection.removeAllRanges();
									userSelection.addRange(mainRange);
								}, 0);
							}
						} else if (document.selection) {
							// Internet Explorer
							mainRange = document.selection.createRange();
							tempRange = document.selection.createRange();
							tempRange.collapse(true); 
							var selectedElement = tempRange.parentElement();
							var contentID = $(selectedElement).attr("id").slice(STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX.length);
							selectedContent = transcript.getContentByID(contentID);
							var transcriptID = transcript.transcriptID;
							
							var quoteLinkURL = STsetURLParameterByName(window.location.href, STCONST_QUERY_PLAYER_QUOTELINK + transcriptID, selectedContent.timestamp);
							
							var container = document.createElement("div");
							$(container).css("visibility","hidden");
							
							var frontText = "<a href='" + quoteLinkURL + "'>";
							var backText = "</a>";
							var h = frontText + mainRange.htmlText + backText;
							$(container).html(h);
							$(document.body).append(container);
							
							var newRange = document.body.createTextRange()
							newRange.moveToElementText(container);
							newRange.select();
							window.setTimeout(function () {
								mainRange.select();
								$(container).remove();
							}, 0)
						}
						$(this).trigger(STCONST_EVENT_CONTENT_COPY);
						
					});
					
					
					// Enable the ability to save changes (if edits are enabled)
					if(config.editEnabled == STCONST_CONFIG_EDITENABLED_ON) {
						var STsaveButton = STplayer.STsaveButton();
						STsaveButton.click(function(e) {
							// disable save button
							$(this).addClass('disabled');
							$(this).html('Saving...');
							
							STplayer.STshowMessage(STCONST_TEXT_MESSAGE_SAVING);
							var transcript = $(this).STtranscript();
							$.ajax({
								type: "PUT",
								url: STCONST_WS_UPDATE_TRANSCRIPT,
								data: ({hash: transcript.hash,
									    	content: transcript.content}),
								success: function(xml, status, request) {
									STplayer.STsaveButton().removeClass('disabled');
									STplayer.STsaveButton().html('Save');
									STplayer.STshowMessage(STCONST_TEXT_MESSAGE_SAVEOK);
									window.setTimeout(function() {$(STplayer).SThideMessage()}, 8000);
								}, 
								error: function(e) {
									STplayer.STsaveButton().removeClass('disabled');
									STplayer.STsaveButton().html('Save');
									STplayer.STshowMessage(STCONST_TEXT_MESSAGE_SAVEERROR);
									window.setTimeout(function() {$(STplayer).SThideMessage()}, 5000);
								}
							});
						});
					}
					
					// Enable the ability to change font size 
					STfontSizeButton.click(function(e) {
						if(STplayer.hasClass(STCONST_CLASS_PLAYER_SMALLFONT)) {
							STplayer.removeClass(STCONST_CLASS_PLAYER_SMALLFONT);
							STplayer.addClass(STCONST_CLASS_PLAYER_MEDIUMFONT);
						}
						else if(STplayer.hasClass(STCONST_CLASS_PLAYER_MEDIUMFONT)) {
							STplayer.removeClass(STCONST_CLASS_PLAYER_MEDIUMFONT);
							STplayer.addClass(STCONST_CLASS_PLAYER_SMALLFONT);
						}
						else if(STplayer.hasClass(STCONST_CLASS_PLAYER_LARGEFONT)) {
							STplayer.removeClass(STCONST_CLASS_PLAYER_LARGEFONT);
							STplayer.addClass(STCONST_CLASS_PLAYER_SMALLFONT);
						}
						else {
							STplayer.addClass(STCONST_CLASS_PLAYER_MEDIUMFONT);
						}
						STplayer.STredraw();
					});
					
					// Enable the ability to open and close the transcript by double clicking the handle
					STplayerBase.dblclick (function(e) {
						if(STplayer.hasClass(STCONST_CLASS_PLAYER_TRANSCRIPT_VISIBLE))
							$(this).trigger(STCONST_EVENT_PLAYER_HIDE);
						else
							$(this).trigger(STCONST_EVENT_PLAYER_SHOW);
					});
					
					// Enable the ability to open and close the transcript by clicking the "click to expand" text
					STtranscriptShowButton.click(function(e) {
						$(this).trigger(STCONST_EVENT_PLAYER_SHOW);
					});
						
					// Enable the ability to resize the transcript pane using the handle
					var transcriptResizeMouseStart = 0;
					var transcriptResizeTranscriptStart = 0;
					var transcriptResizeTranscriptVisible = STplayer.hasClass(STCONST_CLASS_PLAYER_TRANSCRIPT_VISIBLE);
					var startHandleDrag = function(e) {
						transcriptResizeMouseStart = e.pageY;
						transcriptResizeTranscriptStart = STtranscriptWrapper.height();
						transcriptResizeTranscriptVisible = STplayer.hasClass(STCONST_CLASS_PLAYER_TRANSCRIPT_VISIBLE);
						$("html").bind("mousemove",followHandleDrag);
						$("html").bind("mouseleave",stopHandleDrag);
						$("html").bind("mouseup",stopHandleDrag);
						return false;
					}
					var followHandleDrag = function(e) {
						var newHeight = Math.max(transcriptResizeTranscriptStart + e.pageY - transcriptResizeMouseStart,0);
						STtranscriptWrapper.height(newHeight);
						
						if(newHeight > 0 && !transcriptResizeTranscriptVisible) {
							transcriptResizeTranscriptVisible = true;
							STplayer.addClass(STCONST_CLASS_PLAYER_TRANSCRIPT_VISIBLE);
							STtranscriptPane.show();
							STsharePane.show();
						}
						else if(newHeight <=0 && transcriptResizeTranscriptVisible) {
							transcriptResizeTranscriptVisible = false;
							STplayer.removeClass(STCONST_CLASS_PLAYER_TRANSCRIPT_VISIBLE);
							STtranscriptPane.hide();
							STsharePane.hide();
						}
						
						STplayer.STredraw("handleDrag");
						return false;
					}
					var stopHandleDrag = function(e) {
						$("html").unbind("mouseup",stopHandleDrag);
						$("html").unbind("mouseleave",stopHandleDrag);
						$("html").unbind("mousemove",followHandleDrag);
						
						// Make sure the transcript is at least the min height
						if(STtranscriptWrapper.height() < config.minHeight && e.pageY != transcriptResizeMouseStart) {
							STtranscriptWrapper.animate({height: config.defaultHeight}, 200, function() {STplayer.STredraw()});
						}
					}
					STplayerBase.mousedown(startHandleDrag);
					
					
					// Create a styled scroll bar
					var scrollBarPaneHeight = 0;
					var scrollBarTranscriptHeight = 0;
					var scrollBarHandleHeight = 0;
					var scrollBarAutoScrollDisabled = 0;
					var transcriptStart = 0;
					var mouseStart = 0;
					
					var multiplier = 0;
					
					var scrollElemStyle = STtranscriptDisplay.get(0).style;
					
					var startScrollDrag = function(e) {
						var scrollBarPanePadding = STtranscriptPane.css('padding-top');
						scrollBarPanePadding = parseInt(scrollBarPanePadding.substring(0, scrollBarPanePadding.length - 2));
						transcriptStart = STtranscriptPane.offset().top + scrollBarPanePadding;
						mouseStart = e.pageY - STscrollVisible.offset().top;
						scrollBarPaneHeight = STtranscriptPane.height();
						scrollBarTranscriptHeight = STtranscriptDisplay.height() - scrollBarPaneHeight;
						scrollBarHandleHeight = STscrollVisible.height();
						
						multiplier = -1 * scrollBarTranscriptHeight / (scrollBarPaneHeight - scrollBarHandleHeight);
						
						// Turn off autoscroll
						STplayer.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL, STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_OFF);
						
						$(document).bind("mousemove",followScrollDrag);
						$(document).bind("mouseleave",stopScrollDrag);
						$(document).bind("mouseup",stopScrollDrag);
						return false;
					}
					var followScrollDrag = function(e) {
						var offset = e.pageY - transcriptStart - mouseStart;
						var newTranscriptPosition = Math.max(-scrollBarTranscriptHeight, Math.min(offset * multiplier, 0));
						// going straight up js gets us slightly better performance here I think
						scrollElemStyle.top = newTranscriptPosition + "px"; //.css("top", newTranscriptPosition);
						STplayer.STredraw("scroll");
						return false;
					}
					var stopScrollDrag = function(e) {
						$(document).unbind("mouseup",stopScrollDrag);
						$(document).unbind("mouseleave",stopScrollDrag);
						$(document).unbind("mousemove",followScrollDrag);
					}
					STscrollVisible.mousedown(startScrollDrag);
					
					// Make it so the mouse wheel scrolls the transcript
					STtranscriptPane.mousewheel(function(e, delta) {
						var paneHeight = STtranscriptPane.height();
						var transcriptHeight = STtranscriptDisplay.height() - paneHeight;
						if(transcriptHeight < 0)
							return;
							
						var coefficient = 1;
						if( isChrome() || isFirefox() || isMSIE() )
							coefficient = 16;
						
						var newTranscriptPosition = Math.max(-transcriptHeight, Math.min(STtranscriptDisplay.position().top + coefficient * delta, 0));
						
						scrollElemStyle.top = newTranscriptPosition + "px";
						STplayer = $(this).parents("." + STCONST_CLASS_PLAYER).eq(0);
						
						// Turn off autoscroll
						STplayer.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL, STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_OFF);
						
						STplayer.STredraw("scroll");
					}, true);
					
					// Make it so that up and down arrows scroll the transcript by one line
					var scrollUp = function(scrollType) {
						// Turn off autoscroll
						STplayer.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL, STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_OFF);
						
						var newTranscriptPosition = 0;
						if( scrollType == "line" )
							newTranscriptPosition = Math.min(STtranscriptDisplay.position().top + 18, 0);
						else
							newTranscriptPosition = Math.min(STtranscriptDisplay.position().top + STtranscriptPane.height() - 20, 0);
							
						STtranscriptDisplay.css("top", newTranscriptPosition);
						STplayer.STredraw("scroll");
					}
					
					var scrollDown = function(scrollType) {
						var transcriptHeight = STtranscriptDisplay.height() - STtranscriptPane.height();
						if(transcriptHeight < 0)
							return;
						
						// Turn off autoscroll
						STplayer.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL, STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_OFF);
						
						var newTranscriptPosition = 0;
						if( scrollType == "line" )
							newTranscriptPosition = Math.max(STtranscriptDisplay.position().top - 18, -transcriptHeight);
						else
							newTranscriptPosition = Math.max(STtranscriptDisplay.position().top - STtranscriptPane.height() + 20, -transcriptHeight);
							
						STtranscriptDisplay.css("top", newTranscriptPosition);
						STplayer.STredraw("scroll");
					}
					
					STtranscriptPane.keydown( function(e) {
						switch(e.keyCode) {
							case 38:
								scrollUp("line");
								break;
							
							case 33:
								scrollUp("page");
								break;
								
							case 34:
								scrollDown("page");
								break;
									
							case 40:
								scrollDown("line");
								break;
						}
						
						if( e.keyCode == 38 || e.keyCode == 33 || e.keyCode == 40 || e.keyCode == 34 )
							e.preventDefault();
					});
					
					
						/* Triggered when the autoscroll button is pressed */
						STautoScrollButton.click(function(e) {
							var STplayer = $(this).parents("." + STCONST_CLASS_PLAYER).eq(0);
							if(STplayer.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL) == STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_ON)
								STplayer.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL, STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_OFF);
							else
								STplayer.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL, STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_ON);
							STplayer.STredraw();
						});
						
						/* Triggered when the user types in the search field */
						STsearchField.keyup(function(e) {
							$(this).trigger(STCONST_EVENT_PLAYER_SEARCH);
							
							if((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13))
								$(this).trigger(STCONST_EVENT_PLAYER_SEARCHNEXT);
								
							if( $(this).val() != '' ) {
								STsearchNextButton.removeClass(STCONST_CLASS_PLAYER_SEARCHEMPTY);
								STsearchPrevButton.removeClass(STCONST_CLASS_PLAYER_SEARCHEMPTY);
							} else {
								STsearchNextButton.addClass(STCONST_CLASS_PLAYER_SEARCHEMPTY);
								STsearchPrevButton.addClass(STCONST_CLASS_PLAYER_SEARCHEMPTY);
							}
								
						});
						STsearchField.focus(function(e) {
							if($(this).hasClass(STCONST_CLASS_PLAYER_SEARCHEMPTY)) {
								$(this).removeClass(STCONST_CLASS_PLAYER_SEARCHEMPTY);
								$(this).val("");
								$(this).trigger(STCONST_EVENT_PLAYER_SEARCH);
							}
						});
						
						STsearchField.blur(function() {
							if($(this).val() == "") {
								$(this).val(STCONST_TEXT_BAR_SEARCH);
								$(this).addClass(STCONST_CLASS_PLAYER_SEARCHEMPTY);
								STsearchNextButton.addClass(STCONST_CLASS_PLAYER_SEARCHEMPTY);
								STsearchPrevButton.addClass(STCONST_CLASS_PLAYER_SEARCHEMPTY);
							}
						});
						
						/* Triggered when the user clicks "next" in search results */
						STsearchNextButton.click(function(e) {
							$(this).trigger(STCONST_EVENT_PLAYER_SEARCHNEXT);
						});
						
						/* Triggered when the user clicks "prev" in search results */
						STsearchPrevButton.click(function(e) {
							$(this).trigger(STCONST_EVENT_PLAYER_SEARCHPREV);
						});
						
						/* Triggered when a user triggers the display of the transcript */
						STplayer.bind(STCONST_EVENT_PLAYER_SHOW, function(event) {
							STplayer.addClass(STCONST_CLASS_PLAYER_TRANSCRIPT_VISIBLE);
							
							STtranscriptPane.slideDown(500);
							STsharePane.slideDown(500, function() {
								STtranscriptPane.height('');
								STplayer.STredraw();
							});
						});
						
						/* Triggered when a user wants the hiding of the  transcript */
						STplayer.bind(STCONST_EVENT_PLAYER_HIDE, function(event) {
							STtranscriptPane.slideUp(500, function() { STplayer.removeClass(STCONST_CLASS_PLAYER_TRANSCRIPT_VISIBLE); } );
							STsharePane.slideUp(500);
						});
						
						/* Triggered when a user clicks on a piece of content in a ST transcript */
						STplayer.bind(STCONST_EVENT_CONTENT_CLICKED, function(event, clickedContent) {
							STplayer.onSTVPprogress(clickedContent.timestamp, true);
							STplayer.STVPseekToAndPlay(clickedContent.timestamp);
							
							// Turn ON autoscroll
							STplayer.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL, STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_ON);
							STplayer.STredraw();
						});
						
						/* Triggered when a user searches */
						STplayer.bind(STCONST_EVENT_PLAYER_SEARCH, function(event) {
							var searchTerm = STsearchField.val();
							var transcript = STplayer.STtranscript();
							
							if(!STplayer.hasClass(STCONST_CLASS_PLAYER_TRANSCRIPT_VISIBLE))
								$(this).trigger(STCONST_EVENT_PLAYER_SHOW);
								
							// Get and store the content matches
							if(searchTerm == "") 
								var contentMatches = Array();
							else 
								var contentMatches = transcript.search(searchTerm);
							$(this).data(STCONST_DATAKEY_TRANSCRIPT_SEARCHMATCHES, contentMatches);
							
							// Show the prev / next buttons iff there is matched content
							var STsearchPrevButton = $(this).STsearchPrevButton();
							var STsearchNextButton = $(this).STsearchNextButton();
							
							// Hilight the content matches
							$(transcript.content).each(function() {
								var contentDOM = $("#" + STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX + this.id);
								var h = this.text;
								if(searchTerm != "")
									h = h.replace(new RegExp("(" + searchTerm.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1")+")",'i'), "<span class='" + STCONST_CLASS_PLAYER_SEARCHMATCH + "'>$1</span>");
								contentDOM.html(h);
							});
						});
						
						/* Triggered when a user wants to jump to the "next" content match from the search results*/
						STplayer.bind(STCONST_EVENT_PLAYER_SEARCHNEXT, function(event) {
							var searchMatches = $(this).data(STCONST_DATAKEY_TRANSCRIPT_SEARCHMATCHES);
							var currentContentID = $(this).data(STCONST_DATAKEY_TRANSCRIPT_CURRENTCONTENTID);
							var nextContent;
							
							// Analytics (do these before we check for matches because we want to track all
							// search terms, not just ones found)
							var searchTerm = $(this).STsearchField().val();
								
							// If there are no matches, there is nothing to look for
							if(searchMatches.length == 0)
								return;
							
							// if we're already past the last one, jump back to the first match
							if(currentContentID >= searchMatches[searchMatches.length-1].id)
								nextContent = searchMatches[0];
							else {
								// Find the first match after the current content ID
								for(var x in searchMatches) {
									var content = searchMatches[x];
									if(currentContentID < content.id) {
										nextContent = content;
										break;
									}
								}
							}
							
							STplayer.trigger(STCONST_EVENT_CONTENT_CLICKED,[nextContent]);
						});
						
						/* Triggered when a user clicks "prev" on the search results*/
						STplayer.bind(STCONST_EVENT_PLAYER_SEARCHPREV, function(event) {
							var searchMatches = $(this).data(STCONST_DATAKEY_TRANSCRIPT_SEARCHMATCHES);
							var currentContentID = $(this).data(STCONST_DATAKEY_TRANSCRIPT_CURRENTCONTENTID);
							var prevContent;
							
							// if we're already before the last one, jump to the last match
							if(currentContentID <= searchMatches[0].id)
								prevContent = searchMatches[searchMatches.length-1];
							else {
								for(var x in searchMatches) {
									var content = searchMatches[x];
									if(currentContentID <= content.id)
										break;
									prevContent = content;
								}
							}
							
							$(this).trigger(STCONST_EVENT_CONTENT_CLICKED,[prevContent]);
						});
						
						/* Triggered when a user selects text on a ST player */
						var deselectWatcher = function() {
							// make sure the text has time to get deselected
							setTimeout(deselectAction, 50);
						}
						
						var deselectAction = function() {
							if(STgetSelectedText() == "") {
								STplayer.trigger(STCONST_EVENT_CONTENT_DESELECT);
								$('html').unbind("mouseup", deselectWatcher);
								$('html').unbind("keyup", deselectWatcher);
							}
						}
						
						STplayer.bind(STCONST_EVENT_CONTENT_SELECT, function (event) {
							// Don't display quotelink messages if editing is enabled
							if(config.editEnabled == STCONST_CONFIG_EDITENABLED_ON)
								return;
							
							$(this).STsharePane().addClass(STCONST_CLASS_PLAYER_SHAREPANE_HIGHLIGHT).find("." + STCONST_CLASS_PLAYER_SHAREPANE_TEXT).html(STCONST_TEXT_SHARE_HIGHLIGHTED);
							
							$('html').bind("mouseup", deselectWatcher);
							$('html').bind("keyup", deselectWatcher);
						});
						
						/* Triggered when a user deselects text on a ST player */
						STplayer.bind(STCONST_EVENT_CONTENT_DESELECT, function (event) {
							$(this).STsharePane().removeClass(STCONST_CLASS_PLAYER_SHAREPANE_HIGHLIGHT).find("." + STCONST_CLASS_PLAYER_SHAREPANE_TEXT).html(STCONST_TEXT_SHARE_SELECTED);
							
							// only remove the sharepane text if it's not active
							if( ! $(this).STsharePane().hasClass(STCONST_CLASS_PLAYER_SHAREPANE_ACTIVE) ) {
								$(this).STsharePane().removeClass(STCONST_CLASS_COPY_FEEDBACK).find("." + STCONST_CLASS_PLAYER_SHAREPANE_TEXT).html(STCONST_TEXT_SHARE_UNSELECTED);
								$(this).STsharePane().find("." + STCONST_CLASS_SHARE_BUTTON).show();
							}
						});
						
						
						/* Triggered when a user copies text */
						STplayer.bind(STCONST_EVENT_CONTENT_COPY, function(event) {
							// Don't display quotelink messages if editing is enabled
							if(config.editEnabled == STCONST_CONFIG_EDITENABLED_ON)
								return;
							
							STplayer.STshowCopyMessage();
							window.setTimeout(function() {STplayer.SThideCopyMessage()}, 5000);
						});
						
						/* Triggered to handle the server response for a transcript request */
						STplayer.bind(STCONST_EVENT_TRANSCRIPT_LOADED, function(event, transcriptID) {
							// Render the transcript for every element that was waiting for the transcript to load
							$("." + STCONST_CLASS_PLAYER_TRANSCRIPT_LOADING + transcriptID).each(function() {
								$(this).removeClass(STCONST_CLASS_PLAYER_TRANSCRIPT_LOADING + transcriptID);
								$(this).STrenderTranscript(transcriptID);
								
							});
						});
					
					// Initialize Player Settings
					STplayer.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL, STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_ON);
					STplayer.data(STCONST_DATAKEY_TRANSCRIPT_CURRENTCONTENTID,0);
					STplayer.data(STCONST_DATAKEY_CONFIG, config);
					STplayer.data(STCONST_DATAKEY_TRANSCRIPT_IGNOREPROGRESS, false);
					
					if( config.editEnabled == STCONST_CONFIG_EDITENABLED_ON )
						STplayer.data(STCONST_DATAKEY_EDITMESSAGE_SHOWN, false);
						
					if( STplayer.hasClass(STCONST_CLASS_EMBEDDED) ) {
						STplayer.STtranscriptWrapper().height(config.defaultHeight);
						STplayer.STsharePane().height(config.defaultHeight + 14);
					}
					
					if(config.initialState == STCONST_CONFIG_INITIALSTATE_OPEN) {
						STplayer.trigger(STCONST_EVENT_PLAYER_SHOW);
					}
					else {
						STplayer.trigger(STCONST_EVENT_PLAYER_HIDE);
					}
					
					// LOAD THE TRANSCRIPT
					STplayer.STloadTranscriptFromPage(config.preEmbedID);
					   
				});
				
				return this;
			},
			
			//////////////////////////////////
			//// END OF ST INITIALIZATION ////
			//////////////////////////////////
			
			STcaptureQuoteLink: function() {
				var selectedText = STgetSelectedText() + "";
				var selectedContentID = STgetSelectedContentID();
				
				if( selectedText == "" ) {
					var STplayer = $(this).parents("." + STCONST_CLASS_PLAYER).eq(0);
					selectedContentID = STplayer.data(STCONST_DATAKEY_TRANSCRIPT_CURRENTCONTENTID);
					selectedText = STplayer.STtranscriptDisplay().find("#" + STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX + selectedContentID).text();
				}
				$(this).data(STCONST_DATAKEY_QUOTELINK_TEXT, selectedText);
				$(this).data(STCONST_DATAKEY_QUOTELINK_CONTENTID, selectedContentID);
			},
			
			STtwitterShare: function(popupWindow) {
				var selectedText = $(this).data(STCONST_DATAKEY_QUOTELINK_TEXT);
				var selectedContentID = $(this).data(STCONST_DATAKEY_QUOTELINK_CONTENTID);
				var popup = popupWindow;
				
				var STplayer = $(this).parents("." + STCONST_CLASS_PLAYER).eq(0);
				
				var transcript = $(STplayer).STtranscript();
				var selectedContent = transcript.getContentByID(selectedContentID);
				var transcriptID = transcript.transcriptID;
				
				var quoteLinkURL = STsetURLParameterByName(window.location.href, STCONST_QUERY_PLAYER_QUOTELINK + transcriptID, selectedContent.timestamp);
				$.ajax({
					type: "GET",
					url: "http://api.bit.ly/v3/shorten",
					dataType: "jsonp",
					data: ({login: STCONSTS_WSCREDS_BITLY_LOGIN,
							apiKey: STCONSTS_WSCREDS_BITLY_APIKEY,
							longUrl: quoteLinkURL,
							format: "json"}),
					success: function(data, status, request) {
						// Create the transcript object
						var transcript = new STTranscript()
						quoteLinkURL =  " - " + data.data.url;
						var status = selectedText.replace("\n","");
						if(status.length + quoteLinkURL.length > 140)
							status = status.slice(0,138 - quoteLinkURL.length);
						
						status = '"' + status + '"' + quoteLinkURL;
						var shareURL = "http://twitter.com/home?status=" + encodeURIComponent(status);
						popup.document.location = shareURL;
					}, 
					error: function(e) {
					}
				});
				
			},
			
			STfacebookShare: function(popupWindow) {
				var selectedText = $(this).data(STCONST_DATAKEY_QUOTELINK_TEXT);
				var selectedContentID = $(this).data(STCONST_DATAKEY_QUOTELINK_CONTENTID);
				var popup = popupWindow;
								
				var STplayer = $(this).parents("." + STCONST_CLASS_PLAYER).eq(0);
				
				var transcript = $(STplayer).STtranscript();
				var selectedContent = transcript.getContentByID(selectedContentID);
				var transcriptID = transcript.transcriptID;
				
				var quoteLinkURL = STsetURLParameterByName(window.location.href, STCONST_QUERY_PLAYER_QUOTELINK + transcriptID, selectedContent.timestamp);
				
				$.ajax({
					type: "GET",
					url: "http://api.bit.ly/v3/shorten",
					dataType: "jsonp",
					data: ({login: STCONSTS_WSCREDS_BITLY_LOGIN,
							apiKey: STCONSTS_WSCREDS_BITLY_APIKEY,
							longUrl: quoteLinkURL,
							format: "json"}),
					success: function(data, status, request) {
						// Create the transcript object
						var transcript = new STTranscript()
						quoteLinkURL =  data.data.url;
						var shareURL = "http://facebook.com/sharer.php?u=" + encodeURIComponent(quoteLinkURL) + "&t=" + encodeURIComponent(selectedText);
						popup.document.location = shareURL;
					}, 
					error: function(e) {
					}
				});
				
			},
			
			STurlShare: function() {
				var selectedText = $(this).data(STCONST_DATAKEY_QUOTELINK_TEXT);
				var selectedContentID = $(this).data(STCONST_DATAKEY_QUOTELINK_CONTENTID);
								
				var STplayer = $(this).parents("." + STCONST_CLASS_PLAYER).eq(0);
				
				var transcript = $(STplayer).STtranscript();
				var selectedContent = transcript.getContentByID(selectedContentID);
				var transcriptID = transcript.transcriptID;
				
				var quoteLinkURL = STsetURLParameterByName(window.location.href, STCONST_QUERY_PLAYER_QUOTELINK + transcriptID, selectedContent.timestamp);
				
				$.ajax({
					type: "GET",
					url: "http://api.bit.ly/v3/shorten",
					dataType: "jsonp",
					data: ({login: STCONSTS_WSCREDS_BITLY_LOGIN,
							apiKey: STCONSTS_WSCREDS_BITLY_APIKEY,
							longUrl: quoteLinkURL,
							format: "json"}),
					success: function(data, status, request) {
						// Create the transcript object
						var transcript = new STTranscript()
						quoteLinkURL =  data.data.url;
						STplayer.STshowMessage(STCONST_TEXT_MESSAGE_SHAREURL_BEGIN + quoteLinkURL + STCONST_TEXT_MESSAGE_SHAREURL_END);
						
						timeout = STplayer.data(STCONST_DATAKEY_SHAREURL_TIMEOUT);
						window.clearTimeout(timeout);
						STplayer.data(STCONST_DATAKEY_SHAREURL_TIMEOUT, window.setTimeout(function() {$(STplayer).SThideMessage()}, 10000));
					}, 
					error: function(e) {
					}
				});
				
			},
			
			/* Redraws the tool spaces for a ST player */
			
			STredraw: function(redrawType) {
				// redraw share pane
				var transcriptPane = this.STtranscriptPane();
				var transcriptDisplay = this.STtranscriptDisplay();
				var sharePane = this.STsharePane();
				
				var currentContentID = this.data(STCONST_DATAKEY_TRANSCRIPT_CURRENTCONTENTID);
				
				var	transcriptPosition = transcriptDisplay.position().top;
				var newTranscriptPosition = transcriptPosition;
				
				var transcriptHeight = transcriptDisplay.height();
				var visibleHeight = transcriptPane.height();
				
				var autoScrollFlag = this.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL);
				
				if( redrawType != "scroll" ) {
					
					if( visibleHeight <= 0 )
						sharePane.height(0);
					else
						sharePane.height(visibleHeight + 14);
				
					// Redraw Transcript Location
				
					if(currentContentID != 0 && autoScrollFlag == STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_ON) {
						var currentContent = transcriptDisplay.find("#" + STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX + currentContentID);
						// If the content is in the last visible "block" don't display it on the top -- just move to the end of the transcript
						var contentPosition = Math.min(currentContent.position().top, transcriptHeight - visibleHeight);
						var contentHeight = currentContent.height();
					
						var relativeContentPosition = contentPosition + contentHeight + transcriptPosition;
						
						if(relativeContentPosition < -1 || relativeContentPosition > visibleHeight) {
							newTranscriptPosition = -contentPosition;
						}
					}
				
					// Cancel out edge cases (where the user changes height to "below transcript base"
					var bottomHeight = -(transcriptHeight - visibleHeight);
					if(transcriptPosition < bottomHeight)
						newTranscriptPosition = Math.min(0, bottomHeight)
				
					STplayer = this;
					if( newTranscriptPosition != transcriptPosition ) {
						if( redrawType == "handleDrag" )
							transcriptDisplay.css("top", newTranscriptPosition);
						else
							transcriptDisplay.animate({top: newTranscriptPosition}, {step: function() {STplayer.STredrawScrollBar();}});
					}
				}
				
				// Redraw Auto Scroll
				var autoScrollSpace = this.find("." + STCONST_CLASS_PLAYER_AUTOSCROLL);
				var autoScrollFlag = this.data(STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL);
			
				autoScrollSpace.removeClass(STCONST_CLASS_PLAYER_AUTOSCROLL_ON + " " + STCONST_CLASS_PLAYER_AUTOSCROLL_OFF);
			
				switch(autoScrollFlag) {
					case STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_OFF:
						autoScrollSpace.addClass(STCONST_CLASS_PLAYER_AUTOSCROLL_OFF);
						break;
					case STCONST_FLAG_TRANSCRIPT_AUTOSCROLL_ON:
						autoScrollSpace.addClass(STCONST_CLASS_PLAYER_AUTOSCROLL_ON);
						break;
				}

				// Redraw Scroll Bar
				this.STredrawScrollBar();
				
			},
			
			STredrawScrollBar: function() {
				var scrollBarVisible = this.STscrollVisible();
				
				var transcriptPane = this.STtranscriptPane();
				var transcriptDisplay = this.STtranscriptDisplay();
				var transcriptHeight = transcriptDisplay.height();
				var visibleHeight = transcriptPane.height();
				var	transcriptPosition = transcriptDisplay.position().top;				
				
				if(transcriptHeight > 0 && visibleHeight < transcriptHeight) {
					var visibleBarHeight = Math.max((visibleHeight / transcriptHeight) * visibleHeight, 0) + 10;
					
					if(visibleHeight < visibleBarHeight)
						scrollBarVisible.hide();
					else if( scrollBarVisible.is(":hidden") ) {
						scrollBarVisible.show();
					}
					
					var displayPosition = -1 * transcriptPosition;
					var visibleBarPosition = (displayPosition / (transcriptHeight - visibleHeight)) * (visibleHeight - visibleBarHeight);
					
					scrollBarVisible.height(visibleBarHeight).css("top", visibleBarPosition);
				} else {
					scrollBarVisible.hide();
				}
			},
			
			/* Renders a transcript that has been loaded into the transcript cache */
			STrenderTranscript: function(transcriptID) {
				// Make sure the transcript exists in the cache
				if(!(transcriptID in STtranscriptCache))
					return this;
					
				// Make sure the transcript isn't already rendered
				if($(this).data(STCONST_DATAKEY_TRANSCRIPTID) == transcriptID)
					return;
				
				// Load the transcript from the cache
				var transcript = STtranscriptCache[transcriptID];
				var STtranscriptStatus = $(this).STtranscriptStatus();
				//if(transcript.content.length == 0) {
				//	STtranscriptStatus.html(STCONST_TEXT_TRANSCRIPT_UNAVAILABLE);
				//	return;
				//}
				//else
				
				STtranscriptStatus.html("");
				
				// Get the config for this player
				var playerConfig = $(this).data(STCONST_DATAKEY_CONFIG);
				
				// Link this ST Player to this transcript on the data level
				$(this).data(STCONST_DATAKEY_TRANSCRIPTID, transcriptID);
				
				// Generate the transcript HTML
				var editString = "";
				if(playerConfig.editEnabled == STCONST_CONFIG_EDITENABLED_ON)
					editString = " contenteditable='true'";
				
				// Render the transcript HTML
				var transcriptPane = $(this).STtranscriptPane();
				var transcriptDisplay = $(this).STtranscriptDisplay();
				
				// Only redraw the transcript if it was not embedded
				if(!$(this).hasClass(STCONST_CLASS_EMBEDDED)) {
					var sb = new Array();
					$(transcript.content).each(function() {
						sb.push("<span id='" + STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX + this.id + "' class='" + STCONST_CLASS_PLAYER_TRANSCRIPT_CONTENT + "'" + editString + ">" + this.text + "</span>");
					});
					var transcriptHTML = sb.join("");
					transcriptDisplay.html(transcriptHTML);
				} else {
					// remove embedded designation so we can reuse this container for other transcripts
					$(this).removeClass(STCONST_CLASS_EMBEDDED);
				}
				
				$(this).removeClass(STCONST_CLASS_UNINITIALIZED);
				
				var STplayer = this;
				
				// Add content events
				$(transcriptDisplay).find("." + STCONST_CLASS_PLAYER_TRANSCRIPT_CONTENT)
				.click(function(e) {
					if(playerConfig.editEnabled == STCONST_CONFIG_EDITENABLED_ON) {
						// Don't do anything if this is the currently playing segment
						if( $(this).hasClass( STCONST_CLASS_PLAYER_CURRENTCONTENT ) ) {
							return;
						}
						
						if( !STplayer.data(STCONST_DATAKEY_EDITMESSAGE_SHOWN) ) {
							STplayer.data(STCONST_DATAKEY_EDITMESSAGE_SHOWN, true);
							STplayer.STshowMessage(STCONST_TEXT_MESSAGE_EDIT);
							window.setTimeout(function() {$(STplayer).SThideMessage()}, 5000);
						}
					}
								
					// Was this a true click? or was there dragging involved
					if(STgetSelectedText() != "")
						return;
					
					// Load the content object that was clicked
					var transcript = $(this).STtranscript();
					var contentID = $(this).attr("id").slice(STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX.length);
					var clickedContent = transcript.getContentByID(contentID);
					if(!clickedContent)
						return;
					
					// Trigger the content clicked event
					$(this).trigger(STCONST_EVENT_CONTENT_CLICKED,[clickedContent]);
				});
				
				// If editing is enabled, watch for content changes
				if(playerConfig.editEnabled == STCONST_CONFIG_EDITENABLED_ON) {
					$(transcriptDisplay).find("." + STCONST_CLASS_PLAYER_TRANSCRIPT_CONTENT)
					.blur(function(e) {
						// Load the content object that was clicked
						var transcript = $(this).STtranscript();
						var contentID = $(this).attr("id").slice(STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX.length);
						
						$(this).removeClass(STCONST_CLASS_EDIT_EMPTY);
						
						if($(this).html() == "") {
							$(this).html(" ");
							$(this).addClass(STCONST_CLASS_EDIT_EMPTY);
						}
						
						transcript.updateContentByID(contentID, $(this).html());
					});
				}
				
				// Check to see if there were any QuoteLink requests
				timestamp = STgetURLParameterByName(window.location.href, STCONST_QUERY_PLAYER_QUOTELINK + transcriptID);
				if(timestamp != "") {
					timestamp = new Number(timestamp);
					var quoteLinkContent = transcript.getContentByTimestamp(timestamp);
					$(this).trigger(STCONST_EVENT_PLAYER_SHOW);
					$(this).trigger(STCONST_EVENT_CONTENT_CLICKED,[quoteLinkContent]);
				}

				
				$(this).STredraw();
				return this;
			},
		
		
		// DOM Methods
			/* Returns the video player DOM element associated with this ST player */
			STvideoPlayer: function() {
				return $("#" + $(this).data(STCONST_DATAKEY_VIDEOPLAYERID));
			},
			
			/* Returns the header bar DOM element associated with this ST player */
			STbar: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_BAR);
			},
			
			/* Returns the transcript DOM element associated with this ST player */
			STtranscriptPane: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_TRANSCRIPTPANE);
			},
			
			STsharePane: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_SHAREPANE);
			},
			
			STtranscriptDisplay: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_TRANSCRIPTDISPLAY);
			},
			
			STtranscriptWrapper: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_TRANSCRIPTWRAPPER);
			},
			
			STtranscriptStatus: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_TRANSCRIPTSTATUS);
			},
			
			/* Returns the player handle */
			STplayerHandle: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_HANDLE);
			},
			STplayerBase: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_BASE);
			},
			
			
			/* Returns the autoscroll button DOM element associated with this ST player */
			STautoScrollButton: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_AUTOSCROLL);
			},
			
			/* Returns the click to show text button DOM element associated with this ST player */
			STtranscriptShowButton: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_SHOWTEXT);
			},
			
			/* Returns the autoscroll button DOM element associated with this ST player */
			STscrollBar: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_SCROLLBAR);
			},
			
			/* Returns the autoscroll button DOM element associated with this ST player */
			STscrollUp: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_SCROLLUP);
			},
			
			/* Returns the autoscroll button DOM element associated with this ST player */
			STscrollDown: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_SCROLLDOWN);
			},
			
			/* Returns the autoscroll button DOM element associated with this ST player */
			STscrollVisible: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_SCROLLVISIBLE);
			},
			
			/* Returns the search area DOM element associated with this ST player */
			STsearch: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_SEARCH);
			},
			
			/* Returns the search field area DOM element associated with this ST player */
			STsearchField: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_SEARCHFIELD);
			},
			
			/* Returns the embed wrapper DOM element associated with this ST player */
			STembedWrapper: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_EMBEDWRAPPER);
			},
			
			/* Returns the search prev button DOM element associated with this ST player */
			STsearchPrevButton: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_SEARCHPREVBUTTON);
			},
			
			/* Returns the search next button DOM element associated with this ST player */
			STsearchNextButton: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_SEARCHNEXTBUTTON);
			},
			
			/* Returns the font size button DOM element associated with this ST player */
			STfontSizeButton: function() {
				return $(this).find("." + STCONST_CLASS_PLAYER_FONTSIZEBUTTON);
			},
			
			/* Returns the message pane DOM element associated with this ST player */
			STmessagePane: function() {
				return $(this).find("." + STCONST_CLASS_MESSAGEPANE);
			},
			
			/* Returns the transcript object associated with this ST player */
			STtranscript: function() {
				var transcriptKey;
				
				if($(this).hasClass(STCONST_CLASS_PLAYER))
					transcriptKey = $(this).data(STCONST_DATAKEY_TRANSCRIPTID);
				else
					transcriptKey = $(this).parents("." + STCONST_CLASS_PLAYER).eq(0).data(STCONST_DATAKEY_TRANSCRIPTID)
				
				var transcript = STtranscriptCache[transcriptKey];
				if(transcript)
					return STtranscriptCache[transcriptKey];
				else
					return null;
			},
			
			/* Returns the save button DOM element associated with this ST player */
			STsaveButton: function() {
				return $(this).find("." + STCONST_CLASS_EDIT_SAVE);
			},
			
			/* Returns the cancelbutton DOM element associated with this ST player */
			STcancelButton: function() {
				return $(this).find("." + STCONST_CLASS_EDIT_CANCEL);
			},
			
			/* Returns the ST player object associated with this item */
			STplayer: function() {
				var currentID = $(this).attr("id");
				if(currentID in STplayerCache)
					return STplayerCache[currentID];
				return null;
			},
			
			/* Returns the ST player autoscroll indicator */
			STautoScroll: function() {
				return $(this).find("." + STCONST_DATAKEY_TRANSCRIPT_AUTOSCROLL);
			},
			
			/* Loads transcript from where it was embedded on the page */
			STloadTranscriptFromPage: function(preEmbedID) {
				var transcriptID = preEmbedID.replace(STCONST_PLAYER_TRANSCRIPTEMBED_PREFIX + '_', '')
				var transcriptEmbed = $("#" + preEmbedID);
				
				// Mark this element as "waiting for the transcript to load"
				$(this).addClass(STCONST_CLASS_PLAYER_TRANSCRIPT_LOADING + transcriptID);

				// Let the user know what's going on
				var STtranscriptStatus = $(this).STtranscriptStatus();
				STtranscriptStatus.html(STCONST_TEXT_TRANSCRIPT_LOADING);
				
				var contentID = 1;
				var transcript = new STTranscript()
				$(transcriptEmbed).find("." + STCONST_CLASS_PLAYER_TRANSCRIPT_CONTENT).each(function() {
					var content = new STContent()
					content.id = parseInt($(this).attr("id").slice(STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX.length));
					content.timestamp = parseInt($(this).attr("name"));
					content.text = $(this).html();
					transcript.content.push(content);
				});
				transcript.transcriptID = transcriptID;
				transcript.hash = $(this).attr("data-hash");
				STtranscriptCache[transcriptID] = transcript;
				
				$(this).trigger(STCONST_EVENT_TRANSCRIPT_LOADED, [transcriptID]);
				return this;
			},
			
			STloadTranscriptFromServer: function(transcriptID) {
				// clear old tscript
				$(this).STtranscriptDisplay().html("");
				
				// If transcript has already been loaded -- render it
				if((transcriptID in STtranscriptCache) && STtranscriptCache[transcriptID] instanceof STTranscript) {
					$(this).STrenderTranscript(transcriptID);
					return this;
				}
				// If the transcript is in the process of being loaded -- mark it as "waiting for the transcript to load"
				else if((transcriptID in STtranscriptCache) && STtranscriptCache[transcriptID] instanceof XMLHttpRequest) {
					$(this).addClass(STCONST_CLASS_PLAYER_TRANSCRIPT_LOADING + transcriptID);
					return this;
				}
				
				// Mark this element as "waiting for the transcript to load"
				$(this).addClass(STCONST_CLASS_PLAYER_TRANSCRIPT_LOADING + transcriptID);

				// Let the user know what's going on
				var STtranscriptStatus = $(this).STtranscriptStatus();
				STtranscriptStatus.html(STCONST_TEXT_TRANSCRIPT_LOADING);
				
				var config = $(this).data(STCONST_DATAKEY_CONFIG);
				var url = config.transcriptPath;
				
				// add trailing slash
				if( url.length > 0 && url.charAt(url.length - 1) != '/' )
					url += '/';
				
				url += transcriptID + '.html';
				
				STplayer = $(this);

				STtranscriptCache[transcriptID] = $.ajax({
					type: "GET",
					cache: false,
					url: url,
					dataType: "html",
					success: function(html, status, request) {
						STtranscriptStatus.html("");
						var transcript = new STTranscript();
						
						$(html).find("." + STCONST_CLASS_PLAYER_TRANSCRIPT_CONTENT).each(function() {
							var content = new STContent()
							content.id = parseInt($(this).attr("id").slice(STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX.length));
							content.timestamp = parseInt($(this).attr("name"));
							content.text = $(this).html();
							transcript.content.push(content);
						});
						
						transcript.transcriptID = transcriptID;
						transcript.hash = $(html).attr("data-hash");
						STtranscriptCache[transcriptID] = transcript;

						STplayer.trigger(STCONST_EVENT_TRANSCRIPT_LOADED, [transcriptID]);
					}, 
					error: function(request, status, error) {
						// Display the loading message
						STtranscriptStatus.html(STCONST_TEXT_TRANSCRIPT_UNAVAILABLE);
					}
				});
				
				return this;
			},
			
		// Message Handlers
			STshowMessage: function(message) {
				var STmessagePane = $(this).STmessagePane();
				STmessagePane.html(message);
				STmessagePane.fadeIn(200);
			},
			
			STshowCopyMessage: function() {
				var STsharePane = $(this).STsharePane();
				STsharePane.addClass(STCONST_CLASS_COPY_FEEDBACK);
				STsharePane.find("." + STCONST_CLASS_PLAYER_SHAREPANE_TEXT).html(STCONST_TEXT_MESSAGE_COPY);
				STsharePane.find("." + STCONST_CLASS_SHARE_BUTTON).hide();
			},
			
			SThideMessage: function() {
				var STmessagePane = $(this).STmessagePane();
				STmessagePane.fadeOut(200);
			},
			
			SThideCopyMessage: function() {
				var STsharePane = $(this).STsharePane().removeClass(STCONST_CLASS_COPY_FEEDBACK);
				if( STsharePane.hasClass(STCONST_CLASS_PLAYER_SHAREPANE_HIGHLIGHT) ) {
					STsharePane.find("." + STCONST_CLASS_PLAYER_SHAREPANE_TEXT).html( STCONST_TEXT_SHARE_HIGHLIGHTED );
				}
				else if( STsharePane.hasClass(STCONST_CLASS_PLAYER_SHAREPANE_HIGHLIGHT) ) {
					STsharePane.find("." + STCONST_CLASS_PLAYER_SHAREPANE_TEXT).html( STCONST_TEXT_SHARE_SELECTED );
				}
				else {
					STsharePane.find("." + STCONST_CLASS_PLAYER_SHAREPANE_TEXT).html( STCONST_TEXT_SHARE_UNSELECTED );
				}
				
				STsharePane.find("." + STCONST_CLASS_SHARE_BUTTON).show();
				
			},
		
		// Video Player Event Handlers
			onSTVPprogress: function(timestamp, setIgnore) {
				// timestamp is time in milliseconds
				// if setIgnore == true, we will ignore all future progress events until the video player
				// actually tells us that we are at the content we wished to go to
				if(timestamp <= 0)
					return;
				
				var transcript = $(this).STtranscript();
				if(transcript == null)
					return;
				
				var currentContent = transcript.getContentByTimestamp(timestamp);
				var ignoreUntil = $(this).data(STCONST_DATAKEY_TRANSCRIPT_IGNOREPROGRESS);
				
				if( ignoreUntil !== false && !setIgnore) {
					// ignore all updates until we see a timestamp within x seconds after the requested timestamp
					if( currentContent.id < ignoreUntil || currentContent.timestamp - STCONST_PLAYER_IGNORE_THRESHOLD > transcript.getContentByID(ignoreUntil).timestamp )
						return;
					else
						$(this).data(STCONST_DATAKEY_TRANSCRIPT_IGNOREPROGRESS, false);
				}
				
				var transcriptDisplay = $(this).STtranscriptDisplay();
				var oldContentID = $(this).data(STCONST_DATAKEY_TRANSCRIPT_CURRENTCONTENTID);
				
				
				// We don't want to redo a bunch of work
				if(oldContentID == currentContent.id)
					return;
				
				$(transcriptDisplay).find("#" + STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX + oldContentID).removeClass(STCONST_CLASS_PLAYER_CURRENTCONTENT);
				$(this).data(STCONST_DATAKEY_TRANSCRIPT_CURRENTCONTENTID, currentContent.id);
				$(transcriptDisplay).find("#" + STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX + currentContent.id).addClass(STCONST_CLASS_PLAYER_CURRENTCONTENT);
				
				if( setIgnore && $(this).data(STCONST_DATAKEY_VIDEOPLAYERTYPE) != STVP_HOST_BLIP ) {
					// We'll ignore progress in the video player until we hit this content piece
					// This will fix the jumpiness associated with the inaccuracy of the YouTube player
					$(this).data(STCONST_DATAKEY_TRANSCRIPT_IGNOREPROGRESS, currentContent.id);
				}
				
				if( ! $(this).STsharePane().hasClass(STCONST_CLASS_PLAYER_SHAREPANE_ACTIVE) )
					$(this).STsharePane().addClass(STCONST_CLASS_PLAYER_SHAREPANE_ACTIVE).find("." + STCONST_CLASS_PLAYER_SHAREPANE_TEXT).html(STCONST_TEXT_SHARE_SELECTED);
					
				// Reposition if needed
				$(this).STredraw();
			},
			
			STVPseekTo: function(timestamp) {
				if( typeof( timestamp ) == "undefined" )
					return;
				
				// timestamp is in milliseconds, convert to seconds
				timestamp /= 1000.0;
				
				var playerType = $(this).data(STCONST_DATAKEY_VIDEOPLAYERTYPE);
				switch(playerType) {
					case STVP_HOST_YT:
						var ytPlayer = document.getElementById($(this).STvideoPlayer().attr("id"));
						var ytWrapper = $(ytPlayer).parent();
						ytPlayer.seekTo(timestamp, true);
						break;
					case STVP_HOST_VIMEO:
						var vimeoPlayer = document.getElementById($(this).STvideoPlayer().attr("id"));
						var vimeoWrapper = $(vimeoPlayer).parent();
						vimeoPlayer.api_seekTo(timestamp);
						break;
					case STVP_HOST_BC:
						var bcExp = brightcove.getExperience($(this).STvideoPlayer().attr("id"));
						var modVP = bcExp.getModule(APIModules.VIDEO_PLAYER);
						modVP.seek(timestamp);
						break;
					case STVP_HOST_BLIP:
						var blipPlayer = document.getElementById($(this).STvideoPlayer().attr("id"));
						blipPlayer.sendEvent("seek",timestamp);
						break;
					case STVP_HOST_OOYALA:
						var ooyalaPlayer = document.getElementById($(this).STvideoPlayer().attr("id"));
						ooyalaPlayer.setPlayheadTime(timestamp);
						break;
					case STVP_PLAYER_JW:
						var jwPlayer = document.getElementById($(this).STvideoPlayer().attr("id"));
						jwPlayer.sendEvent("SEEK", timestamp);
						break;
					default:
						break;
				}
			},
			
			STVPseekToAndPlay: function(timestamp) {
				
				var playerType = $(this).data(STCONST_DATAKEY_VIDEOPLAYERTYPE);
				switch(playerType) {
					case STVP_HOST_YT:
						var ytPlayer = document.getElementById($(this).STvideoPlayer().attr("id"));
						var ytWrapper = $(ytPlayer).parent();
						var STplayer = ytWrapper.STplayer();
						ytPlayer.seekTo(timestamp / 1000.0, true);
						ytPlayer.playVideo();
						break;
					case STVP_HOST_VIMEO:
						var vimeoPlayer = document.getElementById($(this).STvideoPlayer().attr("id"));
						var vimeoWrapper = $(vimeoPlayer).parent();
						var STplayer = vimeoWrapper.STplayer();
						vimeoPlayer.api_play();
						vimeoPlayer.api_seekTo(timestamp / 1000.0);
						break;
					case STVP_HOST_BC:
						var bcExp = brightcove.getExperience($(this).STvideoPlayer().attr("id"));
						var modVP = bcExp.getModule(APIModules.VIDEO_PLAYER);
						
						if(!modVP.isPlaying()) {
							$(this).data(STCONST_DATAKEY_PLAYERQUEUE, timestamp);
							modVP.pause(false);
						}
						else {
							modVP.seek(timestamp / 1000.0);
						}
						break;
					case STVP_HOST_BLIP:
						var blipPlayer = document.getElementById($(this).STvideoPlayer().attr("id"));
						$(this).data(STCONST_DATAKEY_PLAYERQUEUE, timestamp);
						blipPlayer.sendEvent("play");
						break;
					case STVP_HOST_OOYALA:
						var ooyalaPlayer = document.getElementById($(this).STvideoPlayer().attr("id"));
						if(ooyalaPlayer.getState() != ST_CONST_OOYALASTATE_PLAYING || $(this).data(STCONST_DATAKEY_PLAYER_DISABLED)) {
							$(this).data(STCONST_DATAKEY_PLAYERQUEUE, timestamp);
							ooyalaPlayer.playMovie();
						}
						else {
							ooyalaPlayer.setPlayheadTime(timestamp / 1000.0);
						}
						break;
					case STVP_PLAYER_JW:
						var jwPlayer = document.getElementById($(this).STvideoPlayer().attr("id"));
						if( jwPlayer.getConfig().state == "IDLE" ) {
							jwPlayer.sendEvent("PLAY");
							$(this).data(STCONST_DATAKEY_PLAYERQUEUE, timestamp);
						} else {
							jwPlayer.sendEvent("SEEK", timestamp / 1000.0); // also plays the video (if it's paused)
						}
						break;
					default:
						break;
				}
			}
	});
})(stjQuery);
	
	
/* No man's land */

function isChrome() {
	return navigator.userAgent.toLowerCase().indexOf("chrome") != -1;
}

function isFirefox() {
	return navigator.userAgent.toLowerCase().indexOf("firefox") != -1;
}

function isMSIE() {
	return navigator.userAgent.toLowerCase().indexOf("msie") != -1;
}

function STgetSelectedText() {
	if(window.getSelection){
		return window.getSelection();
	}else if (document.getSelection){
		return document.getSelection();
	}else if (document.selection){
		return document.selection.createRange().text;
	}
	return "";
}

function STgetSelectedContentID() {
	var contentID;
	if (typeof window.getSelection != "undefined") {
		var userSelection = window.getSelection();
		if (userSelection.toString()) if (typeof userSelection.setBaseAndExtent != "undefined") {
			// Safari
			var mainRange = userSelection.getRangeAt(0);
			var tempRange = mainRange.cloneRange();
			tempRange.collapse(true);
			var selectedElement = tempRange.startContainer;
			if(typeof(stjQuery(selectedElement).attr("id")) == "undefined")
				selectedElement = stjQuery(selectedElement).parent();
			return stjQuery(selectedElement).attr("id").slice(STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX.length);
		}
		else {
			// Firefox
			var userSelection = window.getSelection();
			var mainRange = userSelection.getRangeAt(0);
			var tempRange = mainRange.cloneRange();
			tempRange.collapse(true);
			var selectedElement = tempRange.startContainer;
			if(typeof(stjQuery(selectedElement).attr("id")) == "undefined")
				selectedElement = stjQuery(selectedElement).parent();
			return contentID = stjQuery(selectedElement).attr("id").slice(STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX.length);
		}
	} else if (document.selection) {
		// Internet Explorer
		mainRange = document.selection.createRange();
		tempRange = document.selection.createRange();
		tempRange.collapse(true); 
		var selectedElement = tempRange.parentElement();
		return stjQuery(selectedElement).attr("id").slice(STCONST_PLAYER_TRANSCRIPTCONTENT_PREFIX.length);
	}
}

function STgetURLParameterByName(url, name) {
	name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
	var regexS = "[\\?&]?"+name+"=([^&#]*)";
	var regex = new RegExp( regexS );
	var results = regex.exec( url );
	
	if( results == null )
		return "";
	else
		return decodeURIComponent(results[1].replace(/\+/g, " "));
}

function STsetURLParameterByName(url, name, value) {
	var returnURL = "";
	if(url.indexOf("?") != -1) {
		qlIndex = url.indexOf(name + "=");
		if(qlIndex != -1) {
			returnURL = url.substring(0,qlIndex) + name + "=" + value;
			isThereMore = url.indexOf("&", qlIndex);
			if(isThereMore > -1)
				returnURL += url.substring(isThereMore);
		}
		else {
			returnURL = url + "&" + name + "=" + value;
		}
	} else {
		returnURL = url + "?" + name + "=" + value;
	}
	return returnURL;
}

/**
 * credits for this plugin go to brandonaaron.net
 */
stjQuery.fn.extend({
	mousewheel: function(up, down, preventDefault) {
		return this.hover(
			function() {
				stjQuery.event.mousewheel.giveFocus(this, up, down, preventDefault);
			},
			function() {
				stjQuery.event.mousewheel.removeFocus(this);
			}
		);
	},
	mousewheeldown: function(fn, preventDefault) {
		return this.mousewheel(function(){}, fn, preventDefault);
	},
	mousewheelup: function(fn, preventDefault) {
		return this.mousewheel(fn, function(){}, preventDefault);
	},
	unmousewheel: function() {
		return this.each(function() {
			stjQuery(this).unmouseover().unmouseout();
			stjQuery.event.mousewheel.removeFocus(this);
		});
	},
	unmousewheeldown: stjQuery.fn.unmousewheel,
	unmousewheelup: stjQuery.fn.unmousewheel
});


stjQuery.event.mousewheel = {
	giveFocus: function(el, up, down, preventDefault) {
		if (el._handleMousewheel) stjQuery(el).unmousewheel();

		if (preventDefault == window.undefined && down && down.constructor != Function) {
			preventDefault = down;
			down = null;
		}

		el._handleMousewheel = function(event) {
			if (!event) event = window.event;
			if (preventDefault)
				if (event.preventDefault) event.preventDefault();
				else event.returnValue = false;
			var delta = 0;
			if (event.wheelDelta) {
				delta = event.wheelDelta/120;
				if (window.opera) delta = -delta;
			} else if (event.detail) {
				delta = -event.detail/3;
			}
			if (up && (delta > 0 || !down))
				up.apply(el, [event, delta]);
			else if (down && delta < 0)
				down.apply(el, [event, delta]);
		};

		if (window.addEventListener)
			window.addEventListener('DOMMouseScroll', el._handleMousewheel, false);
		window.onmousewheel = document.onmousewheel = el._handleMousewheel;
	},

	removeFocus: function(el) {
		if (!el._handleMousewheel) return;

		if (window.removeEventListener)
			window.removeEventListener('DOMMouseScroll', el._handleMousewheel, false);
		window.onmousewheel = document.onmousewheel = null;
		el._handleMousewheel = null;
	}
};
	
	
/* SpeakerText Glue
 * Dan Schultz 2010
 */

/* Player ID Info */
var  STVP_PLAYER_AUTOID_PREFIX = "STautoID";

/* Video Player Hosts */
var  STVP_HOST_YT = 1;
var  STVP_HOST_VIMEO = 2;
var  STVP_HOST_BC = 3;
var  STVP_HOST_BLIP = 4;
var  STVP_HOST_OOYALA = 5;
var  STVP_HOST_SELF = 7;

var  STVP_PLAYER_JW = 1000;

/* Youtube Constants */
var  ST_CONST_YTSTATE_UNSTARTED = -1;
var  ST_CONST_YTSTATE_ENDED = 0;
var  ST_CONST_YTSTATE_PLAYING = 1;
var  ST_CONST_YTSTATE_PAUSED = 2;
var  ST_CONST_YTSTATE_BUFFERING = 3;
var  ST_CONST_YTSTATE_CUED = 5;

/* Blip.TV Constants */
var  ST_CONST_BLIPUPDATE_STATECHANGE = "player_state_change";
var  ST_CONST_BLIPUPDATE_PROGRESS = "time";
var  ST_CONST_BLIPUPDATE_PROGRESS_2 = "current_time_change";

/* Ooyala Constants */
var  ST_CONST_OOYALASTATE_PLAYING = "playing";
var  ST_CONST_OOYALASTATE_PAUSED = "paused";
var  ST_CONST_OOYALASTATE_BUFFERING = "buffering";

	
// Embed Setups
(function($) {
	$(function() {
		var autoID = 0;
		
		// select all objects and all embeds which are not children of objects
		$("object, embed:not(object > embed)").each(function() {
			autoID++;
			var target = $(this);
			
			// Set up the swfobject parameters
			var playerID = target.attr("id");
			if(typeof(playerID) == "undefined" || playerID == "")
				playerID = STVP_PLAYER_AUTOID_PREFIX + autoID;
				
			target.attr("id",playerID);
			target.attr("name",playerID);
				
			var src = "";
			if( this.tagName.toLowerCase() == "embed" ) {
				src = target.attr("src");
			} else {
				var em = target.find("embed");
				if( em.length )
					src = em.attr("src");
				else if( target.attr("data") )
					src = target.attr("data");
				else
					return true;
			}

			var height = target.attr("height");
			var width = target.attr("width");
			var fixEmbeds = function() {

				var params = {};

				// carry over params
				if( target.get(0).tagName.toLowerCase() == "object") {
					target.find("param").each( function() {
						params[$(this).attr("name")] = $(this).attr("value");
					});
				}
				
				params["allowScriptAccess"] = 'always';
				
				var atts = { id: playerID, name: playerID };
				
				if(src.match("youtube.com")) {
					// YouTube
					if(STgetURLParameterByName(src, "enablejsapi") != 1)
						src = STsetURLParameterByName(src, "enablejsapi", 1);
					if(STgetURLParameterByName(src, "playerapiid") != 1)
						src = STsetURLParameterByName(src, "playerapiid", playerID);
					
					swfobject.embedSWF(src, playerID, width, height, '8', null, null, params, atts);
				}
				else if(src.match("blip.tv")) {
					// Blip.tv
					swfobject.embedSWF(src, playerID, width, height, '8', null, null, params, atts);
				}
				// else if(src.match("vimeo.com")) {
				// 	// Vimeo
				// 	if(STgetURLParameterByName(src, "js_api") != 1)
				// 		src = STsetURLParameterByName(src, "js_api", 1);
				// 	if(STgetURLParameterByName(src, "js_swf_id") != 1)
				// 		src = STsetURLParameterByName(src, "js_swf_id", playerID);
				// 	if(STgetURLParameterByName(src, "js_onLoad") != 1)
				// 		src = STsetURLParameterByName(src, "js_onLoad", "vimeo_player_loaded");
				// 	
				// 	swfobject.embedSWF(src, playerID, width, height, '8', null, null, params, atts);
				// } 
				else {
					// we should probably try to determine whether or not this is a video player like JW
					//swfobject.embedSWF(src, playerID, width, height, '8', null, null, params, atts);
				}
			}
			// make sure swfobject is loaded
			if(typeof(swfobject) == "undefined") {
				$.getScript("http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js", fixEmbeds);
			}
			else {
				fixEmbeds();
			}

		});
		
		// add Brightcove API script to page if main Brightcove JS is loaded and it's not there already
		if( typeof( brightcove ) != "undefined" && typeof( APIModules ) == "undefined" ) {
			var host = brightcove.cdnURL;
			if( window.location.protocol == 'https:' )
				host = brightcove.secureCDNURL;
							
			$.ajax({
				async: false,
				type: "GET",
				url: host + "/js/APIModules_all.js",
				dataType: 'script'
			});
		}
	});
})(stjQuery);

function setupSpeakerText(elem, player_id, opts) {
	elem.speakerText(player_id, opts);
							
	var STplayer = elem.STplayer();
	var STmessagePane = STplayer.STmessagePane();
	var STembedWrapper = STplayer.STembedWrapper();
	var videoWidth = Math.max(400, elem.width());
	STplayer.width(videoWidth - (STplayer.outerWidth() - STplayer.innerWidth()));
	STmessagePane.width(videoWidth - (STmessagePane.outerWidth() - STmessagePane.innerWidth()));
	STembedWrapper.width(videoWidth - (STembedWrapper.outerWidth() - STembedWrapper.innerWidth()));
	
	// position speakertext directly under the video player
	if( elem.css("text-align") == "center" )
		STplayer.css("margin", "0 auto");
	else
		STplayer.css("margin-left", elem.css("margin-left"));
	
	if( STplayer.width() < 460 )
		STplayer.addClass('narrow');
		
	return STplayer;
}

////////////////////////////////////////
////          YOUTUBE GLUE          ////
////////////////////////////////////////

function onYouTubePlayerReady(playerID) {
	(function($) {
		if(typeof(playerID) == "undefined")
			return;
		var ytPlayer = document.getElementById(playerID);
		var ytWrapper = $(ytPlayer).parent();
		if(!ytWrapper.is("object"))
			ytWrapper = $(ytPlayer);
		
		// Initialize the Player
		if($(ytPlayer).is("object")) {
			src = $(ytPlayer).attr("data");
			if(typeof(src) == "undefined" || src == "")
				src = $(ytPlayer).find("param[name='movie']").attr("value");
		}
		else
			src = $(ytPlayer).attr("src");
		
		var videoID = src.match(/v\/[a-zA-Z0-9_\-]+/)[0].slice(2);
		var STplayer = setupSpeakerText(ytWrapper, STVP_HOST_YT, {videoPlayerID: playerID, 
																															preEmbedID: STCONST_PLAYER_TRANSCRIPTEMBED_PREFIX + "_" + STVP_HOST_YT + "_" + videoID });	
		
		// Add state change handler
		//ytPlayer.addEventListener("onStateChange", '(function(state) { return STYTplayerStateChange(state, "' + playerID + '"); })');
		
		// Add progress listeners
		window.setInterval(function() {
			var currentTimestamp = ytPlayer.getCurrentTime();
			var queuePoint = $(STplayer).data(STCONST_DATAKEY_PLAYERQUEUE);
			if(typeof(queuePoint) == "undefined") {
				// triggered when reembedding with swfobject
				STplayer.data(STCONST_DATAKEY_PLAYERQUEUE, -1);
			}
			else if(queuePoint != -1) {
				STplayer.data(STCONST_DATAKEY_PLAYERQUEUE, -1);
				STplayer.STVPseekTo(queuePoint);
			}
			else {
				STplayer.onSTVPprogress(currentTimestamp * 1000, false);
			}
		}, 100);
	})(stjQuery);
}

function STYTplayerStateChange(state, playerID) {
	var state = state;
	(function($) {
		var ytPlayer = document.getElementById(playerID);
		var ytWrapper = $(ytPlayer).parent();
		if(!ytWrapper.is("object"))
			ytWrapper = $(ytPlayer);
		var STplayer = ytWrapper.STplayer();
		switch(state) {
			case ST_CONST_YTSTATE_UNSTARTED:
				break;
			case ST_CONST_YTSTATE_ENDED:
				break;
			case ST_CONST_YTSTATE_PLAYING:
				// Gets triggered every time a new video is selected
				// This event also seems to be the only one triggered on autoplay videos
				//var currentVideoID = STgetURLParameterByName(ytPlayer.getVideoUrl(), "v");
				//STplayer.STloadTranscriptFromVideoID(STVP_HOST_YT, currentVideoID);
				break;
			case ST_CONST_YTSTATE_PAUSED:
				break;
			case ST_CONST_YTSTATE_BUFFERING:
				break;
			case ST_CONST_YTSTATE_CUED:
				// This seems to be the only thing triggered when swfobject embeds a video (and it doesn't autoplay)
				// hopefully its not a problem to rerender the transcript when we get the playing event as well
				// although it doesn't seem to be necessary right now so i took it out
				//var currentVideoID = STgetURLParameterByName(ytPlayer.getVideoUrl(), "v");
				//STplayer.STloadTranscriptFromVideoID(STVP_HOST_YT, currentVideoID);
				break;
		}
	})(stjQuery);
}

////////////////////////////////////////
////       BRIGHTCOVE GLUE          ////
////////////////////////////////////////

function onTemplateLoaded(experienceID) {
	(function($) {
		var bcExpID = experienceID;
		var bcExp = brightcove.getExperience(bcExpID); 
		var modVP = bcExp.getModule(APIModules.VIDEO_PLAYER);
		var modExp = bcExp.getModule(APIModules.EXPERIENCE);
		var modCon = bcExp.getModule(APIModules.CONTENT);
		var experienceObject = $("#" + experienceID);

		// Add content load listener
		var contentLoaded = function() {
			var currentVideo = modVP.getCurrentVideo();
			
			// Set up the player
			var videoID = currentVideo.id;
			
			var STplayer = setupSpeakerText(experienceObject, STVP_HOST_BC, {preEmbedID: STCONST_PLAYER_TRANSCRIPTEMBED_PREFIX + "_" + STVP_HOST_BC + "_" + videoID });
			modVP.pause(true);
		}
		
		if( modVP.getCurrentVideo() != null ) {
			// in case we missed the event
			contentLoaded();
		}
		else {
			modExp.addEventListener(BCExperienceEvent.CONTENT_LOAD, contentLoaded);
		}
		
		// Add media event listeners
		modVP.addEventListener(BCMediaEvent.PROGRESS, function (evt) {
			var STplayer = experienceObject.STplayer();
			var queuePoint = $(STplayer).data(STCONST_DATAKEY_PLAYERQUEUE);
			if(queuePoint != -1) {
				STplayer.data(STCONST_DATAKEY_PLAYERQUEUE, -1);
				STplayer.STVPseekTo(queuePoint);
			}
			else {
				STplayer.onSTVPprogress(evt.position * 1000, false);
			}
		});
	})(stjQuery);
}

////////////////////////////////////////
////          BLIP.TV GLUE          ////
////////////////////////////////////////

function getUpdate(type, arg1, arg2) {
	(function($) {
		// Since there is no ID for blip we can only support the first player
		var src = '';
		var swf = $("embed[src*='blip.tv']").first();

		if( typeof(swf_id) == "undefined" ) {
			swf = $("object[data*='blip.tv']").first();
			src = $(swf).attr("data");
		}
		else {
			src = $(swf).attr("src");
		}
		
		var blipPlayer = document.getElementById($(swf).attr('id'));
		
		// Extract the episode ID
		var episodeID = src.match(/play\/[a-zA-Z0-9]+/)[0].slice(5);
		
		// Since there is no initialization method for blip, make sure ST was set up
		if(!$(blipPlayer).hasSpeakerText()) {
			var STplayer = setupSpeakerText($(blipPlayer), STVP_HOST_BLIP, {videoPlayerID: $(swf).attr('id'), 
																																			preEmbedID: STCONST_PLAYER_TRANSCRIPTEMBED_PREFIX + "_" + STVP_HOST_BLIP + "_" + episodeID });
		} else {
			var STplayer = $(blipPlayer).STplayer();
		}
		
		switch(type) {
			case ST_CONST_BLIPUPDATE_STATECHANGE:
				break;
			
			case ST_CONST_BLIPUPDATE_PROGRESS:
			case ST_CONST_BLIPUPDATE_PROGRESS_2:
				var queuePoint = STplayer.data(STCONST_DATAKEY_PLAYERQUEUE);
				if(queuePoint != -1) {
					STplayer.data(STCONST_DATAKEY_PLAYERQUEUE, -1);
					STplayer.STVPseekTo(queuePoint);
				}
				else {
					STplayer.onSTVPprogress(arg1 * 1000, false);
				}
				break;
		}
	})(stjQuery);
}

////////////////////////////////////////
////          VIMEO GLUE            ////
////          BROKEN                ////
////////////////////////////////////////

// Vimeo Glue
// function vimeo_player_loaded(swf_id) {
// 	(function($) {
// 		if(typeof(swf_id) == "undefined")
// 			return;
// 		
// 		var vimeoPlayer = document.getElementById(swf_id);
// 		var vimeoWrapper = $(vimeoPlayer).parent();
// 		
// 		// Look up the clip ID
// 		var clipID = STgetURLParameterByName($(vimeoPlayer).attr("data"), "clip_id");
// 		
// 		var STplayer = setupSpeakerText(vimeoWrapper, STVP_HOST_VIMEO, STVP_HOST_VIMEO, clipID, {videoPlayerID: swf_id});
// 		
// 		// Load the transcript
// 		STplayer.STloadTranscriptFromVideoID(STVP_HOST_VIMEO, clipID);
// 		
// 		// Add progress handler
// 		vimeoPlayer.api_addEventListener("onProgress", "STvimeo_on_progress");
// 		vimeoPlayer.api_addEventListener("onLoading", "STvimeo_on_loading");
// 	})(stjQuery);
// }
// 
// function STvimeo_on_progress(time, swf_id) {
// 	(function($) {
// 		if(typeof(swf_id) == "undefined")
// 			return;
// 		
// 		var vimeoPlayer = document.getElementById(swf_id);
// 		var vimeoWrapper = $(vimeoPlayer).parent();
// 		var STplayer = vimeoWrapper.STplayer();
// 		
// 		var queuePoint = $(STplayer).data(STCONST_DATAKEY_PLAYERQUEUE);
// 		if(queuePoint != -1) {
// 			STplayer.data(STCONST_DATAKEY_PLAYERQUEUE, -1);
// 			STplayer.STVPseekTo(queuePoint);
// 		}
// 		else {
// 			STplayer.onSTVPprogress(time * 1000, false);
// 		}
// 		
// 	})(stjQuery);
// }
// 
// function STvimeo_on_loading(data, swf_id) {
// 	(function($) {
// 		if(typeof(swf_id) == "undefined")
// 			return;
// 		
// 		var vimeoPlayer = document.getElementById(swf_id);
// 		var vimeoWrapper = $(vimeoPlayer).parent();
// 		var STplayer = vimeoWrapper.STplayer();
// 	})(stjQuery);
// }

////////////////////////////////////////
////          OOYALA GLUE           ////
////////////////////////////////////////

function st_ooyala_callback(playerId, eventName, eventParams) {
	(function($) {
		var ooyalaPlayer = document.getElementById(playerId);
		var ooyalaWrapper = $(ooyalaPlayer).parent();
		
		//console.log(eventName);
		//if( eventName == "stateChanged" )
			//console.log(eventParams.state);
		
		switch(eventName) {
			case "apiReady":
			
				// Look up the clip ID
				var currentItem = ooyalaPlayer.getCurrentItem();
				var videoID = currentItem.embedCode;
				
				var STplayer = setupSpeakerText(ooyalaWrapper, STVP_HOST_OOYALA, {videoPlayerID: playerId,
																																					preEmbedID: STCONST_PLAYER_TRANSCRIPTEMBED_PREFIX + "_" + STVP_HOST_OOYALA + "_" + videoID });
				
				STplayer.data(STCONST_DATAKEY_PLAYER_DISABLED, false);
				
				break;
			case "playheadTimeChanged":
				var STplayer = ooyalaWrapper.STplayer();
				
				// don't track any progress unless we're not in an ad
				if (!STplayer.data(STCONST_DATAKEY_PLAYER_DISABLED)) {
					var queuePoint = STplayer.data(STCONST_DATAKEY_PLAYERQUEUE);
					if(queuePoint != -1) {
						STplayer.data(STCONST_DATAKEY_PLAYERQUEUE, -1);
						STplayer.STVPseekTo(queuePoint);
					}
					else {
						STplayer.onSTVPprogress(eventParams.playheadTime * 1000, false);
					}
				}
				break;
				
			case "adStarted":
				var STplayer = ooyalaWrapper.STplayer();
				STplayer.data(STCONST_DATAKEY_PLAYER_DISABLED, true);
				break;
			
			case "adCompleted":
				var STplayer = ooyalaWrapper.STplayer();
				STplayer.data(STCONST_DATAKEY_PLAYER_DISABLED, false);
				break;
		}
	})(stjQuery);
}

////////////////////////////////////////
////        JW PLAYER GLUE          ////
////////////////////////////////////////

function playerReady(obj) {
	if( typeof( obj.id ) == "undefined" )
		return;
		
	var jwPlayer = document.getElementById(obj.id);
		
	jwPlayer.addModelListener("TIME", "st_jw_onProgress");
	jwPlayer.addControllerListener("ITEM", "st_jw_itemChanged");
}

function st_jw_itemChanged(obj) {
	(function($) {
		if( typeof( obj.id ) == "undefined" )
			return;

		var jwPlayer = document.getElementById(obj.id);
		var STplayer = $(jwPlayer).STplayer();
		var current_item = jwPlayer.getPlaylist()[obj.index];
		
		if (STplayer == null) {
			// Allow user to override the way we match video player and transcript player
			var embed_id = $(jwPlayer).attr('data-stid');
			if( typeof(embed_id) !== 'undefined' && embed_id !== false ) {
				clipID = embed_id.replace(STCONST_PLAYER_TRANSCRIPTEMBED_PREFIX + '_', '').split('_')[1];
				var STplayer = setupSpeakerText($(jwPlayer), STVP_PLAYER_JW, {videoPlayerID: obj.id,
																																			preEmbedID: STCONST_PLAYER_TRANSCRIPTEMBED_PREFIX + "_" + STVP_HOST_SELF + "_" + clipID });
			} else if( typeof(current_item['captionbox']) !== 'undefined' ) {
			 		var clipID = current_item['captionbox'];
			 		var STplayer = setupSpeakerText($(jwPlayer), STVP_PLAYER_JW, {videoPlayerID: obj.id,
			 																																	preEmbedID: STCONST_PLAYER_TRANSCRIPTEMBED_PREFIX + "_" + clipID });
			} else {
				var finishJWInitialization = function() {
					// Look up the filename
					var filename = current_item.file;
		
					// only take the pathname
					var dummyLink = $('<a/>').attr('href',filename)[0];
					filename = dummyLink.pathname.replace(/^[^\/]/,'/') + dummyLink.search;
					var clipID = sha1Hash(filename);
		
					var STplayer = setupSpeakerText($(jwPlayer), STVP_PLAYER_JW, {videoPlayerID: obj.id,
																																				preEmbedID: STCONST_PLAYER_TRANSCRIPTEMBED_PREFIX + "_" + STVP_HOST_SELF + "_" + clipID });
				}
	
				if( typeof(sha1Hash) == "undefined" ) {
		
					var path = $("script[src*=" + STCONST_FILENAME + "]").attr('src').replace( new RegExp("(.*)" + STCONST_FILENAME + ".*"), '$1');
					$.getScript(path + "sha1.js", finishJWInitialization);
				} else {
					finishJWInitialization();
				}
			}
		} else {
			// reset current content id
			STplayer.data(STCONST_DATAKEY_TRANSCRIPT_CURRENTCONTENTID,0);
			
			var cb_url = current_item['captionbox'];
			STplayer.STloadTranscriptFromServer(cb_url);
		}
		
	})(stjQuery);
}

function st_jw_onProgress(obj) {
	(function($) {
		if(typeof(obj.id) == "undefined")
			return;
		
		var jwPlayer = document.getElementById(obj.id);
		var STplayer = $(jwPlayer).STplayer();
		
		if( STplayer == null )
			return;
		
		var queuePoint = $(STplayer).data(STCONST_DATAKEY_PLAYERQUEUE);

		if(queuePoint != -1 && jwPlayer.getConfig().state == "PLAYING") {
			STplayer.data(STCONST_DATAKEY_PLAYERQUEUE, -1);
			STplayer.STVPseekTo(queuePoint);
		}
		else {
			STplayer.onSTVPprogress(parseFloat(obj.position) * 1000, false);
		}
		
	})(stjQuery);
}
