if (window.tcc_package_tcsmainplayer===undefined) {
 var tcc_package_tcsmainplayer=1;
/** Start: flivpee.js */
/**
 * @fileoverview
 * <p>
 * This file is part of Flivpee.
 * </p>
 * <p>
 * Flivpee is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * </p>
 * <p>
 * Flivpee is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * </p>
 * <p>
 * You should have received a copy of the GNU General Public License
 * along with Flivpee.  If not, see http://www.gnu.org/licenses/
 * </p>
 */

/** @class An enumerator for player events. */
function EventFlivpee(){};
EventFlivpee.READY = "flvp_ready";
EventFlivpee.LOADING = "flvp_loading";
EventFlivpee.PLAYING = "flvp_playing";
EventFlivpee.STOPPED = "flvp_stopped";
EventFlivpee.NOT_FOUND = "flvp_not_found";
EventFlivpee.PAUSED = "flvp_paused";
EventFlivpee.SEEK_SUCCESS = "flvp_seek_success";
EventFlivpee.SEEK_FAILED = "flvp_seek_failed";
EventFlivpee.VOLUME_UPDATE = "flvp_volume_update";

/** @class An enumerator for button events. */
function EventFlivpeeButton(){};
EventFlivpeeButton.OVER = "fb_over";
EventFlivpeeButton.OUT = "fb_out";
EventFlivpeeButton.PRESS = "fb_press";
EventFlivpeeButton.RELEASE = "fb_release";
EventFlivpeeButton.DISABLED = "fb_disabled";
EventFlivpeeButton.ENABLED = "fb_enabled";

/** @class An enumerator for slider events. */
function EventFlivpeeSlider(){};
EventFlivpeeSlider.UPDATE = "fs_update";
EventFlivpeeSlider.RELEASE = "fs_release";

/** @class An enumerator for widget types. */
function FlivpeeWidget(){};
FlivpeeWidget.MESSAGES = "flvpw_messages";
FlivpeeWidget.MUTE = "flvpw_mute";
FlivpeeWidget.PAUSE = "flvpw_pause";
FlivpeeWidget.STOP = "flvpw_stop";
FlivpeeWidget.UNPAUSE = "flvpw_unpause";
FlivpeeWidget.VOLUME = "flvpw_volume";
FlivpeeWidget.DURATION = "flvpw_duration";
FlivpeeWidget.TIMELINE = "flvpw_timeline";
FlivpeeWidget.BUFFER = "flvpw_buffer";


/**
 * @class
 * An instance manager. This is a way for the Flash embed to get back to the page instance. Also, this will contain logic to handle to updates to all the instances in one setInterval (so that we might have decent performance with multiple instances of the player).
 */
function FlivpeeManager(){};
/** @private */
FlivpeeManager._instances = [];
/** @private */
FlivpeeManager._uinterval = null;
/** @private */
FlivpeeManager._upointer = 0;
/** @private The number of milliseconds between timeline and time display updates. */
FlivpeeManager._update_ms = 250;
/**
 * @param {Flivpee} flivpee_instance	An instance of Flivpee.
 */
FlivpeeManager.add_instance = function( flivpee_instance ){
	FlivpeeManager._instances.push( flivpee_instance );
	FlivpeeManager._check_uinterval();
	return FlivpeeManager._instances.length-1;
};
/**
 * This method finds an instance of Flivpee by its index number. This is used internally for Flivpee -> Flash communication. When you instantiate Flivpee, you should keep a reference to it rather than relying on this.
 * @param {int} index	An index to an instance of Flivpee.
 */
FlivpeeManager.find_instance = function( index ){
	return FlivpeeManager._instances[index];
};
/**
 * This method will change the update speed for the timeline and time display of all instances of Flivpee. If there's already a update interval running, we'll clear it and restart with the new speed.
 * @param {Number} ms    The number of milliseconds between updates.
 */
FlivpeeManager.set_update_speed = function( ms ){
	if( !isNaN(ms) && ms > 0 ) FlivpeeManager._update_ms = Math.round(ms);
	if( FlivpeeManager._uinterval != null )
	{
		clearInterval( FlivpeeManager._uinterval );
		FlivpeeManager._check_interval();
	}
};
/**
 * @private
 * This method will be run everytime an instance of Flivpee is registered. It will check if the update interval has been started. If it hasn't been, it will start it. This update intervel will increment through all the instances of Flivpee on the page and run the update method. This method will ultimately query the Flash movie for the position of the video in the stream and get the current buffer position. I'm limiting the player in this way to avoid bogging down the page with requests between the Flash player and the page.
 */
FlivpeeManager._check_uinterval = function(){
	if( FlivpeeManager._uinterval == null )
	{
		FlivpeeManager._uinterval = setInterval( FlivpeeManager._update, FlivpeeManager._update_ms );
	}
};
/**
 * @private
 * Handles the updates for all Flivpee instances.
 */
FlivpeeManager._update = function(){
	if( FlivpeeManager._upointer > FlivpeeManager._instances.length-1 )
	{
		FlivpeeManager._upointer = 0;
	}
	FlivpeeManager._instances[FlivpeeManager._upointer]._update();
	FlivpeeManager._upointer++;
};



/**
 * @class
 * The main class; the one you'll be interacting with most.
 *
 * @param {String} swf    The path to the Flivpee swf. It plays the videos.
 * @param {int} width    The width of the player.
 * @param {int} height    The height of the player.
 * @param {Color} background_color    The background color of the player in hex, i.e. #ffffff.
 * @param {Boolean} debug    Whether or not to turn on debugging for this instance of the player.
 */
function Flivpee( swf, width, height, background_color, as3_fullscreen, debug ){
	this._widgets_div = document.createElement("div");
	this._widgets_div.className = "flivpee_box";
	this._widgets_div.style.position = "relative";
	this._events = {};
	this._update_props = new FlivpeeUpdateProps();
	
	try
	{
		this._index = FlivpeeManager.add_instance( this );
		this._debug = debug==true||debug=="true" ? true : false;
		this._as3_fullscreen = as3_fullscreen==true||as3_fullscreen=="true" ? true : false;
		
		this._swf_object = new SWFObject( swf, "flivpee_embed_"+this._index, width, height, "9", background_color );
		this._swf_object.addParam( "allowScriptAccess", "always" );
		this._swf_object.addParam( "allowFullscreen", "true" );
		this._swf_object.addParam( "swfLiveConnect", "true" );
		this._swf_object.addParam( "wmode", "window" );
		this._swf_object.addParam( "quality", "high" );
		this._swf_object.addVariable( "name", this._index );
		this._swf_object.addVariable( "debug", this._debug );
		this._swf_object.addVariable( "enable_fullscreen", this._as3_fullscreen );
	}
	catch(e)
	{
		if( this._debug )
		{
			console.error( this.toString()+" failed to construct, error:\n"+e );
		}
	}
	
	try
	{
		this._events[EventFlivpee.READY] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpee.LOADING] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpee.PLAYING] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpee.STOPPED] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpee.NOT_FOUND] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpee.PAUSED] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpee.SEEK_SUCCESS] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpee.SEEK_FAILED] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpee.VOLUME_UPDATE] = new FlivpeeEventBroadcaster();
	}
	catch(e)
	{
		if( this._debug )
		{
			console.error( this.toString()+" failed to initialize events, error:\n"+e );
		}
	}
};
Flivpee.prototype = {
	/** @private */
	_index: "",
	/** @private */
	_as3_fullscreen: null,
	/** @private */
	_debug: false,
	/** @private */
	_swf_object: null,
	/** @private */
	_embed: null,
	/** @private */
	_events: null,
	/** @private */
	_widgets_div: null,
	/** @private */
	_w_messages: null,
	/** @private */
	_w_mute: null,
	/** @private */
	_w_pause: null,
	/** @private */
	_w_stop: null,
	/** @private */
	_w_unpause: null,
	/** @private */
	_w_volume: null,
	/** @private */
	_w_duration: null,
	/** @private */
	_w_timeline: null,
	/** @private */
	_w_buffer: null,
	/** @private */
	_volume_muted: .5,
	/** @private */
	_volume_current: .5,
	/** @private */
	_update_props: null,
	toString: function(){
		return '[Flivpee]';
	},
	/**
	 * Writes the Flivpee DOM inside a div you've provided on your page.
	 *
	 * @param {String} target_div_id    The ID of a div on the page.
	 */
	write: function( target_div_id ){
		try
		{
			var box = document.getElementById( target_div_id );

			var flash_box = document.createElement("div");
			flash_box.className = "flivpee_flash_box";
			this._widgets_div.appendChild( flash_box );

			this._build_all_widgets();
			box.appendChild( this._widgets_div );
			
			this._swf_object.write( flash_box );
			this._embed = document.getElementById( "flivpee_embed_"+this._index );
		}
		catch(e)
		{
			if( this._debug )
			{
				console.error( this.toString()+" failed to write embed, error:\n"+e );
			}
		}
	},
	/**
	 * Adds a listener to this instance of the player. The <i>method</i> will be called whenever the event <i>type</i> is called.
	 *
	 * @param {String} type    The event type from EventFlivpee.
	 * @param {Object} obj    The object on which to apply the method scope.
	 * @param {Function} method    A reference to the method on the <i>obj</i>.
	 *
	 * @see EventFlivpee
	 */
	add_listener: function( type, obj, method ){
		try
		{
			this._events[type].add_listener( obj, method );
		}
		catch(e)
		{
			if( this._debug )
			{
				console.error( this.toString()+" failed to add a listener for event '"+type+"', error:\n"+e ); 
			}
		}
	},
	/** @private */
	_build_all_widgets: function(){
		this._w_messages = new FlivpeeMessages( this._build_widget_div(), "flivpee_messages" );
		this._w_mute = new FlivpeeButton( this._build_widget_div(), "flivpee_mute" );
		this._w_pause = new FlivpeeButton( this._build_widget_div(), "flivpee_pause" );
		this._w_stop = new FlivpeeButton( this._build_widget_div(), "flivpee_stop" );
		this._w_unpause = new FlivpeeButton( this._build_widget_div(), "flivpee_unpause" );
		this._w_volume = new FlivpeeSlider( this._widgets_div, "flivpee_volume" );
		this._w_timeline = new FlivpeeSlider( this._widgets_div, "flivpee_timeline" );
		this._w_buffer = new FlivpeeProgress( this._widgets_div, "flivpee_buffer" );
		this._w_duration = new FlivpeeDuration( this._build_widget_div(), "flivpee_duration" );

		this._w_mute.add_listener( EventFlivpeeButton.PRESS, this, this.mute_toggle );
		this._w_pause.add_listener( EventFlivpeeButton.PRESS, this, this.pause_toggle );
		this._w_stop.add_listener( EventFlivpeeButton.PRESS, this, this.stop );
		this._w_unpause.add_listener( EventFlivpeeButton.PRESS, this, this.pause_toggle );

		this._w_volume.add_listener( EventFlivpeeSlider.UPDATE, this, this.update_volume );
		this._w_timeline.add_listener( EventFlivpeeSlider.UPDATE, this, this.update_seek );

		this.add_listener( EventFlivpee.VOLUME_UPDATE, this._w_volume, this._w_volume.set_position );
		this._w_timeline.disable();
	},
	/** @private */
	_build_widget_div: function( id ){
		var div = document.createElement("div");
		//div.id = id;
		this._widgets_div.appendChild( div );
		return div;
	},
	/**
	 * @private
	 * This will send the current properties into the Flash and get back the current timeline stats.
	 */
	_update: function(){
		var s;
		if( this._embed && this._embed.flivpee_update_pipe )
		{
			var s = this._embed.flivpee_update_pipe( this._update_props.get_position(), this._update_props.get_volume() );
			this._update_props = new FlivpeeUpdateProps();
		}
		
		if( s )
		{
			var time = s.time;
			var duration = s.duration;
			var buffer = s.buffer;
			var position = s.position;
	
			this._w_duration.display( this._seconds_to_string(time), this._seconds_to_string(duration) );

			if( position>-1 )
			{
				this._w_timeline.set_position( position );
			}
			if( buffer>-1 )
			{
				this._w_buffer.update( buffer );
			}
		}
	},
	/** @private */
	_seconds_to_string: function( s ){
		if( s > -1 )
		{
			var nm = Math.floor( s/60 );
			var ns = Math.round( s%60 );
			
			return nm + ":" + ( ns<10 ? "0"+ns : ns );
		}
		return "0:00";
	},
	/**
	 * Plays a video at a <i>url</i>.
	 *
	 * @param {String} url    A path to an FLV to play.
	 */
	play: function( url ){
		this._embed.flivpee_play( url );
	},
	/** Stops playback of the player. */
	stop: function(){
		this._embed.flivpee_stop();
	},
	/**
	 * Pauses or unpauses, depending on <i>bool</i>.
	 * @param {Boolean} bool    Whether or not to pause the player.
	 */
	pause: function( bool ){
		this._embed.flivpee_pause( bool );
	},
	/** Toggles playback of the video. */
	pause_toggle: function(){
		this._embed.flivpee_pause_toggle();
	},
	/**
	 * Jumps to a point in the video.
	 *
	 * @param {Float} pos    A number, 0-1, representing the point in the stream to which you want to jump.
	 */
	seek: function( pos ){
		this._embed.flivpee_seek( pos );
	},
	/**
	 * Changes the volume of the audio.
	 *
	 * @param {Float} pos    A number, 0-1, representing the volume of the player. 0 is mute; 1 is full volume.
	 */
	volume: function( pos ){
		this._embed.flivpee_volume( pos );
	},
	/**
	 * Toggles muting of the volume. It will restore the same volume when it was originally muted.
	 */
	mute_toggle: function(){
		if( this._volume_current > 0 )
		{
			this._volume_muted = this._volume_current;
			this.volume( 0 );
		}
		else
		{
			this.volume( this._volume_muted );
		}
	},
	/**
	 * This is part of the update pipeline. It will update the current FlivpeeUpdateProps with the volume from the slider. When the update event is called on an instance of Flivpee, it will pass is the latest value from this function.
	 */
	update_volume: function( pos ){
		this._update_props.set_volume( pos );
	},
	/**
	 * This is part of the update pipeline. It will update the current FlivpeeUpdateProps with the latest seek position from the slider. When the update is called on an instance of Flivpee, it will pass the latest value into the Flash.
	 */
	update_seek: function( pos ){
		this._update_props.set_position( pos );
	},
	/** @private */
	ready: function(){
		if( this._debug )
		{
			console.debug( this.toString()+" ready" );
		}
		// Sometimes the player is ready before the line line defining the embed (in the write function)...strange.
		this._embed = document.getElementById( "flivpee_embed_"+this._index );
		this._events[EventFlivpee.READY].broadcast();
	},
	/** @private */
	loading: function(){
		if( this._debug )
		{
			console.debug( this.toString()+" loading" );
		}
		this._events[EventFlivpee.LOADING].broadcast();
		this._w_messages.show_event( "loading" );
	},
	/** @private */
	playing: function(){
		if( this._debug )
		{
			console.debug( this.toString()+" playing" );
		}
		this._events[EventFlivpee.PLAYING].broadcast();
		this._w_messages.show_event( "playing" );
		this._w_timeline.enable();
		this._w_pause.enable();
		this._w_unpause.disable();
		this._w_stop.enable();
	},
	/** @private */
	stopped: function(){
		if( this._debug )
		{
			console.debug( this.toString()+" stopped" );
		}
		this._events[EventFlivpee.STOPPED].broadcast();
		this._w_messages.show_event( "stopped" );
		this._w_timeline.disable();
		this._w_pause.disable();
		this._w_unpause.disable();
		this._w_stop.disable();
	},
	/** @private */
	not_found: function(){
		if( this._debug )
		{
			console.debug( this.toString()+" not_found" );
		}
		this._events[EventFlivpee.NOT_FOUND].broadcast();
		this._w_messages.show_event( "not_found" );
		this._w_timeline.disable();
	},
	/** @private */
	paused: function( bool ){
		if( this._debug )
		{
			console.debug( this.toString()+" paused? "+bool );
		}
		this._events[EventFlivpee.PAUSED].broadcast([bool]);

		if( bool )
		{
			this._w_messages.show_event( "playing" );
			this._w_pause.disable();
			this._w_unpause.enable();
		}
		else
		{
			this._w_messages.show_event( "paused" );
			this._w_pause.enable();
			this._w_unpause.disable();
		}
	},
	/** @private */
	seek_success: function(){
		if( this._debug )
		{
			console.debug( this.toString()+" seek_success" );
		}
		this._events[EventFlivpee.SEEK_SUCCESS].broadcast();
	},
	/** @private */
	seek_failed: function(){
		if( this._debug )
		{
			console.debug( this.toString()+" seek_failed" );
		}
		this._events[EventFlivpee.SEEK_FAILED].broadcast();
	},
	/** @private */
	volume_update: function( pos ){
		if( this._debug )
		{
			console.debug( this.toString()+" volume_update : "+pos );
		}
		this._events[EventFlivpee.VOLUME_UPDATE].broadcast([pos]);
		this._volume_current = pos;
	}
};

/**
 * @class
 * A class to store properties to send to the Flash movie when the update event happens. We'll use this so that the sliders can update as much as they want without worrying about bogging down the page. This is to solve a performance problem I noticed in Opera. It will be used as an update pipeline.
 */
function FlivpeeUpdateProps(){
	this._newpos = -1;
	this._newvol = -1;
};
FlivpeeUpdateProps.prototype = {
	/** @private */
	_newpos:null,
	/** @private */
	_newvol:null,
	/**
	 * Sets the position to store.
	 *
	 * @param {Float} position    A number, 0-1, representing the new position.
	 */
	set_position:function( position ){
		this._newpos = position;
	},
	/**
	 * Sets the volume to store.
	 *
	 * @param {Float} volume    A number, 0-1, representing the new volume.
	 */
	set_volume:function( volume ){
		this._newvol = volume;
	},
	/**
	 * Returns the stored position.
	 */
	get_position:function(){
		return this._newpos;
	},
	/**
	 * Returns the stored volume.
	 */
	get_volume:function(){
		return this._newvol;
	}
};



/**
 * @class
 * An event broadcaster. This is a utility for Flivpee.
 */
function FlivpeeEventBroadcaster(){
	this._l = [];
};
FlivpeeEventBroadcaster.prototype = {
	/** @private */
	_l: null,
	/** @private */
	_p: null,
	/**
	 * Add a listener to this event.
	 *
	 * @param {Object} obj    An object on which to apply scope.
	 * @param {Function} method    A method on <i>obj</i> to call when this class broadcasts.
	 */
	add_listener: function( obj, method ){
		var new_entry = new FlivpeeEventBroadcasterEntry(obj, method);
		this._l.push( new_entry );
		if( this._p != null )
		{
			new_entry.broadcast( this._p );
		}
	},
	/**
	 * Broadcast an events.
	 *
	 * @param {Array} params    An array of method paramters to pass to the listeners. If there's a function( one, two ){}, then params would be ["one_string", "two_string"].
	 */
	broadcast: function( params ){
		this._p = params==null ? [] : params;
		if( this._l.length == 1 )
		{
			this._l[0].broadcast( this._p );
		}
		else if( this._l.length > 0 )
		{
			for( var i in this._l )
			{
				this._l[i].broadcast( this._p );
			}
		}
	}
};



/**
 * @private
 * @class
 * An entry for the FlivpeeEventBroadcaster. Pay no attention to this.
 */
function FlivpeeEventBroadcasterEntry( obj, method ){
	this._obj = obj;
	this._method = method;
};
FlivpeeEventBroadcasterEntry.prototype = {
	_obj: null,
	_method: null,
	broadcast: function( params ){
		this._method.apply( this._obj, params );
	}
};



/**
 * @class
 * This is a button. You can listen to its events defined in {@link EventFlivpeeButton}.
 *
 * @param {HTMLDivElement} node    A reference to the div to turn into a button.
 * @param {String} style_name    The base style name. The div will be assigned this as a base class name. When a button event is called it will append another class name in this format: style_name+"_over", style_name+"_press", style_name+"_disabled". So, finally, the full class name for a button with style_name="mybutton" on an over event will be "mybutton mybutton_over".
 */
function FlivpeeButton( node, style_name ){
	this._enabled = true;
	
	// Events
	try
	{
		this._node = node;
		var _this = this;
		
		this._node.onmouseover = function( event )
		{
			_this._over.apply( _this, [event] );
		}
		
		this._node.onmouseout = function( event )
		{
			_this._out.apply( _this, [event] );
		}
		
		this._node.onmousedown = function( event )
		{
			_this._press.apply( _this, [event] );
		}
		
		this._node.onclick = function( event )
		{
			_this._release.apply( _this, [event] );
		}
	}
	catch(e)
	{
		try
		{
			console.error( this.toString()+" events failed to initialize, error: "+e );
		}
		catch(e){}
	}
	
	// Style
	try
	{
		this._style_base = style_name;
		this._style_over = style_name + "_over";
		this._style_press = style_name + "_press";
		this._style_disabled = style_name + "_disabled";
		
		if( this._node.className.length > 0 )
		{
			this._style_base = this._node.className + " " + this._style_base;
		}
		
		this._node.className = this._style_base;
	}
	catch(e)
	{
		try
		{
			console.error( this.toString()+" style initialization failed, error: "+e );
		}
		catch(e){}
	}
	
	// Broadcaster
	try
	{
		this._events = {};
		this._events[EventFlivpeeButton.OVER] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpeeButton.OUT] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpeeButton.PRESS] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpeeButton.RELEASE] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpeeButton.DISABLED] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpeeButton.ENABLED] = new FlivpeeEventBroadcaster();
	}
	catch(e)
	{
		try
		{
			console.error( this.toString()+" broadcaster initialization failed, error: "+e );
		}
		catch(e){}
	}
}
FlivpeeButton.prototype = {
	/** @private */
	_node: null,
	/** @private */
	_style_base: null,
	/** @private */
	_style_over: null,
	/** @private */	
	_style_press: null,
	/** @private */
	_style_disabled: null,
	/** @private */
	_events: null,
	/** @private */
	_enabled: null,
	toString: function(){
		return "[FlivpeeButton]";
	},
	/**
	 * @return {HTMLDivElement}    A reference to the DOM element.
	 */
	get_node: function(){
		return this._node;
	},
	/**
	 * Listen to this button's events.
	 *
	 * @param {String} event    An event type from {@link EventFlivpeeButton}.
	 * @param {Object} obj    An object on which to apply scope for the <i>method</i>.
	 * @param {Function} method    The function to call when an event is executed.
	 */
	add_listener: function( event, obj, method ){
		try
		{
			this._events[event].add_listener( obj, method );
		}
		catch(e)
		{
			try
			{
				console.error( this.toString()+" failed to add an event listener for event '"+event+"', error: "+e );
			}
			catch(e){}
		}
	},
	/** Disable the button. */
	disable: function(){
		this._enabled = false;
		this._node.className = this._style_base + " " + this._style_disabled;
		this._events[EventFlivpeeButton.DISABLED].broadcast();
	},
	/** Enable the button. */
	enable: function(){
		this._enabled = true;
		this._node.className = this._style_base;
		this._events[EventFlivpeeButton.ENABLED].broadcast();
	},
	/** @private */
	_over: function( event ){
		if( this._enabled )
		{
			this._node.className = this._style_base + " " + this._style_over;
			this._events[EventFlivpeeButton.OVER].broadcast( [event] );
		}
	},
	/** @private */
	_out: function( event ){
		if( this._enabled )
		{
			this._node.className = this._style_base;
			this._events[EventFlivpeeButton.OUT].broadcast( [event] );
		}
	},
	/** @private */
	_press: function( event ){
		if( this._enabled )
		{
			this._node.className = this._style_base + " " + this._style_press;
			this._events[EventFlivpeeButton.PRESS].broadcast( [event] );
		}
	},
	/** @private */
	_release: function( event ){
		if( this._enabled )
		{
			this._node.className = this._style_base + " " + this._style_over;
			this._events[EventFlivpeeButton.RELEASE].broadcast( [event] );
		}
	}
};


/**
 * @class
 * This is a slider widget. The user can click and drag on a handle inside the <i>node</i>. You can add a listener to the {@link EventFlivpeeSlider} to make it do stuff.
 *
 * @param {HTMLDivElement} node    A div in which to build the slider.
 * @param {String} style_name    The base class name for this slider. The bar or background will have the class name style_name+"_bar" and the handle will be a {@link FlivpeeButton} with a base style of style_name+"_handle".
 */
function FlivpeeSlider( node, style_name ){
	try
	{
		this._active = false;
		this._node = node;
		
		var bar_div = document.createElement("div");
		bar_div.className = style_name + "_bar";
		
		var handle_div = document.createElement("div");
		// IE 7 doesn't seem to be applying this style, so it needs to be 
		// defined in the stylesheet.
		// TODO: Put this as a requirement in the documentation.
		//handle_div.setAttribute( "style", "position:absolute; left:0px;" );
		
		bar_div.appendChild( handle_div );
		this._node.appendChild( bar_div );
		
		this._bar = bar_div;
		this._handle = new FlivpeeButton( handle_div, style_name+"_handle" );
		
		this._handle.add_listener( EventFlivpeeButton.PRESS, this, this._handle_press );
		this._handle.add_listener( EventFlivpeeButton.RELEASE, this, this._handle_release );
	}
	catch(e)
	{
		try
		{
			console.error( this.toString()+" failed to initialize the DOM, error: "+e );
		}catch(e){}
	}
	
	try
	{
		this._events = {};
		this._events[EventFlivpeeSlider.UPDATE] = new FlivpeeEventBroadcaster();
		this._events[EventFlivpeeSlider.RELEASE] = new FlivpeeEventBroadcaster();
	}
	catch(e)
	{
		try
		{
			console.error( this.toString()+" failed to initialize events, error: "+e );
		}catch(e){}
	}
}
FlivpeeSlider.prototype = {
	/** @private */
	_node: null,
	/** @private */
	_bar: null,
	/** @private */
	_handle: null,
	/** @private */
	_mouse_base_x: null,
	/** @private */
	_handle_base_x: null,
	/** @private */
	_handle_max_x: null,
	/** @private */
	_events: null,
	/** @private */
	_active: null,
	toString: function(){
		return "[FlivpeeSlider]";
	},
	/**
	 * Listen to this slider's events.
	 *
	 * @param {String} event    An event type from {@link EventFlivpeeSlider}.
	 * @param {Object} obj    An object on which to apply scope for the <i>method</i>.
	 * @param {Function} method    A function to call when the event has been called.
	 */
	add_listener: function( event, obj, method ){
		try
		{
			this._events[event].add_listener( obj, method );
		}
		catch(e)
		{
			try
			{
				console.error( this.toString()+" failed to add a listener for event '"+event+"', error: "+e );
			}catch(e){}
		}
	},
	/**
	 * Manually sets the position of the handle.
	 * 
	 * @param {Float} pos    The position as a number, 0-1. The x position will become the handles maximum x position * pos.
	 */
	set_position: function( pos ){
		if( !this._active )
		{
			if( isNaN(pos) ) pos = 0;
			if( pos < 0 ) pos = 0;
			if( pos > 1 ) pos = 1;
			
			this._calculate_handle_props();
			
			var target_pos = Math.floor( this._handle_max_x * pos );
			this._handle.get_node().style.left = target_pos + "px";
		}
	},
	/**
	 * Disables the slider handle.
	 */
	disable: function(){
		this._handle.disable();
	},
	/**
	 * Enables the slider handle.
	 */
	enable: function(){
		this._handle.enable();
	},
	/** @private */
	_handle_press: function( event ){
		if( event && event.clientX!=null )
		{
			this._mouse_base_x = event.clientX;
		}
		else
		{
			this._mouse_base_x = window.event.clientX;
		}
		this._calculate_handle_props();
		
		this._watch();
		
		this._active = true;
	},
	/** @private */
	_handle_release: function( event ){
		this._unwatch();
		this._active = false;
	},
	/** @private */
	_update: function( event ){
		var x;
		if( event && event.clientX!=null )
		{
			x = event.clientX;
		}
		else
		{
			x = window.event.clientX;
		}
		
		var dist = x - this._mouse_base_x;
		var handle_dist = this._handle_base_x + dist;
		
		if( handle_dist < 0 )
		{
			handle_dist = 0;
		}
		else if( handle_dist > this._handle_max_x )
		{
			handle_dist = this._handle_max_x;
		}
		
		this._handle.get_node().style.left = handle_dist + "px";
		this._events[EventFlivpeeSlider.UPDATE].broadcast( [ handle_dist/this._handle_max_x ] );
	},
	/** @private */
	_watch: function(){
		var _this = this;
		
		this._bar.onmousemove = function( event )
		{
			_this._update.apply( _this, [event] );
		}
		this._bar.onmouseout = function( event )
		{
			_this._unwatch.apply( _this );
		}
	},
	/** @private */
	_unwatch: function(){
		if( this._bar.onmousemove != null )
		{
			this._bar.onmousemove = null;
			
			var handle_dist = parseInt( this._handle.get_node().style.left );
			this._events[EventFlivpeeSlider.RELEASE].broadcast( [ handle_dist/this._handle_max_x ] );
		}
	},
	_calculate_handle_props: function(){
		this._handle_base_x = parseInt( this._handle.get_node().style.left );
		// this doesn't work in Safari and Konqueror, so...
		if( isNaN(this._handle_base_x) ) this._handle_base_x = 0;
		
		this._handle_max_x = this._bar.offsetWidth - this._handle.get_node().offsetWidth;
	}
};



/**
 * @class
 * A progress bar. It just scales a nested div to a certain percentage (represented as a number, 0-1). The style_name will be the base class name for the elements. A background and indicator will be generated with class names: style_name+"_background" and style_name+"_indicator".
 *
 * @param {HTMLDivElement} node    A div with which to make a progress bar.
 * @param {String} style_name    This will be the base style name.
 */
function FlivpeeProgress( node, style_name ){
	try
	{
		this._enabled = true;
		this._current_pos = 0;
		this._node = node;
		
		var bg = document.createElement("div");
		bg.className = style_name + "_background";
		
		var bar = document.createElement("div");
		bar.className = style_name + "_indicator";
		bar.setAttribute( "style", "position:absolute; left:0px; top:0px; width:0%;" );
		
		bg.appendChild( bar );
		this._node.appendChild( bg );
		this._bar = bar;
	}
	catch( e )
	{
		try{
			console.error( this.toString()+" construction failed, error : "+e );
		}catch(e){}
	}
}
FlivpeeProgress.prototype = {
	/** @private */
	_node: null,
	/** @private */
	_bar: null,
	/** @private */
	_enabled: null,
	/** @private */
	_current_pos: null,
	toString: function(){
		return "[FlivpeeProgress]";
	},
	/**
	 * Updates the progress display.
	 *
	 * @param {Float} pos    A number, 0-1, representing the progress you wish to display.
	 */
	update: function( pos ){
		this._current_pos = pos;
		
		if( this._enabled )
		{
			var per;
			if( pos >= 0 && pos <= 1 )
			{
				per = Math.floor( pos*100 );
			}
			else if( pos <= 100 )
			{
				per = Math.floor( pos );
			}
			this._bar.style.width = per+"%";
		}
	},
	/**
	 * Disables the progress bar.
	 */
	disable: function(){
		this._enabled = false;
		this._bar.style.width = "0%";
	},
	/**
	 * Enables the progress bar.
	 */
	enable: function(){
		this._enabled = true;
		this.update( this._current_pos );
	}
};

/**
 * @class
 * This class will display the states of the current player.
 *
 * @param {HTMLDivElement} node    A node to use to display the messages.
 * @param {String} style_name    The base class name for the messages.
 */
function FlivpeeMessages( node, style_name ){
	try
	{
		this._node = node;
		this._style_base = style_name;
		this._node.className = this._style_base;
	}
	catch(e)
	{
		try{
			console.error( this.toString()+" construction failed, error : "+e );
		}catch(e){}
	}
};
FlivpeeMessages.prototype = {
	/** @private */
	_node: null,
	/** @private */
	_style_base:"",
	toString: function()
	{
		return "[FlivpeeMessages]";
	},
	/**
	 * Changes the class name for the div to reflect this arbitrary string.
	 *
	 * @param {String} str_event    The new class name for the div will be style_name+" "+style_name+"_"+event.
	 */
	show_event: function( str_event )
	{
		this._node.className = this._style_base + " " + this._style_base+"_"+str_event;
	}
};

/**
 * @class
 * Displays the current position and duration of the current video. This class will create two span nodes with class names "flivpee_duration_position" and "flivpee_duration_total" separated with a "/".
 *
 * @param {HTMLDivElement} node    The DOM node with which to create the duration display.
 * @param {String} style_name    The base class name for the elements of the duration display.
 */
function FlivpeeDuration( node, style_name )
{
	try
	{
		this._node = node;
		this._style_base = style_name;
		this._node.className = this._style_base;

		this._pos_dom = document.createElement("span");
		this._dur_dom = document.createElement("span");
		var sep = document.createTextNode("/");

		this._pos_dom.className = "flivpee_duration_position";
		this._dur_dom.className = "flivpee_duration_total";

		this._node.appendChild( this._pos_dom );
		this._node.appendChild( sep );
		this._node.appendChild( this._dur_dom );

	}
	catch( e )
	{
		try{
			console.error( this.toString()+" construction failed, error : "+e );
		}catch(e){}
	}
};
FlivpeeDuration.prototype = {
	/** @private */
	_node: null,
	/** @private */
	_pos_dom: null,
	/** @private */
	_dur_dom: null,
	/** @private */
	_style_base: "",
	toString: function()
	{
		return "[FlivpeeDuration]";
	},
	/**
	 * Display the position and duration.
	 *
	 * @param {String} position
	 * @param {String} duration
	 */
	display: function( position, duration )
	{
		this._pos_dom.innerHTML = position;
		this._dur_dom.innerHTML = duration;
	}
};

/** End: flivpee.js */
/** Start: player.js */
var tc_Player=function(name,container,video,width,height,type,loop){this._hasFlash=swfobject.getFlashPlayerVersion().major!==0;this._name=name;this._container=container;this._video=video;this._width=width;this._height=height;this._type=type;this._observers={};this._observers[EventFlivpee.READY]=[];this._observers[EventFlivpee.PLAYING]=[];this._observers[EventFlivpee.STOPPED]=[];this.addObserver(EventFlivpee.PLAYING,function(){this._playing=true});var stopped;if(loop===true){stopped=function(){this._playing=false;if(this._type===tc_Player.TYPE_MUSIC){this._player.seek(0)}else{this.play()}}}else{stopped=function(){this._playing=false;this._player._widgets_div.className="player_box player_not_started player_"+this._type}}this.addObserver(EventFlivpee.STOPPED,stopped)};tc_Player.prototype={_alternativeContent:undefined,_container:undefined,_hasFlash:true,_height:undefined,_name:undefined,_observers:undefined,_openWindow:false,_paused:false,_player:undefined,_playing:false,_preview:undefined,_video:undefined,_width:undefined,_window:undefined,_setEvents:function(control){var instance=this;var types=[EventFlivpee.PLAYING,EventFlivpee.STOPPED];for(var type=0;type<types.length;type++){for(var index=0;index<this._observers[types[type]].length;index++){this._player.add_listener(types[type],this,this._observers[types[type]][index])}}this._player.add_listener(EventFlivpee.PAUSED,this,function(paused){this._paused=pause});var play=function(){if(instance.isPlaying()===false){instance.play()}else{instance.togglePause()}};var overlay=control.getOverlay();if(overlay!==undefined){overlay.onclick=play}this._player._w_unpause.add_listener(EventFlivpeeButton.PRESS,this,play)},addObserver:function(type,callback){this._observers[type].push(callback)},destruct:function(){if(this._player!==undefined){this._player._update=Prototype.emptyFunction;this._player.stop()}},isPaused:function(){return this._paused},isPlaying:function(){return this._playing},openWindow:function(){tc_load("/s/tc-www/js/window.js");var instance=this;var windowContainer=this._window;if(windowContainer===undefined){windowContainer=this._container}var overlay=new tc_Overlay(this._name,undefined,"player_window_overlay",windowContainer);overlay.addObserver({update:function(subject){if(subject.getStatus()==="close"){if(instance._player!==undefined){instance._player.stop()}}}});overlay.open();var container=new tc_Window(this._name,undefined,"player_window",windowContainer);container.get().style.width=this._width+"px";container.setContentHTML('<div id="player_window_'+this._name+'_player" class="player_window_player"></div>');var close=function(){overlay.close();container.close()};var actions=new tc_Window_Actions();actions.add({id:"stop",title:"",callback:function(){instance._player.stop()}});container.setActions(actions);var control=new tc_PlayerControl("player_window_"+this._name+"_player",this._width,this._height);for(var index=0;index<this._observers[EventFlivpee.READY].length;index++){control._player.add_listener(EventFlivpee.READY,this,this._observers[EventFlivpee.READY][index])}control._player.add_listener(EventFlivpee.READY,this,this.play);control._player.add_listener(EventFlivpee.STOPPED,this,function(){this._player._update=Prototype.emptyFunction;this._player=undefined;window.setTimeout(close,0)});control.setFlashParam("enable_fullscreen",false);this._player=control.create();control.getBox().className+=" player_"+this._type;this._setEvents(control);container.open();var button=$("player_window_"+this._name+"_actions_stop");button.onmouseover=function(){this.className="player_window_action_stop player_window_action_stop_over"};button.onmouseout=function(){this.className="player_window_action_stop"};button.onmousedown=function(){this.className="player_window_action_stop player_window_action_stop_press"}},play:function(){this._player._widgets_div.className="player_box player_started player_"+this._type;this._player.play(this._video)},run:function(){var width=this._width;var height=this._height;if(this._openWindow===true||this._hasFlash===false){if(this._preview!==undefined){width=this._preview.width;height=this._preview.height}else{var size=$(this._container).getDimensions();if(width>240){width=Math.min(240,size.width)}if(height>240){height=Math.min(240,size.height);if(height===0){height=180}height-=18}}}var control=new tc_PlayerControl(this._container,width,height);for(var index=0;index<this._observers[EventFlivpee.READY].length;index++){control._player.add_listener(EventFlivpee.READY,this,this._observers[EventFlivpee.READY][index])}if(this._preview!==undefined){control.setPreview(this._preview.image,this._preview.width,this._preview.height)}this._player=control.create();control.getBox().className+=" player_"+this._type;if(this._hasFlash===true&&this._openWindow!==true){this._setEvents(control)}else{this._player._update=Prototype.emptyFunction;var instance=this;var windowOpener=document.createElement("div");windowOpener.className="player_window_opener";if(this._hasFlash===true){windowOpener.onclick=function(){instance.openWindow()}}else{control._readyFlash=true;control._setReady();if(this._alternativeContent!==undefined){windowOpener.innerHTML=this._alternativeContent}}control.getBox().appendChild(windowOpener)}},setAlternativeContent:function(content){this._alternativeContent=content},setOpenWindow:function(openWindow,windowContainer){this._openWindow=openWindow;this._window=windowContainer},setPreview:function(image,width,height){this._preview={image:image,width:width,height:height}},togglePause:function(){this._player.pause_toggle()}};tc_Player.TYPE_MUSIC="type_music";tc_Player.TYPE_VIDEO="type_video";var tc_PlayerControl=function(container,width,height){this._container=container;this._width=width;this._height=height;if(height===0){height=1}this._player=new Flivpee("/s/tc-www/js/modules/flivpee/flivpee.swf",width,height,"#ffffff",true,false);this._player._swf_object.addParam("wmode","opaque");this._player.add_listener(EventFlivpee.READY,this,function(){this._readyFlash=true;this._setReady()})};tc_PlayerControl.prototype={_container:undefined,_height:undefined,_overlay:undefined,_player:undefined,_preview:undefined,_readyFlash:false,_readyRun:false,_width:undefined,_setReady:function(){if(this._readyFlash===true&&this._readyRun===true){this._player._widgets_div.className=this._player._widgets_div.className.replace("player_not_ready","player_not_started");var elements=this._player._widgets_div.getElementsByTagName("div");elements[1].style.height=this._height+"px";if(Prototype.Browser.IE===true){elements[1].style.overflow="hidden"}}},create:function(){var instance=this;this._player.write(this._container);var elements=this._player._widgets_div.getElementsByTagName("div");elements[1].style.width=this._width+"px";this._player._widgets_div.className="player_box player_not_ready";this._player._widgets_div.style.width=this._width+"px";this._player._widgets_div.style.height=this._height+"px";if(this._width>168){this._player._tcSeekbar.style.width=this._width-168+"px"}else{this._player._tcSeekbar.style.display="none"}elements=this._player._widgets_div.getElementsByTagName("span");elements[0].innerHTML="0:00";elements[1].innerHTML="0:00";if(this._height>0){this._overlay=document.createElement("div");this._overlay.className="player_overlay";this._overlay.style.width=this._width+"px";this._overlay.style.height=this._height+"px";this._player._widgets_div.appendChild(this._overlay);if(this._preview!==undefined){var preview=document.createElement("img");preview.src=this._preview.image;preview.width=this._preview.width;preview.height=this._preview.height;preview.className="player_preview";if(this._height>this._preview.height){preview.style.paddingTop=(this._height-this._preview.height)/2+"px"}preview.alt="";this._overlay.appendChild(preview)}var overlayInner=document.createElement("div");overlayInner.className="player_overlay_inner";this._overlay.appendChild(overlayInner)}this._readyRun=true;this._setReady();return this._player},getBox:function(){return this._player._widgets_div},getOverlay:function(){return this._overlay},setFlashParam:function(param,value){this._player._swf_object.addVariable(param,value)},setPreview:function(image,width,height){this._preview={image:image,width:width,height:height}}};Flivpee.prototype._tcControls=undefined;Flivpee.prototype._tcSeekbar=undefined;Flivpee.prototype._build_all_widgets=function(){controlsContainer=this._build_widget_div(this._widgets_div);controlsContainer.className="player_controls_container";controlsOuter=this._build_widget_div(controlsContainer);controlsOuter.className="player_controls_outer";this._tcControls=this._build_widget_div(controlsOuter);this._tcControls.className="player_controls_inner";this._w_messages=new FlivpeeMessages(this._build_widget_div(),"player_messages");this._w_stop=new FlivpeeButton(this._build_widget_div(),"player_stop");this._w_unpause=new FlivpeeButton(this._build_widget_div(),"player_unpause");this._w_pause=new FlivpeeButton(this._build_widget_div(),"player_pause");this._tcSeekbar=this._build_widget_div();this._tcSeekbar.className="player_seekbar";this._w_buffer=new tc_PlayerProgress(this._tcSeekbar,"player_buffer");this._w_timeline=new FlivpeeSlider(this._tcSeekbar,"player_timeline");this._w_duration=new FlivpeeDuration(this._build_widget_div(),"player_duration");this._w_mute=new FlivpeeButton(this._build_widget_div(),"player_mute");volumeOuter=this._build_widget_div(this._tcControls);volumeOuter.className="player_volume_bar_outer";volumeInner=this._build_widget_div(volumeOuter);volumeInner.className="player_volume_bar_inner";this._w_volume=new FlivpeeSlider(volumeInner,"player_volume");this._w_mute.add_listener(EventFlivpeeButton.PRESS,this,this.mute_toggle);this._w_pause.add_listener(EventFlivpeeButton.PRESS,this,this.pause_toggle);this._w_stop.add_listener(EventFlivpeeButton.PRESS,this,this.stop);this._w_unpause.add_listener(EventFlivpeeButton.PRESS,this,this.pause_toggle);this._w_volume.add_listener(EventFlivpeeSlider.UPDATE,this,this.update_volume);this._w_timeline.add_listener(EventFlivpeeSlider.UPDATE,this,this.update_seek);this.add_listener(EventFlivpee.VOLUME_UPDATE,this._w_volume,this._w_volume.set_position);this._w_timeline.disable()};Flivpee.prototype._build_widget_div=function(parent){if(parent===undefined){parent=this._tcControls}var div=document.createElement("div");parent.appendChild(div);return div};Flivpee.prototype.stopped=function(){if(this._debug){console.debug(this.toString()+" stopped")}this._events[EventFlivpee.STOPPED].broadcast();this._w_messages.show_event("stopped");this._w_timeline.disable();this._w_pause.disable();this._w_unpause.enable()};Flivpee.prototype.write=function(target_div_id){try{var flashBoxOuter=this._build_widget_div(this._widgets_div);flashBoxOuter.className="player_flash_box_outer";var flashBox=this._build_widget_div(flashBoxOuter);flashBox.className="player_flash_box_inner";this._build_all_widgets();document.getElementById(target_div_id).appendChild(this._widgets_div);this._swf_object.write(flashBox);this._embed=document.getElementById("flivpee_embed_"+this._index)}catch(e){if(this._debug===true){console.error(this.toString()+" failed to write embed, error:\n"+e)}}};FlivpeeEventBroadcaster.prototype.broadcast=function(params){this._p=params==null?[]:params;for(var i=0;i<this._l.length;i++){this._l[i].broadcast(this._p)}};function tc_PlayerProgress(node,style_name){try{this._enabled=true;this._current_pos=0;this._node=node;var bgOuter=document.createElement("div");bgOuter.className=style_name+"_background_outer";this._node.appendChild(bgOuter);var bg=document.createElement("div");bg.className=style_name+"_background";bgOuter.appendChild(bg);var barOuter=document.createElement("div");barOuter.className=style_name+"_indicator_outer";this._node.appendChild(barOuter);var barInner=document.createElement("div");barInner.className=style_name+"_indicator_inner";barOuter.appendChild(barInner);var bar=document.createElement("div");bar.className=style_name+"_indicator";barInner.appendChild(bar);this._bar=barOuter}catch(e){if(tc_Consts.debug===true){console.error(this.toString()+" construction failed, error : "+e)}}}tc_PlayerProgress.prototype=FlivpeeProgress.prototype;

/** End: player.js */

}
