/*!
* MediaElement.js
* HTML5 <video> and <audio> shim and player
* http://mediaelementjs.com/
*
* Creates a JavaScript object that mimics HTML5 MediaElement API
* for browsers that don't understand HTML5 or can't play the provided codec
* Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3
*
* Copyright 2010-2011, John Dyer (http://j.hn)
* Dual licensed under the MIT or GPL Version 2 licenses.
*
*/
// Namespace

var mejs = mejs || {};



// version number

mejs.version = '2.6.4';



// player number (for missing, same id attr)

mejs.meIndex = 0;



// media types accepted by plugins

mejs.plugins = {

	silverlight: [

		{version: [3,0], types: ['video/mp4','video/m4v','video/mov','video/wmv','audio/wma','audio/m4a','audio/mp3','audio/wav','audio/mpeg']}

	],

	flash: [

		{version: [9,0,124], types: ['video/mp4','video/m4v','video/mov','video/flv','video/x-flv','audio/flv','audio/x-flv','audio/mp3','audio/m4a','audio/mpeg']}

		//,{version: [12,0], types: ['video/webm']} // for future reference (hopefully!)

	],

	youtube: [

		{version: null, types: ['video/youtube']}

	],

	vimeo: [

		{version: null, types: ['video/vimeo']}

	]

};


/*

Utility methods

*/

mejs.Utility = {

	encodeUrl: function(url) {

		return encodeURIComponent(url); //.replace(/\?/gi,'%3F').replace(/=/gi,'%3D').replace(/&/gi,'%26');

	},

	escapeHTML: function(s) {

		return s.toString().split('&').join('&amp;').split('<').join('&lt;').split('"').join('&quot;');

	},

	absolutizeUrl: function(url) {

		var el = document.createElement('div');

		el.innerHTML = '<a href="' + this.escapeHTML(url) + '">x</a>';

		return el.firstChild.href;

	},

	getScriptPath: function(scriptNames) {

		var

			i = 0,

			j,

			path = '',

			name = '',

			script,

			scripts = document.getElementsByTagName('script');



		for (; i < scripts.length; i++) {

			script = scripts[i].src;

			for (j = 0; j < scriptNames.length; j++) {

				name = scriptNames[j];

				if (script.indexOf(name) > -1) {

					path = script.substring(0, script.indexOf(name));

					break;

				}

			}

			if (path !== '') {

				break;

			}

		}

		return path;

	},

	secondsToTimeCode: function(time, forceHours, showFrameCount, fps) {

		//add framecount

		if (typeof showFrameCount == 'undefined') {

		    showFrameCount=false;

		} else if(typeof fps == 'undefined') {

		    fps = 25;

		}

	

		var hours = Math.floor(time / 3600) % 24,

			minutes = Math.floor(time / 60) % 60,

			seconds = Math.floor(time % 60),

			frames = Math.floor(((time % 1)*fps).toFixed(3)),

			result = 

					( (forceHours || hours > 0) ? (hours < 10 ? '0' + hours : hours) + ':' : '')

						+ (minutes < 10 ? '0' + minutes : minutes) + ':'

						+ (seconds < 10 ? '0' + seconds : seconds)

						+ ((showFrameCount) ? ':' + (frames < 10 ? '0' + frames : frames) : '');

	

		return result;

	},

	

	timeCodeToSeconds: function(hh_mm_ss_ff, forceHours, showFrameCount, fps){

		if (typeof showFrameCount == 'undefined') {

		    showFrameCount=false;

		} else if(typeof fps == 'undefined') {

		    fps = 25;

		}

	

		var tc_array = hh_mm_ss_ff.split(":"),

			tc_hh = parseInt(tc_array[0], 10),

			tc_mm = parseInt(tc_array[1], 10),

			tc_ss = parseInt(tc_array[2], 10),

			tc_ff = 0,

			tc_in_seconds = 0;

		

		if (showFrameCount) {

		    tc_ff = parseInt(tc_array[3])/fps;

		}

		

		tc_in_seconds = ( tc_hh * 3600 ) + ( tc_mm * 60 ) + tc_ss + tc_ff;

		

		return tc_in_seconds;

	},

	

	/* borrowed from SWFObject: http://code.google.com/p/swfobject/source/browse/trunk/swfobject/src/swfobject.js#474 */

	removeSwf: function(id) {

		var obj = document.getElementById(id);

		if (obj && obj.nodeName == "OBJECT") {

			if (mejs.MediaFeatures.isIE) {

				obj.style.display = "none";

				(function(){

					if (obj.readyState == 4) {

						mejs.Utility.removeObjectInIE(id);

					} else {

						setTimeout(arguments.callee, 10);

					}

				})();

			} else {

				obj.parentNode.removeChild(obj);

			}

		}

	},

	removeObjectInIE: function(id) {

		var obj = document.getElementById(id);

		if (obj) {

			for (var i in obj) {

				if (typeof obj[i] == "function") {

					obj[i] = null;

				}

			}

			obj.parentNode.removeChild(obj);

		}		

	}

};



// Core detector, plugins are added below
mejs.PluginDetector = {

	// main public function to test a plug version number PluginDetector.hasPluginVersion('flash',[9,0,125]);
	hasPluginVersion: function(plugin, v) {
		var pv = this.plugins[plugin];
		v[1] = v[1] || 0;
		v[2] = v[2] || 0;
		return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
	},

	// cached values
	nav: window.navigator,
	ua: window.navigator.userAgent.toLowerCase(),

	// stored version numbers
	plugins: [],

	// runs detectPlugin() and stores the version number
	addPlugin: function(p, pluginName, mimeType, activeX, axDetect) {
		this.plugins[p] = this.detectPlugin(pluginName, mimeType, activeX, axDetect);
	},

	// get the version number from the mimetype (all but IE) or ActiveX (IE)
	detectPlugin: function(pluginName, mimeType, activeX, axDetect) {

		var version = [0,0,0],
			description,
			i,
			ax;

		// Firefox, Webkit, Opera
		if (typeof(this.nav.plugins) != 'undefined' && typeof this.nav.plugins[pluginName] == 'object') {
			description = this.nav.plugins[pluginName].description;
			if (description && !(typeof this.nav.mimeTypes != 'undefined' && this.nav.mimeTypes[mimeType] && !this.nav.mimeTypes[mimeType].enabledPlugin)) {
				version = description.replace(pluginName, '').replace(/^\s+/,'').replace(/\sr/gi,'.').split('.');
				for (i=0; i<version.length; i++) {
					version[i] = parseInt(version[i].match(/\d+/), 10);
				}
			}
		// Internet Explorer / ActiveX
		} else if (typeof(window.ActiveXObject) != 'undefined') {
			try {
				ax = new ActiveXObject(activeX);
				if (ax) {
					version = axDetect(ax);
				}
			}
			catch (e) { }
		}
		return version;
	}
};

// Add Flash detection
mejs.PluginDetector.addPlugin('flash','Shockwave Flash','application/x-shockwave-flash','ShockwaveFlash.ShockwaveFlash', function(ax) {
	// adapted from SWFObject
	var version = [],
		d = ax.GetVariable("$version");
	if (d) {
		d = d.split(" ")[1].split(",");
		version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
	}
	return version;
});

// Add Silverlight detection
mejs.PluginDetector.addPlugin('silverlight','Silverlight Plug-In','application/x-silverlight-2','AgControl.AgControl', function (ax) {
	// Silverlight cannot report its version number to IE
	// but it does have a isVersionSupported function, so we have to loop through it to get a version number.
	// adapted from http://www.silverlightversion.com/
	var v = [0,0,0,0],
		loopMatch = function(ax, v, i, n) {
			while(ax.isVersionSupported(v[0]+ "."+ v[1] + "." + v[2] + "." + v[3])){
				v[i]+=n;
			}
			v[i] -= n;
		};
	loopMatch(ax, v, 0, 1);
	loopMatch(ax, v, 1, 1);
	loopMatch(ax, v, 2, 10000); // the third place in the version number is usually 5 digits (4.0.xxxxx)
	loopMatch(ax, v, 2, 1000);
	loopMatch(ax, v, 2, 100);
	loopMatch(ax, v, 2, 10);
	loopMatch(ax, v, 2, 1);
	loopMatch(ax, v, 3, 1);

	return v;
});
// add adobe acrobat
/*
PluginDetector.addPlugin('acrobat','Adobe Acrobat','application/pdf','AcroPDF.PDF', function (ax) {
	var version = [],
		d = ax.GetVersions().split(',')[0].split('=')[1].split('.');

	if (d) {
		version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
	}
	return version;
});
*/
// necessary detection (fixes for <IE9)
mejs.MediaFeatures = {
	init: function() {
		var
			t = this,
			d = document,
			nav = mejs.PluginDetector.nav,
			ua = mejs.PluginDetector.ua.toLowerCase(),
			i,
			v,
			html5Elements = ['source','track','audio','video'];

		// detect browsers (only the ones that have some kind of quirk we need to work around)
		t.isiPad = (ua.match(/ipad/i) !== null);
		t.isiPhone = (ua.match(/iphone/i) !== null);
		t.isiOS = t.isiPhone || t.isiPad;
		t.isAndroid = (ua.match(/android/i) !== null);
		t.isBustedAndroid = (ua.match(/android 2\.[12]/) !== null);
		t.isIE = (nav.appName.toLowerCase().indexOf("microsoft") != -1);
		t.isChrome = (ua.match(/chrome/gi) !== null);
		t.isFirefox = (ua.match(/firefox/gi) !== null);
		t.isWebkit = (ua.match(/webkit/gi) !== null);
		t.isGecko = (ua.match(/gecko/gi) !== null) && !t.isWebkit;
		t.isOpera = (ua.match(/opera/gi) !== null);
		t.hasTouch = ('ontouchstart' in window);

		// create HTML5 media elements for IE before 9, get a <video> element for fullscreen detection
		for (i=0; i<html5Elements.length; i++) {
			v = document.createElement(html5Elements[i]);
		}
		
		t.supportsMediaTag = (typeof v.canPlayType !== 'undefined' || t.isBustedAndroid);

		// detect native JavaScript fullscreen (Safari/Firefox only, Chrome still fails)
		
		// iOS
		t.hasSemiNativeFullScreen = (typeof v.webkitEnterFullscreen !== 'undefined');
		
		// Webkit/firefox
		t.hasWebkitNativeFullScreen = (typeof v.webkitRequestFullScreen !== 'undefined');
		t.hasMozNativeFullScreen = (typeof v.mozRequestFullScreen !== 'undefined');
		
		t.hasTrueNativeFullScreen = (t.hasWebkitNativeFullScreen || t.hasMozNativeFullScreen);
		t.nativeFullScreenEnabled = t.hasTrueNativeFullScreen;
		if (t.hasMozNativeFullScreen) {
			t.nativeFullScreenEnabled = v.mozFullScreenEnabled;
		}
		
		
		if (this.isChrome) {
			t.hasSemiNativeFullScreen = false;
		}
		
		if (t.hasTrueNativeFullScreen) {
			t.fullScreenEventName = (t.hasWebkitNativeFullScreen) ? 'webkitfullscreenchange' : 'mozfullscreenchange';
			
			
			t.isFullScreen = function() {
				if (v.mozRequestFullScreen) {
					return d.mozFullScreen;
				} else if (v.webkitRequestFullScreen) {
					return d.webkitIsFullScreen;
				}
			}
					
			t.requestFullScreen = function(el) {
		
				if (t.hasWebkitNativeFullScreen) {
					el.webkitRequestFullScreen();
				} else if (t.hasMozNativeFullScreen) {
					el.mozRequestFullScreen();
				}
			}
			
			t.cancelFullScreen = function() {				
				if (t.hasWebkitNativeFullScreen) {
					document.webkitCancelFullScreen();
				} else if (t.hasMozNativeFullScreen) {
					document.mozCancelFullScreen();
				}
			}	
			
		}
		
		
		// OS X 10.5 can't do this even if it says it can :(
		if (t.hasSemiNativeFullScreen && ua.match(/mac os x 10_5/i)) {
			t.hasNativeFullScreen = false;
			t.hasSemiNativeFullScreen = false;
		}
		
	}
};
mejs.MediaFeatures.init();


/*
extension methods to <video> or <audio> object to bring it into parity with PluginMediaElement (see below)
*/
mejs.HtmlMediaElement = {
	pluginType: 'native',
	isFullScreen: false,

	setCurrentTime: function (time) {
		this.currentTime = time;
	},

	setMuted: function (muted) {
		this.muted = muted;
	},

	setVolume: function (volume) {
		this.volume = volume;
	},

	// for parity with the plugin versions
	stop: function () {
		this.pause();
	},

	// This can be a url string
	// or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
	setSrc: function (url) {
		
		// Fix for IE9 which can't set .src when there are <source> elements. Awesome, right?
		var 
			existingSources = this.getElementsByTagName('source');
		while (existingSources.length > 0){
			this.removeChild(existingSources[0]);
		}
	
		if (typeof url == 'string') {
			this.src = url;
		} else {
			var i, media;

			for (i=0; i<url.length; i++) {
				media = url[i];
				if (this.canPlayType(media.type)) {
					this.src = media.src;
				}
			}
		}
	},

	setVideoSize: function (width, height) {
		this.width = width;
		this.height = height;
	}
};

/*
Mimics the <video/audio> element by calling Flash's External Interface or Silverlights [ScriptableMember]
*/
mejs.PluginMediaElement = function (pluginid, pluginType, mediaUrl) {
	this.id = pluginid;
	this.pluginType = pluginType;
	this.src = mediaUrl;
	this.events = {};
};

// JavaScript values and ExternalInterface methods that match HTML5 video properties methods
// http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/FLVPlayback.html
// http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
mejs.PluginMediaElement.prototype = {

	// special
	pluginElement: null,
	pluginType: '',
	isFullScreen: false,

	// not implemented :(
	playbackRate: -1,
	defaultPlaybackRate: -1,
	seekable: [],
	played: [],

	// HTML5 read-only properties
	paused: true,
	ended: false,
	seeking: false,
	duration: 0,
	error: null,

	// HTML5 get/set properties, but only set (updated by event handlers)
	muted: false,
	volume: 1,
	currentTime: 0,

	// HTML5 methods
	play: function () {
		if (this.pluginApi != null) {
			if (this.pluginType == 'youtube') {
				this.pluginApi.playVideo();
			} else {
				this.pluginApi.playMedia();
			}
			this.paused = false;
		}
	},
	load: function () {
		if (this.pluginApi != null) {
			if (this.pluginType == 'youtube') {
			} else {
				this.pluginApi.loadMedia();
			}
			
			this.paused = false;
		}
	},
	pause: function () {
		if (this.pluginApi != null) {
			if (this.pluginType == 'youtube') {
				this.pluginApi.pauseVideo();
			} else {
				this.pluginApi.pauseMedia();
			}			
			
			
			this.paused = true;
		}
	},
	stop: function () {
		if (this.pluginApi != null) {
			if (this.pluginType == 'youtube') {
				this.pluginApi.stopVideo();
			} else {
				this.pluginApi.stopMedia();
			}	
			this.paused = true;
		}
	},
	canPlayType: function(type) {
		var i,
			j,
			pluginInfo,
			pluginVersions = mejs.plugins[this.pluginType];

		for (i=0; i<pluginVersions.length; i++) {
			pluginInfo = pluginVersions[i];

			// test if user has the correct plugin version
			if (mejs.PluginDetector.hasPluginVersion(this.pluginType, pluginInfo.version)) {

				// test for plugin playback types
				for (j=0; j<pluginInfo.types.length; j++) {
					// find plugin that can play the type
					if (type == pluginInfo.types[j]) {
						return true;
					}
				}
			}
		}

		return false;
	},
	
	positionFullscreenButton: function(x,y,visibleAndAbove) {
		if (this.pluginApi != null && this.pluginApi.positionFullscreenButton) {
			this.pluginApi.positionFullscreenButton(x,y,visibleAndAbove);
		}
	},
	
	hideFullscreenButton: function() {
		if (this.pluginApi != null && this.pluginApi.hideFullscreenButton) {
			this.pluginApi.hideFullscreenButton();
		}		
	},	
	

	// custom methods since not all JavaScript implementations support get/set

	// This can be a url string
	// or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
	setSrc: function (url) {
		if (typeof url == 'string') {
			this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(url));
			this.src = mejs.Utility.absolutizeUrl(url);
		} else {
			var i, media;

			for (i=0; i<url.length; i++) {
				media = url[i];
				if (this.canPlayType(media.type)) {
					this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(media.src));
					this.src = mejs.Utility.absolutizeUrl(url);
				}
			}
		}

	},
	setCurrentTime: function (time) {
		if (this.pluginApi != null) {
			if (this.pluginType == 'youtube') {
				this.pluginApi.seekTo(time);
			} else {
				this.pluginApi.setCurrentTime(time);
			}				
			
			
			
			this.currentTime = time;
		}
	},
	setVolume: function (volume) {
		if (this.pluginApi != null) {
			// same on YouTube and MEjs
			if (this.pluginType == 'youtube') {
				this.pluginApi.setVolume(volume * 100);
			} else {
				this.pluginApi.setVolume(volume);
			}
			this.volume = volume;
		}
	},
	setMuted: function (muted) {
		if (this.pluginApi != null) {
			if (this.pluginType == 'youtube') {
				if (muted) {
					this.pluginApi.mute();
				} else {
					this.pluginApi.unMute();
				}
				this.muted = muted;
				this.dispatchEvent('volumechange');
			} else {
				this.pluginApi.setMuted(muted);
			}
			this.muted = muted;
		}
	},

	// additional non-HTML5 methods
	setVideoSize: function (width, height) {
		
		//if (this.pluginType == 'flash' || this.pluginType == 'silverlight') {
			if ( this.pluginElement.style) {
				this.pluginElement.style.width = width + 'px';
				this.pluginElement.style.height = height + 'px';
			}
			if (this.pluginApi != null && this.pluginApi.setVideoSize) {
				this.pluginApi.setVideoSize(width, height);
			}
		//}
	},

	setFullscreen: function (fullscreen) {
		if (this.pluginApi != null && this.pluginApi.setFullscreen) {
			this.pluginApi.setFullscreen(fullscreen);
		}
	},
	
	enterFullScreen: function() {
		if (this.pluginApi != null && this.pluginApi.setFullscreen) {
			this.setFullscreen(true);
		}		
		
	},
	
	exitFullScreen: function() {
		if (this.pluginApi != null && this.pluginApi.setFullscreen) {
			this.setFullscreen(false);
		}
	},	

	// start: fake events
	addEventListener: function (eventName, callback, bubble) {
		this.events[eventName] = this.events[eventName] || [];
		this.events[eventName].push(callback);
	},
	removeEventListener: function (eventName, callback) {
		if (!eventName) { this.events = {}; return true; }
		var callbacks = this.events[eventName];
		if (!callbacks) return true;
		if (!callback) { this.events[eventName] = []; return true; }
		for (i = 0; i < callbacks.length; i++) {
			if (callbacks[i] === callback) {
				this.events[eventName].splice(i, 1);
				return true;
			}
		}
		return false;
	},	
	dispatchEvent: function (eventName) {
		var i,
			args,
			callbacks = this.events[eventName];

		if (callbacks) {
			args = Array.prototype.slice.call(arguments, 1);
			for (i = 0; i < callbacks.length; i++) {
				callbacks[i].apply(null, args);
			}
		}
	},
	// end: fake events
	
	remove: function() {
		mejs.Utility.removeSwf(this.pluginElement.id);
	}
};

// Handles calls from Flash/Silverlight and reports them as native <video/audio> events and properties
mejs.MediaPluginBridge = {

	pluginMediaElements:{},
	htmlMediaElements:{},

	registerPluginElement: function (id, pluginMediaElement, htmlMediaElement) {
		this.pluginMediaElements[id] = pluginMediaElement;
		this.htmlMediaElements[id] = htmlMediaElement;
	},

	// when Flash/Silverlight is ready, it calls out to this method
	initPlugin: function (id) {

		var pluginMediaElement = this.pluginMediaElements[id],
			htmlMediaElement = this.htmlMediaElements[id];

		if (pluginMediaElement) {
			// find the javascript bridge
			switch (pluginMediaElement.pluginType) {
				case "flash":
					pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(id);
					break;
				case "silverlight":
					pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
					pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
					break;
			}
	
			if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
				pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
			}
		}
	},

	// receives events from Flash/Silverlight and sends them out as HTML5 media events
	// http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
	fireEvent: function (id, eventName, values) {

		var
			e,
			i,
			bufferedTime,
			pluginMediaElement = this.pluginMediaElements[id];

		pluginMediaElement.ended = false;
		pluginMediaElement.paused = true;

		// fake event object to mimic real HTML media event.
		e = {
			type: eventName,
			target: pluginMediaElement
		};

		// attach all values to element and event object
		for (i in values) {
			pluginMediaElement[i] = values[i];
			e[i] = values[i];
		}

		// fake the newer W3C buffered TimeRange (loaded and total have been removed)
		bufferedTime = values.bufferedTime || 0;

		e.target.buffered = e.buffered = {
			start: function(index) {
				return 0;
			},
			end: function (index) {
				return bufferedTime;
			},
			length: 1
		};

		pluginMediaElement.dispatchEvent(e.type, e);
	}
};

/*
Default options
*/
mejs.MediaElementDefaults = {
	// allows testing on HTML5, flash, silverlight
	// auto: attempts to detect what the browser can do
	// native: forces HTML5 playback
	// shim: disallows HTML5, will attempt either Flash or Silverlight
	// none: forces fallback view
	mode: 'auto',
	// remove or reorder to change plugin priority and availability
	plugins: ['flash','silverlight','youtube','vimeo'],
	// shows debug errors on screen
	enablePluginDebug: false,
	// overrides the type specified, useful for dynamic instantiation
	type: '',
	// path to Flash and Silverlight plugins
	pluginPath: mejs.Utility.getScriptPath(['mediaelement.js','mediaelement.min.js','mediaelement-and-player.js','mediaelement-and-player.min.js']),
	// name of flash file
	flashName: 'flashmediaelement.swf',
	// turns on the smoothing filter in Flash
	enablePluginSmoothing: false,
	// name of silverlight file
	silverlightName: 'silverlightmediaelement.xap',
	// default if the <video width> is not specified
	defaultVideoWidth: 480,
	// default if the <video height> is not specified
	defaultVideoHeight: 270,
	// overrides <video width>
	pluginWidth: -1,
	// overrides <video height>
	pluginHeight: -1,
	// additional plugin variables in 'key=value' form
	pluginVars: [],	
	// rate in milliseconds for Flash and Silverlight to fire the timeupdate event
	// larger number is less accurate, but less strain on plugin->JavaScript bridge
	timerRate: 250,
	// initial volume for player
	startVolume: 0.8,
	success: function () { },
	error: function () { }
};

/*
Determines if a browser supports the <video> or <audio> element
and returns either the native element or a Flash/Silverlight version that
mimics HTML5 MediaElement
*/
mejs.MediaElement = function (el, o) {
	return mejs.HtmlMediaElementShim.create(el,o);
};

mejs.HtmlMediaElementShim = {

	create: function(el, o) {
		var
			options = mejs.MediaElementDefaults,
			htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el,
			tagName = htmlMediaElement.tagName.toLowerCase(),
			isMediaTag = (tagName === 'audio' || tagName === 'video'),
			src = (isMediaTag) ? htmlMediaElement.getAttribute('src') : htmlMediaElement.getAttribute('href'),
			poster = htmlMediaElement.getAttribute('poster'),
			autoplay =  htmlMediaElement.getAttribute('autoplay'),
			preload =  htmlMediaElement.getAttribute('preload'),
			controls =  htmlMediaElement.getAttribute('controls'),
			playback,
			prop;

		// extend options
		for (prop in o) {
			options[prop] = o[prop];
		}

		// clean up attributes
		src = 		(typeof src == 'undefined' 	|| src === null || src == '') ? null : src;		
		poster =	(typeof poster == 'undefined' 	|| poster === null) ? '' : poster;
		preload = 	(typeof preload == 'undefined' 	|| preload === null || preload === 'false') ? 'none' : preload;
		autoplay = 	!(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false');
		controls = 	!(typeof controls == 'undefined' || controls === null || controls === 'false');

		// test for HTML5 and plugin capabilities
		playback = this.determinePlayback(htmlMediaElement, options, mejs.MediaFeatures.supportsMediaTag, isMediaTag, src);
		playback.url = (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '';

		if (playback.method == 'native') {
			// second fix for android
			if (mejs.MediaFeatures.isBustedAndroid) {
				htmlMediaElement.src = playback.url;
				htmlMediaElement.addEventListener('click', function() {
					htmlMediaElement.play();
				}, false);
			}
		
			// add methods to native HTMLMediaElement
			return this.updateNative(playback, options, autoplay, preload);
		} else if (playback.method !== '') {
			// create plugin to mimic HTMLMediaElement
			
			return this.createPlugin( playback,  options, poster, autoplay, preload, controls);
		} else {
			// boo, no HTML5, no Flash, no Silverlight.
			this.createErrorMessage( playback, options, poster );
			
			return this;
		}
	},
	
	determinePlayback: function(htmlMediaElement, options, supportsMediaTag, isMediaTag, src) {
		var
			mediaFiles = [],
			i,
			j,
			k,
			l,
			n,
			type,
			result = { method: '', url: '', htmlMediaElement: htmlMediaElement, isVideo: (htmlMediaElement.tagName.toLowerCase() != 'audio')},
			pluginName,
			pluginVersions,
			pluginInfo,
			dummy;
			
		// STEP 1: Get URL and type from <video src> or <source src>

		// supplied type overrides <video type> and <source type>
		if (typeof options.type != 'undefined' && options.type !== '') {
			
			// accept either string or array of types
			if (typeof options.type == 'string') {
				mediaFiles.push({type:options.type, url:src});
			} else {
				
				for (i=0; i<options.type.length; i++) {
					mediaFiles.push({type:options.type[i], url:src});
				}
			}

		// test for src attribute first
		} else if (src !== null) {
			type = this.formatType(src, htmlMediaElement.getAttribute('type'));
			mediaFiles.push({type:type, url:src});

		// then test for <source> elements
		} else {
			// test <source> types to see if they are usable
			for (i = 0; i < htmlMediaElement.childNodes.length; i++) {
				n = htmlMediaElement.childNodes[i];
				if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') {
					src = n.getAttribute('src');
					type = this.formatType(src, n.getAttribute('type'));
					mediaFiles.push({type:type, url:src});
				}
			}
		}
		
		// in the case of dynamicly created players
		// check for audio types
		if (!isMediaTag && mediaFiles.length > 0 && mediaFiles[0].url !== null && this.getTypeFromFile(mediaFiles[0].url).indexOf('audio') > -1) {
			result.isVideo = false;
		}
		

		// STEP 2: Test for playback method
		
		// special case for Android which sadly doesn't implement the canPlayType function (always returns '')
		if (mejs.MediaFeatures.isBustedAndroid) {
			htmlMediaElement.canPlayType = function(type) {
				return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : '';
			};
		}		
		

		// test for native playback first
		if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'native')) {
						
			if (!isMediaTag) {

				// create a real HTML5 Media Element 
				dummy = document.createElement( result.isVideo ? 'video' : 'audio');			
				htmlMediaElement.parentNode.insertBefore(dummy, htmlMediaElement);
				htmlMediaElement.style.display = 'none';
				
				// use this one from now on
				result.htmlMediaElement = htmlMediaElement = dummy;
			}
				
			for (i=0; i<mediaFiles.length; i++) {
				// normal check
				if (htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== '' 
					// special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg')
					|| htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '') {
					result.method = 'native';
					result.url = mediaFiles[i].url;
					break;
				}
			}			
			
			if (result.method === 'native') {
				if (result.url !== null) {
					htmlMediaElement.src = result.url;
				}
			
				return result;
			}
		}

		// if native playback didn't work, then test plugins
		if (options.mode === 'auto' || options.mode === 'shim') {
			for (i=0; i<mediaFiles.length; i++) {
				type = mediaFiles[i].type;

				// test all plugins in order of preference [silverlight, flash]
				for (j=0; j<options.plugins.length; j++) {

					pluginName = options.plugins[j];
			
					// test version of plugin (for future features)
					pluginVersions = mejs.plugins[pluginName];				
					
					for (k=0; k<pluginVersions.length; k++) {
						pluginInfo = pluginVersions[k];
					
						// test if user has the correct plugin version
						
						// for youtube/vimeo
						if (pluginInfo.version == null || 
							
							mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) {

							// test for plugin playback types
							for (l=0; l<pluginInfo.types.length; l++) {
								// find plugin that can play the type
								if (type == pluginInfo.types[l]) {
									result.method = pluginName;
									result.url = mediaFiles[i].url;
									return result;
								}
							}
						}
					}
				}
			}
		}
		
		// what if there's nothing to play? just grab the first available
		if (result.method === '' && mediaFiles.length > 0) {
			result.url = mediaFiles[0].url;
		}

		return result;
	},

	formatType: function(url, type) {
		var ext;

		// if no type is supplied, fake it with the extension
		if (url && !type) {		
			return this.getTypeFromFile(url);
		} else {
			// only return the mime part of the type in case the attribute contains the codec
			// see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
			// `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4`
			
			if (type && ~type.indexOf(';')) {
				return type.substr(0, type.indexOf(';')); 
			} else {
				return type;
			}
		}
	},
	
	getTypeFromFile: function(url) {
		var ext = url.substring(url.lastIndexOf('.') + 1);
		return (/(mp4|m4v|ogg|ogv|webm|flv|wmv|mpeg|mov)/gi.test(ext) ? 'video' : 'audio') + '/' + ext;
	},

	createErrorMessage: function(playback, options, poster) {
		var 
			htmlMediaElement = playback.htmlMediaElement,
			errorContainer = document.createElement('div');
			
		errorContainer.className = 'me-cannotplay';

		try {
			errorContainer.style.width = htmlMediaElement.width + 'px';
			errorContainer.style.height = htmlMediaElement.height + 'px';
		} catch (e) {}

		errorContainer.innerHTML = (poster !== '') ?
			'<a href="' + playback.url + '"><img src="' + poster + '" /></a>' :
			'<a href="' + playback.url + '"><span>Download File</span></a>';

		htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement);
		htmlMediaElement.style.display = 'none';

		options.error(htmlMediaElement);
	},

	createPlugin:function(playback, options, poster, autoplay, preload, controls) {
		var 
			htmlMediaElement = playback.htmlMediaElement,
			width = 1,
			height = 1,
			pluginid = 'me_' + playback.method + '_' + (mejs.meIndex++),
			pluginMediaElement = new mejs.PluginMediaElement(pluginid, playback.method, playback.url),
			container = document.createElement('div'),
			specialIEContainer,
			node,
			initVars;

		// check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
		node = htmlMediaElement.parentNode;
		while (node !== null && node.tagName.toLowerCase() != 'body') {
			if (node.parentNode.tagName.toLowerCase() == 'p') {
				node.parentNode.parentNode.insertBefore(node, node.parentNode);
				break;
			}
			node = node.parentNode;
		}

		if (playback.isVideo) {
			width = (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
			height = (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight;
		
			// in case of '%' make sure it's encoded
			width = mejs.Utility.encodeUrl(width);
			height = mejs.Utility.encodeUrl(height);
		
		} else {
			if (options.enablePluginDebug) {
				width = 320;
				height = 240;
			}
		}

		// register plugin
		pluginMediaElement.success = options.success;
		mejs.MediaPluginBridge.registerPluginElement(pluginid, pluginMediaElement, htmlMediaElement);

		// add container (must be added to DOM before inserting HTML for IE)
		container.className = 'me-plugin';
		container.id = pluginid + '_container';
		
		if (playback.isVideo) {
				htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement);
		} else {
				document.body.insertBefore(container, document.body.childNodes[0]);
		}

		// flash/silverlight vars
		initVars = [
			'id=' + pluginid,
			'isvideo=' + ((playback.isVideo) ? "true" : "false"),
			'autoplay=' + ((autoplay) ? "true" : "false"),
			'preload=' + preload,
			'width=' + width,
			'startvolume=' + options.startVolume,
			'timerrate=' + options.timerRate,
			'height=' + height];

		if (playback.url !== null) {
			if (playback.method == 'flash') {
				initVars.push('file=' + mejs.Utility.encodeUrl(playback.url));
			} else {
				initVars.push('file=' + playback.url);
			}
		}
		if (options.enablePluginDebug) {
			initVars.push('debug=true');
		}
		if (options.enablePluginSmoothing) {
			initVars.push('smoothing=true');
		}
		if (controls) {
			initVars.push('controls=true'); // shows controls in the plugin if desired
		}
		if (options.pluginVars) {
			initVars = initVars.concat(options.pluginVars);
		}		

		switch (playback.method) {
			case 'silverlight':
				container.innerHTML =
'<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '">' +
'<param name="initParams" value="' + initVars.join(',') + '" />' +
'<param name="windowless" value="true" />' +
'<param name="background" value="black" />' +
'<param name="minRuntimeVersion" value="3.0.0.0" />' +
'<param name="autoUpgrade" value="true" />' +
'<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' +
'</object>';
					break;

			case 'flash':

				if (mejs.MediaFeatures.isIE) {
					specialIEContainer = document.createElement('div');
					container.appendChild(specialIEContainer);
					specialIEContainer.outerHTML =
'<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
'id="' + pluginid + '" width="' + width + '" height="' + height + '">' +
'<param name="movie" value="' + options.pluginPath + options.flashName + '?x=' + (new Date()) + '" />' +
'<param name="flashvars" value="' + initVars.join('&amp;') + '" />' +
'<param name="quality" value="high" />' +
'<param name="bgcolor" value="#000000" />' +
'<param name="wmode" value="transparent" />' +
'<param name="allowScriptAccess" value="always" />' +
'<param name="allowFullScreen" value="true" />' +
'</object>';

				} else {

					container.innerHTML =
'<embed id="' + pluginid + '" name="' + pluginid + '" ' +
'play="true" ' +
'loop="false" ' +
'quality="high" ' +
'bgcolor="#000000" ' +
'wmode="transparent" ' +
'allowScriptAccess="always" ' +
'allowFullScreen="true" ' +
'type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" ' +
'src="' + options.pluginPath + options.flashName + '" ' +
'flashvars="' + initVars.join('&') + '" ' +
'width="' + width + '" ' +
'height="' + height + '"></embed>';
				}
				break;
			
			case 'youtube':
			
				
				var
					videoId = playback.url.substr(playback.url.lastIndexOf('=')+1);
					youtubeSettings = {
						container: container,
						containerId: container.id,
						pluginMediaElement: pluginMediaElement,
						pluginId: pluginid,
						videoId: videoId,
						height: height,
						width: width	
					};				
				
				if (mejs.PluginDetector.hasPluginVersion('flash', [10,0,0]) ) {
					mejs.YouTubeApi.createFlash(youtubeSettings);
				} else {
					mejs.YouTubeApi.enqueueIframe(youtubeSettings);		
				}
				
				break;
			
			// DEMO Code. Does NOT work.
			case 'vimeo':
				console.log('vimeoid');
				
				pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/')+1);
				
				container.innerHTML =
					'<object width="' + width + '" height="' + height + '">' +
						'<param name="allowfullscreen" value="true" />' +
						'<param name="allowscriptaccess" value="always" />' +
						'<param name="flashvars" value="api=1" />' + 
						'<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=' + pluginMediaElement.vimeoid  + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" />' +
						'<embed src="//vimeo.com/moogaloop.swf?api=1&amp;clip_id=' + pluginMediaElement.vimeoid + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="' + width + '" height="' + height + '"></embed>' +
					'</object>';
					
				break;			
		}
		// hide original element
		htmlMediaElement.style.display = 'none';

		// FYI: options.success will be fired by the MediaPluginBridge
		
		return pluginMediaElement;
	},

	updateNative: function(playback, options, autoplay, preload) {
		
		var htmlMediaElement = playback.htmlMediaElement,
			m;
		
		
		// add methods to video object to bring it into parity with Flash Object
		for (m in mejs.HtmlMediaElement) {
			htmlMediaElement[m] = mejs.HtmlMediaElement[m];
		}

		/*
		Chrome now supports preload="none"
		if (mejs.MediaFeatures.isChrome) {
		
			// special case to enforce preload attribute (Chrome doesn't respect this)
			if (preload === 'none' && !autoplay) {
			
				// forces the browser to stop loading (note: fails in IE9)
				htmlMediaElement.src = '';
				htmlMediaElement.load();
				htmlMediaElement.canceledPreload = true;

				htmlMediaElement.addEventListener('play',function() {
					if (htmlMediaElement.canceledPreload) {
						htmlMediaElement.src = playback.url;
						htmlMediaElement.load();
						htmlMediaElement.play();
						htmlMediaElement.canceledPreload = false;
					}
				}, false);
			// for some reason Chrome forgets how to autoplay sometimes.
			} else if (autoplay) {
				htmlMediaElement.load();
				htmlMediaElement.play();
			}
		}
		*/

		// fire success code
		options.success(htmlMediaElement, htmlMediaElement);
		
		return htmlMediaElement;
	}
};

/*
 - test on IE (object vs. embed)
 - determine when to use iframe (Firefox, Safari, Mobile) vs. Flash (Chrome, IE)
 - fullscreen?
*/

// YouTube Flash and Iframe API
mejs.YouTubeApi = {
	isIframeStarted: false,
	isIframeLoaded: false,
	loadIframeApi: function() {
		if (!this.isIframeStarted) {
			var tag = document.createElement('script');
			tag.src = "http://www.youtube.com/player_api";
			var firstScriptTag = document.getElementsByTagName('script')[0];
			firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
			this.isIframeStarted = true;
		}
	},
	iframeQueue: [],
	enqueueIframe: function(yt) {
		
		if (this.isLoaded) {
			this.createIframe(yt);
		} else {
			this.loadIframeApi();
			this.iframeQueue.push(yt);
		}
	},
	createIframe: function(settings) {
		
		var
		pluginMediaElement = settings.pluginMediaElement,	
		player = new YT.Player(settings.containerId, {
			height: settings.height,
			width: settings.width,
			videoId: settings.videoId,
			playerVars: {controls:0},
			events: {
				'onReady': function() {
					
					// hook up iframe object to MEjs
					settings.pluginMediaElement.pluginApi = player;
					
					// init mejs
					mejs.MediaPluginBridge.initPlugin(settings.pluginId);
					
					// create timer
					setInterval(function() {
						mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
					}, 250);					
				},
				'onStateChange': function(e) {
					
					mejs.YouTubeApi.handleStateChange(e.data, player, pluginMediaElement);
					
				}
			}
		});
	},
	
	createEvent: function (player, pluginMediaElement, eventName) {
		var obj = {
			type: eventName,
			target: pluginMediaElement
		};

		if (player && player.getDuration) {
			
			// time 
			pluginMediaElement.currentTime = obj.currentTime = player.getCurrentTime();
			pluginMediaElement.duration = obj.duration = player.getDuration();
			
			// state
			obj.paused = pluginMediaElement.paused;
			obj.ended = pluginMediaElement.ended;			
			
			// sound
			obj.muted = player.isMuted();
			obj.volume = player.getVolume() / 100;
			
			// progress
			obj.bytesTotal = player.getVideoBytesTotal();
			obj.bufferedBytes = player.getVideoBytesLoaded();
			
			// fake the W3C buffered TimeRange
			var bufferedTime = obj.bufferedBytes / obj.bytesTotal * obj.duration;
			
			obj.target.buffered = obj.buffered = {
				start: function(index) {
					return 0;
				},
				end: function (index) {
					return bufferedTime;
				},
				length: 1
			};
			
		}
		
		// send event up the chain
		pluginMediaElement.dispatchEvent(obj.type, obj);
	},	
	
	iFrameReady: function() {
		
		this.isIframeLoaded = true;
		
		while (this.iframeQueue.length > 0) {
			var settings = this.iframeQueue.pop();
			this.createIframe(settings);
		}	
	},
	
	// FLASH!
	flashPlayers: {},
	createFlash: function(settings) {
		
		this.flashPlayers[settings.pluginId] = settings;
		
		/*
		settings.container.innerHTML =
			'<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="//www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId  + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0" ' +
				'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' +
				'<param name="allowScriptAccess" value="always">' +
				'<param name="wmode" value="transparent">' +
			'</object>';
		*/

		var specialIEContainer,
			youtubeUrl = 'http://www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId  + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0';
			
		if (mejs.MediaFeatures.isIE) {
			
			specialIEContainer = document.createElement('div');
			settings.container.appendChild(specialIEContainer);
			specialIEContainer.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '">' +
	'<param name="movie" value="' + youtubeUrl + '" />' +
	'<param name="wmode" value="transparent" />' +
	'<param name="allowScriptAccess" value="always" />' +
	'<param name="allowFullScreen" value="true" />' +
'</object>';
		} else {
		settings.container.innerHTML =
			'<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + youtubeUrl + '" ' +
				'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' +
				'<param name="allowScriptAccess" value="always">' +
				'<param name="wmode" value="transparent">' +
			'</object>';
		}		
		
	},
	
	flashReady: function(id) {
		var
			settings = this.flashPlayers[id],
			player = document.getElementById(id),
			pluginMediaElement = settings.pluginMediaElement;
		
		// hook up and return to MediaELementPlayer.success	
		pluginMediaElement.pluginApi = 
		pluginMediaElement.pluginElement = player;
		mejs.MediaPluginBridge.initPlugin(id);
		
		// load the youtube video
		player.cueVideoById(settings.videoId);
		
		var callbackName = settings.containerId + '_callback'
		
		window[callbackName] = function(e) {
			mejs.YouTubeApi.handleStateChange(e, player, pluginMediaElement);
		}
		
		player.addEventListener('onStateChange', callbackName);
		
		setInterval(function() {
			mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
		}, 250);
	},
	
	handleStateChange: function(youTubeState, player, pluginMediaElement) {
		switch (youTubeState) {
			case -1: // not started
				pluginMediaElement.paused = true;
				pluginMediaElement.ended = true;
				mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'loadedmetadata');
				//createYouTubeEvent(player, pluginMediaElement, 'loadeddata');
				break;
			case 0:
				pluginMediaElement.paused = false;
				pluginMediaElement.ended = true;
				mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'ended');
				break;
			case 1:
				pluginMediaElement.paused = false;
				pluginMediaElement.ended = false;				
				mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'play');
				mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'playing');
				break;
			case 2:
				pluginMediaElement.paused = true;
				pluginMediaElement.ended = false;				
				mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'pause');
				break;
			case 3: // buffering
				mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'progress');
				break;
			case 5:
				// cued?
				break;						
			
		}			
		
	}
}
// IFRAME
function onYouTubePlayerAPIReady() {
	mejs.YouTubeApi.iFrameReady();
}
// FLASH
function onYouTubePlayerReady(id) {
	mejs.YouTubeApi.flashReady(id);
}

window.mejs = mejs;
window.MediaElement = mejs.MediaElement;

/*!
 * MediaElementPlayer
 * http://mediaelementjs.com/
 *
 * Creates a controller bar for HTML5 <video> add <audio> tags
 * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
 *
 * Copyright 2010-2011, John Dyer (http://j.hn/)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 *
 */
if (typeof jQuery != 'undefined') {
	mejs.$ = jQuery;
} else if (typeof ender != 'undefined') {
	mejs.$ = ender;
}
(function ($) {



	// default player values

	mejs.MepDefaults = {

		// url to poster (to fix iOS 3.x)

		poster: '',

		// default if the <video width> is not specified

		defaultVideoWidth: 480,

		// default if the <video height> is not specified

		defaultVideoHeight: 270,

		// if set, overrides <video width>

		videoWidth: -1,

		// if set, overrides <video height>

		videoHeight: -1,

		// default if the user doesn't specify

		defaultAudioWidth: 400,

		// default if the user doesn't specify

		defaultAudioHeight: 30,

		// width of audio player

		audioWidth: -1,

		// height of audio player

		audioHeight: -1,		

		// initial volume when the player starts (overrided by user cookie)

		startVolume: 0.8,

		// useful for <audio> player loops

		loop: false,

		// resize to media dimensions

		enableAutosize: true,

		// forces the hour marker (##:00:00)

		alwaysShowHours: false,



		// show framecount in timecode (##:00:00:00)

		showTimecodeFrameCount: false,

		// used when showTimecodeFrameCount is set to true

		framesPerSecond: 25,

		

		// automatically calculate the width of the progress bar based on the sizes of other elements

		autosizeProgress : true,

		// Hide controls when playing and mouse is not over the video

		alwaysShowControls: false,

		// force iPad's native controls

		iPadUseNativeControls: false,

		// force iPad's native controls

		iPhoneUseNativeControls: false,	

		// force iPad's native controls

		AndroidUseNativeControls: false,			

		// features to show

		features: ['playpause','current','progress','duration','tracks','volume','fullscreen'],

		// only for dynamic

		isVideo: true,

		

		// turns keyboard support on and off for this instance

		enableKeyboard: true,

		

		// whenthis player starts, it will pause other players

		pauseOtherPlayers: true,

		

		// array of keyboard actions such as play pause

		keyActions: [

				{

						keys: [

								32, // SPACE

								179 // GOOGLE play/pause button

							  ],

						action: function(player, media) {

								if (media.paused || media.ended) {

										media.play();	

								} else {

										media.pause();

								}										

						}

				},

				{

						keys: [38], // UP

						action: function(player, media) {

								var newVolume = Math.min(media.volume + 0.1, 1);

								media.setVolume(newVolume);

						}

				},

				{

						keys: [40], // DOWN

						action: function(player, media) {

								var newVolume = Math.max(media.volume - 0.1, 0);

								media.setVolume(newVolume);

						}

				},

				{

						keys: [

								37, // LEFT

								227 // Google TV rewind

						],

						action: function(player, media) {

								if (!isNaN(media.duration) && media.duration > 0) {

										if (player.isVideo) {

												player.showControls();

												player.startControlsTimer();

										}

										

										// 5%

										var newTime = Math.min(media.currentTime - (media.duration * 0.05), media.duration);

										media.setCurrentTime(newTime);

								}

						}

				},

				{

						keys: [

								39, // RIGHT

								228 // Google TV forward

						], 

						action: function(player, media) {

								if (!isNaN(media.duration) && media.duration > 0) {

										if (player.isVideo) {

												player.showControls();

												player.startControlsTimer();

										}

										

										// 5%

										var newTime = Math.max(media.currentTime + (media.duration * 0.05), 0);

										media.setCurrentTime(newTime);

								}

						}

				},

				{

						keys: [70], // f

						action: function(player, media) {

								if (typeof player.enterFullScreen != 'undefined') {

										if (player.isFullScreen) {

												player.exitFullScreen();

										} else {

												player.enterFullScreen();

										}

								}

						}

				}					

		]		

	};



	mejs.mepIndex = 0;

	

	mejs.players = [];



	// wraps a MediaElement object in player controls

	mejs.MediaElementPlayer = function(node, o) {

		// enforce object, even without "new" (via John Resig)

		if ( !(this instanceof mejs.MediaElementPlayer) ) {

			return new mejs.MediaElementPlayer(node, o);

		} 



		var t = this;

		

		// these will be reset after the MediaElement.success fires

		t.$media = t.$node = $(node);

		t.node = t.media = t.$media[0];		

		

		// check for existing player

		if (typeof t.node.player != 'undefined') {

			return t.node.player;

		} else {

			// attach player to DOM node for reference

			t.node.player = t;

		}

				

				

		// try to get options from data-mejsoptions

		if (typeof o == 'undefined') {

			o = t.$node.data('mejsoptions');	

		}

			

		// extend default options

		t.options = $.extend({},mejs.MepDefaults,o);

		

		// add to player array (for focus events)

		mejs.players.push(t);

		

		// start up

		t.init();



		return t;

	};



	// actual player

	mejs.MediaElementPlayer.prototype = {

		

		hasFocus: false,

		

		controlsAreVisible: true,

		

		init: function() {



			var

				t = this,

				mf = mejs.MediaFeatures,

				// options for MediaElement (shim)

				meOptions = $.extend(true, {}, t.options, {

					success: function(media, domNode) { t.meReady(media, domNode); },

					error: function(e) { t.handleError(e);}

				}),

				tagName = t.media.tagName.toLowerCase();

		

			t.isDynamic = (tagName !== 'audio' && tagName !== 'video');

			

			if (t.isDynamic) {	

				// get video from src or href?				

				t.isVideo = t.options.isVideo;						

			} else {

				t.isVideo = (tagName !== 'audio' && t.options.isVideo);

			}

		

			// use native controls in iPad, iPhone, and Android	

			if ((mf.isiPad && t.options.iPadUseNativeControls) || (mf.isiPhone && t.options.iPhoneUseNativeControls)) {

				

				// add controls and stop

				t.$media.attr('controls', 'controls');



				// attempt to fix iOS 3 bug

				t.$media.removeAttr('poster');



				// override Apple's autoplay override for iPads

				if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {

					t.media.load();

					t.media.play();

				}

					

			} else if (mf.isAndroid && t.AndroidUseNativeControls) {

				

				// leave default player



			} else {



				// DESKTOP: use MediaElementPlayer controls

				

				// remove native controls 			

				t.$media.removeAttr('controls');					

				

				// unique ID

				t.id = 'mep_' + mejs.mepIndex++;



				// build container

				t.container =

					$('<div id="' + t.id + '" class="mejs-container">'+

						'<div class="mejs-inner">'+

							'<div class="mejs-mediaelement"></div>'+

							'<div class="mejs-layers"></div>'+

							'<div class="mejs-controls"></div>'+

							'<div class="mejs-clear"></div>'+

						'</div>' +

					'</div>')

					.addClass(t.$media[0].className)

					.insertBefore(t.$media);	

					

				// add classes for user and content

				t.container.addClass(

					(mf.isAndroid ? 'mejs-android ' : '') +

					(mf.isiOS ? 'mejs-ios ' : '') +

					(mf.isiPad ? 'mejs-ipad ' : '') +

					(mf.isiPhone ? 'mejs-iphone ' : '') +

					(t.isVideo ? 'mejs-video ' : 'mejs-audio ')

				);	

					



				// move the <video/video> tag into the right spot

				if (mf.isiOS) {

				

					// sadly, you can't move nodes in iOS, so we have to destroy and recreate it!

					var $newMedia = t.$media.clone();

					

					t.container.find('.mejs-mediaelement').append($newMedia);

					

					t.$media.remove();

					t.$node = t.$media = $newMedia;

					t.node = t.media = $newMedia[0]

					

				} else {

					

					// normal way of moving it into place (doesn't work on iOS)

					t.container.find('.mejs-mediaelement').append(t.$media);

				}

				

				// find parts

				t.controls = t.container.find('.mejs-controls');

				t.layers = t.container.find('.mejs-layers');



				// determine the size

				

				/* size priority:

					(1) videoWidth (forced), 

					(2) style="width;height;"

					(3) width attribute,

					(4) defaultVideoWidth (for unspecified cases)

				*/

				

				var capsTagName = tagName.substring(0,1).toUpperCase() + tagName.substring(1);

				

				if (t.options[tagName + 'Width'] > 0 || t.options[tagName + 'Width'].toString().indexOf('%') > -1) {

					t.width = t.options[tagName + 'Width'];

				} else if (t.media.style.width !== '' && t.media.style.width !== null) {

					t.width = t.media.style.width;						

				} else if (t.media.getAttribute('width') !== null) {

					t.width = t.$media.attr('width');

				} else {

					t.width = t.options['default' + capsTagName + 'Width'];

				}

				

				if (t.options[tagName + 'Height'] > 0 || t.options[tagName + 'Height'].toString().indexOf('%') > -1) {

					t.height = t.options[tagName + 'Height'];

				} else if (t.media.style.height !== '' && t.media.style.height !== null) {

					t.height = t.media.style.height;

				} else if (t.$media[0].getAttribute('height') !== null) {

					t.height = t.$media.attr('height');	

				} else {

					t.height = t.options['default' + capsTagName + 'Height'];

				}



				// set the size, while we wait for the plugins to load below

				t.setPlayerSize(t.width, t.height);

				

				// create MediaElementShim

				meOptions.pluginWidth = t.height;

				meOptions.pluginHeight = t.width;				

			}

			

			



			// create MediaElement shim

			mejs.MediaElement(t.$media[0], meOptions);

		},

		

		showControls: function(doAnimation) {

			var t = this;

			

			doAnimation = typeof doAnimation == 'undefined' || doAnimation;

			

			if (t.controlsAreVisible)

				return;

			

			if (doAnimation) {

				t.controls

					.css('visibility','visible')

					.stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});	

	

				// any additional controls people might add and want to hide

				t.container.find('.mejs-control')

					.css('visibility','visible')

					.stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});	

					

			} else {

				t.controls

					.css('visibility','visible')

					.css('display','block');

	

				// any additional controls people might add and want to hide

				t.container.find('.mejs-control')

					.css('visibility','visible')

					.css('display','block');

					

				t.controlsAreVisible = true;

			}

			

			t.setControlsSize();

			

		},



		hideControls: function(doAnimation) {

			var t = this;

			

			doAnimation = typeof doAnimation == 'undefined' || doAnimation;

			

			if (!t.controlsAreVisible)

				return;

			

			if (doAnimation) {

				// fade out main controls

				t.controls.stop(true, true).fadeOut(200, function() {

					$(this)

						.css('visibility','hidden')

						.css('display','block');

						

					t.controlsAreVisible = false;

				});	

	

				// any additional controls people might add and want to hide

				t.container.find('.mejs-control').stop(true, true).fadeOut(200, function() {

					$(this)

						.css('visibility','hidden')

						.css('display','block');

				});	

			} else {

				

				// hide main controls

				t.controls

					.css('visibility','hidden')

					.css('display','block');		

				

				// hide others

				t.container.find('.mejs-control')

					.css('visibility','hidden')

					.css('display','block');

					

				t.controlsAreVisible = false;

			}

		},		



		controlsTimer: null,



		startControlsTimer: function(timeout) {



			var t = this;

			

			timeout = typeof timeout != 'undefined' ? timeout : 1500;



			t.killControlsTimer('start');



			t.controlsTimer = setTimeout(function() {

				//console.log('timer fired');

				t.hideControls();

				t.killControlsTimer('hide');

			}, timeout);

		},



		killControlsTimer: function(src) {



			var t = this;



			if (t.controlsTimer !== null) {

				clearTimeout(t.controlsTimer);

				delete t.controlsTimer;

				t.controlsTimer = null;

			}

		},		

		

		controlsEnabled: true,

		

		disableControls: function() {

			var t= this;

			

			t.killControlsTimer();

			t.hideControls(false);

			this.controlsEnabled = false;

		},

		

		enableControls: function() {

			var t= this;

			

			t.showControls(false);

			

			t.controlsEnabled = true;

		},		

		



		// Sets up all controls and events

		meReady: function(media, domNode) {			

		

		

			var t = this,

				mf = mejs.MediaFeatures,

				autoplayAttr = domNode.getAttribute('autoplay'),

				autoplay = !(typeof autoplayAttr == 'undefined' || autoplayAttr === null || autoplayAttr === 'false'),

				featureIndex,

				feature;



			// make sure it can't create itself again if a plugin reloads

			if (t.created)

				return;

			else

				t.created = true;			



			t.media = media;

			t.domNode = domNode;

			

			if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {				

				

				// two built in features

				t.buildposter(t, t.controls, t.layers, t.media);

				t.buildkeyboard(t, t.controls, t.layers, t.media);

				t.buildoverlays(t, t.controls, t.layers, t.media);



				// grab for use by features

				t.findTracks();



				// add user-defined features/controls

				for (featureIndex in t.options.features) {

					feature = t.options.features[featureIndex];

					if (t['build' + feature]) {

						try {

							t['build' + feature](t, t.controls, t.layers, t.media);

						} catch (e) {

							// TODO: report control error

							//throw e;

							//console.log('error building ' + feature);

							//console.log(e);

						}

					}

				}



				t.container.trigger('controlsready');

				

				// reset all layers and controls

				t.setPlayerSize(t.width, t.height);

				t.setControlsSize();

				



				// controls fade

				if (t.isVideo) {

				

					if (mejs.MediaFeatures.hasTouch) {

						

						// for touch devices (iOS, Android)

						// show/hide without animation on touch

						

						t.$media.bind('touchstart', function() {

							

							

							// toggle controls

							if (t.controlsAreVisible) {

								t.hideControls(false);

							} else {

								if (t.controlsEnabled) {

									t.showControls(false);

								}

							}

						});					

					

					} else {

						// click controls

						var clickElement = (t.media.pluginType == 'native') ? t.$media : $(t.media.pluginElement);

						

						// click to play/pause

						clickElement.click(function() {

							if (media.paused) {

								media.play();

							} else {

								media.pause();

							}

						});

						

					

						// show/hide controls

						t.container

							.bind('mouseenter mouseover', function () {

								if (t.controlsEnabled) {

									if (!t.options.alwaysShowControls) {								

										t.killControlsTimer('enter');

										t.showControls();

										t.startControlsTimer(2500);		

									}

								}

							})

							.bind('mousemove', function() {

								if (t.controlsEnabled) {

									if (!t.controlsAreVisible) {

										t.showControls();

									}

									//t.killControlsTimer('move');

									if (!t.options.alwaysShowControls) {

										t.startControlsTimer(1000);

									}

								}

							})

							.bind('mouseleave', function () {

								if (t.controlsEnabled) {

									if (!t.media.paused && !t.options.alwaysShowControls) {

										t.startControlsTimer(1000);								

									}

								}

							});

					}

					

					// check for autoplay

					if (autoplay && !t.options.alwaysShowControls) {

						t.hideControls();

					}



					// resizer

					if (t.options.enableAutosize) {

						t.media.addEventListener('loadedmetadata', function(e) {

							// if the <video height> was not set and the options.videoHeight was not set

							// then resize to the real dimensions

							if (t.options.videoHeight <= 0 && t.domNode.getAttribute('height') === null && !isNaN(e.target.videoHeight)) {

								t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);

								t.setControlsSize();

								t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);

							}

						}, false);

					}

				}

				

				// EVENTS



				// FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)

				media.addEventListener('play', function() {

						

						// go through all other players

						for (var i=0, il=mejs.players.length; i<il; i++) {

							var p = mejs.players[i];

							if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {

								p.pause();

							}

							p.hasFocus = false;

						}

						

						t.hasFocus = true;

				},false);

								



				// ended for all

				t.media.addEventListener('ended', function (e) {

					try{

						t.media.setCurrentTime(0);

					} catch (exp) {

						

					}

					t.media.pause();

					

					if (t.setProgressRail)

						t.setProgressRail();

					if (t.setCurrentRail)

						t.setCurrentRail();						



					if (t.options.loop) {

						t.media.play();

					} else if (!t.options.alwaysShowControls && t.controlsEnabled) {

						t.showControls();

					}

				}, false);

				

				// resize on the first play

				t.media.addEventListener('loadedmetadata', function(e) {

					if (t.updateDuration) {

						t.updateDuration();

					}

					if (t.updateCurrent) {

						t.updateCurrent();

					}

					

					if (!t.isFullScreen) {

						t.setPlayerSize(t.width, t.height);

						t.setControlsSize();

					}

				}, false);





				// webkit has trouble doing this without a delay

				setTimeout(function () {

					t.setPlayerSize(t.width, t.height);

					t.setControlsSize();

				}, 50);

				

				// adjust controls whenever window sizes (used to be in fullscreen only)

				$(window).resize(function() {

					

					// don't resize for fullscreen mode				

					if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {

						t.setPlayerSize(t.width, t.height);

					}

					

					// always adjust controls

					t.setControlsSize();

				});				



				// TEMP: needs to be moved somewhere else

				if (t.media.pluginType == 'youtube') {

					t.container.find('.mejs-overlay-play').hide();	

				}

			}

			

			// force autoplay for HTML5

			if (autoplay && media.pluginType == 'native') {

				media.load();

				media.play();

			}





			if (t.options.success) {

				

				if (typeof t.options.success == 'string') {

						window[t.options.success](t.media, t.domNode, t);

				} else {

						t.options.success(t.media, t.domNode, t);

				}

			}

		},



		handleError: function(e) {

			var t = this;

			

			t.controls.hide();

		

			// Tell user that the file cannot be played

			if (t.options.error) {

				t.options.error(e);

			}

		},



		setPlayerSize: function(width,height) {

			var t = this;

			

			// testing for 100% code

			if (t.height.toString().indexOf('%') > 0) {

			

				// do we have the native dimensions yet?

				var 

					nativeWidth = (t.media.videoWidth && t.media.videoWidth > 0) ? t.media.videoWidth : t.options.defaultVideoWidth,

					nativeHeight = (t.media.videoHeight && t.media.videoHeight > 0) ? t.media.videoHeight : t.options.defaultVideoHeight,

					parentWidth = t.container.parent().width(),

					newHeight = parseInt(parentWidth * nativeHeight/nativeWidth, 10);

					

				if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) {

					parentWidth = $(window).width();

					newHeight = $(window).height();

				}

					

				

				// set outer container size

				t.container

					.width(parentWidth)

					.height(newHeight);

					

				// set native <video>

				t.$media

					.width('100%')

					.height('100%');

					

				// set shims

				t.container.find('object, embed, iframe')

					.width('100%')

					.height('100%');

					

				// if shim is ready, send the size to the embeded plugin	

				if (t.media.setVideoSize)

					t.media.setVideoSize(parentWidth, newHeight);

					

				// set the layers

				t.layers.children('.mejs-layer')

					.width('100%')

					.height('100%');					

			

			

			} else {



				t.container

					.width(t.width)

					.height(t.height);

	

				t.layers.children('.mejs-layer')

					.width(t.width)

					.height(t.height);

					

			}

		},



		setControlsSize: function() {

			var t = this,

				usedWidth = 0,

				railWidth = 0,

				rail = t.controls.find('.mejs-time-rail'),

				total = t.controls.find('.mejs-time-total'),

				current = t.controls.find('.mejs-time-current'),

				loaded = t.controls.find('.mejs-time-loaded');

				others = rail.siblings();

			



			// allow the size to come from custom CSS

			if (t.options && !t.options.autosizeProgress) {

				// Also, frontends devs can be more flexible 

				// due the opportunity of absolute positioning.

				railWidth = parseInt(rail.css('width'));

			}

			

			// attempt to autosize

			if (railWidth === 0 || !railWidth) {

				

				// find the size of all the other controls besides the rail

				others.each(function() {

					if ($(this).css('position') != 'absolute') {

						usedWidth += $(this).outerWidth(true);

					}

				});

				

				// fit the rail into the remaining space

				railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.outerWidth(false));

			}



			// outer area

			rail.width(railWidth);

			// dark space

			total.width(railWidth - (total.outerWidth(true) - total.width()));

			

			if (t.setProgressRail)

				t.setProgressRail();

			if (t.setCurrentRail)

				t.setCurrentRail();				

		},





		buildposter: function(player, controls, layers, media) {

			var t = this,

				poster = 

				$('<div class="mejs-poster mejs-layer">' +

				'</div>')

					.appendTo(layers),

				posterUrl = player.$media.attr('poster');



			// prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)

			if (player.options.poster !== '') {

				posterUrl = player.options.poster;

			}	

				

			// second, try the real poster

			if (posterUrl !== '' && posterUrl != null) {

				t.setPoster(posterUrl);

			} else {

				poster.hide();

			}



			media.addEventListener('play',function() {

				poster.hide();

			}, false);

		},

		

		setPoster: function(url) {

			var t = this,

				posterDiv = t.container.find('.mejs-poster'),

				posterImg = posterDiv.find('img');

				

			if (posterImg.length == 0) {

				posterImg = $('<img width="100%" height="100%" />').appendTo(posterDiv);

			}	

			

			posterImg.attr('src', url);

		},



		buildoverlays: function(player, controls, layers, media) {

			if (!player.isVideo)

				return;



			var 

			loading = 

				$('<div class="mejs-overlay mejs-layer">'+

					'<div class="mejs-overlay-loading"><span></span></div>'+

				'</div>')

				.hide() // start out hidden

				.appendTo(layers),

			error = 

				$('<div class="mejs-overlay mejs-layer">'+

					'<div class="mejs-overlay-error"></div>'+

				'</div>')

				.hide() // start out hidden

				.appendTo(layers),				

				

			// this needs to come last so it's on top

			bigPlay = 

				$('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+

					'<div class="mejs-overlay-button"></div>'+

				'</div>')

				.appendTo(layers)

				.click(function() {

					if (media.paused) {

						media.play();

					} else {

						media.pause();

					}

				});

			

			/*

			if (mejs.MediaFeatures.isiOS || mejs.MediaFeatures.isAndroid) {

				bigPlay.remove();

				loading.remove();

			}

			*/

	



			// show/hide big play button

			media.addEventListener('play',function() {

				bigPlay.hide();

				loading.hide();

				error.hide();

			}, false);	

			

			media.addEventListener('playing', function() {

				bigPlay.hide();

				loading.hide();

				error.hide();			

			}, false);

	

			media.addEventListener('pause',function() {

				if (!mejs.MediaFeatures.isiPhone) {

					bigPlay.show();

				}

			}, false);

			

			media.addEventListener('waiting', function() {

				loading.show();	

			}, false);			

			

			

			// show/hide loading			

			media.addEventListener('loadeddata',function() {

				// for some reason Chrome is firing this event

				//if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')

				//	return;

					

				loading.show();

			}, false);	

			media.addEventListener('canplay',function() {

				loading.hide();

			}, false);	



			// error handling

			media.addEventListener('error',function() {

				loading.hide();

				error.show();

				error.find('mejs-overlay-error').html("Error loading this resource");

			}, false);				

		},

		

		buildkeyboard: function(player, controls, layers, media) {



				var t = this;

				

				// listen for key presses

				$(document).keydown(function(e) {

						

						if (player.hasFocus && player.options.enableKeyboard) {

										

								// find a matching key

								for (var i=0, il=player.options.keyActions.length; i<il; i++) {

										var keyAction = player.options.keyActions[i];

										

										for (var j=0, jl=keyAction.keys.length; j<jl; j++) {

												if (e.keyCode == keyAction.keys[j]) {

														e.preventDefault();

														keyAction.action(player, media);

														return false;

												}												

										}

								}

						}

						

						return true;

				});

				

				// check if someone clicked outside a player region, then kill its focus

				$(document).click(function(event) {

						if ($(event.target).closest('.mejs-container').length == 0) {

								player.hasFocus = false;

						}

				});

			

		},



		findTracks: function() {

			var t = this,

				tracktags = t.$media.find('track');



			// store for use by plugins

			t.tracks = [];

			tracktags.each(function(index, track) {

				

				track = $(track);

				

				t.tracks.push({

					srclang: track.attr('srclang').toLowerCase(),

					src: track.attr('src'),

					kind: track.attr('kind'),

					label: track.attr('label') || '',

					entries: [],

					isLoaded: false

				});

			});

		},

		changeSkin: function(className) {

			this.container[0].className = 'mejs-container ' + className;

			this.setPlayerSize();

			this.setControlsSize();

		},

		play: function() {

			this.media.play();

		},

		pause: function() {

			this.media.pause();

		},

		load: function() {

			this.media.load();

		},

		setMuted: function(muted) {

			this.media.setMuted(muted);

		},

		setCurrentTime: function(time) {

			this.media.setCurrentTime(time);

		},

		getCurrentTime: function() {

			return this.media.currentTime;

		},

		setVolume: function(volume) {

			this.media.setVolume(volume);

		},

		getVolume: function() {

			return this.media.volume;

		},

		setSrc: function(src) {

			this.media.setSrc(src);

		},

		remove: function() {

			var t = this;

			

			if (t.media.pluginType == 'flash') {

				t.media.remove();

			} else if (t.media.pluginTyp == 'native') {

				t.media.prop('controls', true);

			}

			

			// grab video and put it back in place

			if (!t.isDynamic) {

				t.$node.insertBefore(t.container)

			}

			

			t.container.remove();

		}

	};



	// turn into jQuery plugin

	if (typeof jQuery != 'undefined') {

		jQuery.fn.mediaelementplayer = function (options) {

			return this.each(function () {

				new mejs.MediaElementPlayer(this, options);

			});

		};

	}

	

	$(document).ready(function() {

		// auto enable using JSON attribute

		$('.mejs-player').mediaelementplayer();

	});

	

	// push out to window

	window.MediaElementPlayer = mejs.MediaElementPlayer;



})(mejs.$);
(function($) {

	$.extend(mejs.MepDefaults, {
		playpauseText: 'Play/Pause'
	});

	// PLAY/pause BUTTON
	$.extend(MediaElementPlayer.prototype, {
		buildplaypause: function(player, controls, layers, media) {
			var 
				t = this,
				play = 
				$('<div class="mejs-button mejs-playpause-button mejs-play" >' +
					'<button type="button" aria-controls="' + t.id + '" title="' + t.options.playpauseText + '"></button>' +
				'</div>')
				.appendTo(controls)
				.click(function(e) {
					e.preventDefault();
				
					if (media.paused) {
						media.play();
					} else {
						media.pause();
					}
					
					return false;
				});

			media.addEventListener('play',function() {
				play.removeClass('mejs-play').addClass('mejs-pause');
			}, false);
			media.addEventListener('playing',function() {
				play.removeClass('mejs-play').addClass('mejs-pause');
			}, false);


			media.addEventListener('pause',function() {
				play.removeClass('mejs-pause').addClass('mejs-play');
			}, false);
			media.addEventListener('paused',function() {
				play.removeClass('mejs-pause').addClass('mejs-play');
			}, false);
		}
	});
	
})(mejs.$);
(function($) {

	$.extend(mejs.MepDefaults, {
		stopText: 'Stop'
	});

	// STOP BUTTON
	$.extend(MediaElementPlayer.prototype, {
		buildstop: function(player, controls, layers, media) {
			var t = this,
				stop = 
				$('<div class="mejs-button mejs-stop-button mejs-stop">' +
					'<button type="button" aria-controls="' + t.id + '" title="' + t.options.stopText + '></button>' +
				'</div>')
				.appendTo(controls)
				.click(function() {
					if (!media.paused) {
						media.pause();
					}
					if (media.currentTime > 0) {
						media.setCurrentTime(0);	
						controls.find('.mejs-time-current').width('0px');
						controls.find('.mejs-time-handle').css('left', '0px');
						controls.find('.mejs-time-float-current').html( mejs.Utility.secondsToTimeCode(0) );
						controls.find('.mejs-currenttime').html( mejs.Utility.secondsToTimeCode(0) );					
						layers.find('.mejs-poster').show();
					}
				});
		}
	});
	
})(mejs.$);
(function($) {
	// progress/loaded bar
	$.extend(MediaElementPlayer.prototype, {
		buildprogress: function(player, controls, layers, media) {

			$('<div class="mejs-time-rail">'+
				'<span class="mejs-time-total">'+
					'<span class="mejs-time-loaded"></span>'+
					'<span class="mejs-time-current"></span>'+
					'<span class="mejs-time-handle"></span>'+
					'<span class="mejs-time-float">' + 
						'<span class="mejs-time-float-current">00:00</span>' + 
						'<span class="mejs-time-float-corner"></span>' + 
					'</span>'+
				'</span>'+
			'</div>')
				.appendTo(controls);

			var 
				t = this,
				total = controls.find('.mejs-time-total'),
				loaded  = controls.find('.mejs-time-loaded'),
				current  = controls.find('.mejs-time-current'),
				handle  = controls.find('.mejs-time-handle'),
				timefloat  = controls.find('.mejs-time-float'),
				timefloatcurrent  = controls.find('.mejs-time-float-current'),
				handleMouseMove = function (e) {
					// mouse position relative to the object
					var x = e.pageX,
						offset = total.offset(),
						width = total.outerWidth(),
						percentage = 0,
						newTime = 0,
						pos = x - offset.left;


					if (x > offset.left && x <= width + offset.left && media.duration) {
						percentage = ((x - offset.left) / width);
						newTime = (percentage <= 0.02) ? 0 : percentage * media.duration;

						// seek to where the mouse is
						if (mouseIsDown) {
							media.setCurrentTime(newTime);
						}

						// position floating time box
						if (!mejs.MediaFeatures.hasTouch) {
								timefloat.css('left', pos);
								timefloatcurrent.html( mejs.Utility.secondsToTimeCode(newTime) );
								timefloat.show();
						}
					}
				},
				mouseIsDown = false,
				mouseIsOver = false;

			// handle clicks
			//controls.find('.mejs-time-rail').delegate('span', 'click', handleMouseMove);
			total
				.bind('mousedown', function (e) {
					// only handle left clicks
					if (e.which === 1) {
						mouseIsDown = true;
						handleMouseMove(e);
						return false;
					}					
				});

			controls.find('.mejs-time-total')
				.bind('mouseenter', function(e) {
					mouseIsOver = true;
					if (!mejs.MediaFeatures.hasTouch) {
						timefloat.show();
					}
				})
				.bind('mouseleave',function(e) {
					mouseIsOver = false;
					timefloat.hide();
				});

			$(document)
				.bind('mouseup', function (e) {
					mouseIsDown = false;
					timefloat.hide();
					//handleMouseMove(e);
				})
				.bind('mousemove', function (e) {
					if (mouseIsDown || mouseIsOver) {
						handleMouseMove(e);
					}
				});

			// loading
			media.addEventListener('progress', function (e) {
				player.setProgressRail(e);
				player.setCurrentRail(e);
			}, false);

			// current time
			media.addEventListener('timeupdate', function(e) {
				player.setProgressRail(e);
				player.setCurrentRail(e);
			}, false);
			
			
			// store for later use
			t.loaded = loaded;
			t.total = total;
			t.current = current;
			t.handle = handle;
		},
		setProgressRail: function(e) {

			var
				t = this,
				target = (e != undefined) ? e.target : t.media,
				percent = null;			

			// newest HTML5 spec has buffered array (FF4, Webkit)
			if (target && target.buffered && target.buffered.length > 0 && target.buffered.end && target.duration) {
				// TODO: account for a real array with multiple values (only Firefox 4 has this so far) 
				percent = target.buffered.end(0) / target.duration;
			} 
			// Some browsers (e.g., FF3.6 and Safari 5) cannot calculate target.bufferered.end()
			// to be anything other than 0. If the byte count is available we use this instead.
			// Browsers that support the else if do not seem to have the bufferedBytes value and
			// should skip to there. Tested in Safari 5, Webkit head, FF3.6, Chrome 6, IE 7/8.
			else if (target && target.bytesTotal != undefined && target.bytesTotal > 0 && target.bufferedBytes != undefined) {
				percent = target.bufferedBytes / target.bytesTotal;
			}
			// Firefox 3 with an Ogg file seems to go this way
			else if (e && e.lengthComputable && e.total != 0) {
				percent = e.loaded/e.total;
			}

			// finally update the progress bar
			if (percent !== null) {
				percent = Math.min(1, Math.max(0, percent));
				// update loaded bar
				if (t.loaded && t.total) {
					t.loaded.width(t.total.width() * percent);
				}
			}
		},
		setCurrentRail: function() {

			var t = this;
		
			if (t.media.currentTime != undefined && t.media.duration) {

				// update bar and handle
				if (t.total && t.handle) {
					var 
						newWidth = t.total.width() * t.media.currentTime / t.media.duration,
						handlePos = newWidth - (t.handle.outerWidth(true) / 2);

					t.current.width(newWidth);
					t.handle.css('left', handlePos);
				}
			}

		}	
	});
})(mejs.$);
(function($) {

	

	// options

	$.extend(mejs.MepDefaults, {

		duration: -1,

		timeAndDurationSeparator: ' <span> | </span> '

	});





	// current and duration 00:00 / 00:00

	$.extend(MediaElementPlayer.prototype, {

		buildcurrent: function(player, controls, layers, media) {

			var t = this;

			

			$('<div class="mejs-time">'+

					'<span class="mejs-currenttime">' + (player.options.alwaysShowHours ? '00:' : '')

					+ (player.options.showTimecodeFrameCount? '00:00:00':'00:00')+ '</span>'+

					'</div>')

					.appendTo(controls);

			

			t.currenttime = t.controls.find('.mejs-currenttime');



			media.addEventListener('timeupdate',function() {

				player.updateCurrent();

			}, false);

		},





		buildduration: function(player, controls, layers, media) {

			var t = this;

			

			if (controls.children().last().find('.mejs-currenttime').length > 0) {

				$(t.options.timeAndDurationSeparator +

					'<span class="mejs-duration">' + 

						(t.options.duration > 0 ? 

							mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount,  t.options.framesPerSecond || 25) :

				   			((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00')) 

				   		) + 

					'</span>')

					.appendTo(controls.find('.mejs-time'));

			} else {



				// add class to current time

				controls.find('.mejs-currenttime').parent().addClass('mejs-currenttime-container');

				

				$('<div class="mejs-time mejs-duration-container">'+

					'<span class="mejs-duration">' + 

						(t.options.duration > 0 ? 

							mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount,  t.options.framesPerSecond || 25) :

				   			((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00')) 

				   		) + 

					'</span>' +

				'</div>')

				.appendTo(controls);

			}

			

			t.durationD = t.controls.find('.mejs-duration');



			media.addEventListener('timeupdate',function() {

				player.updateDuration();

			}, false);

		},

		

		updateCurrent:  function() {

			var t = this;



			if (t.currenttime) {

				t.currenttime.html(mejs.Utility.secondsToTimeCode(t.media.currentTime, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount,  t.options.framesPerSecond || 25));

			}

		},

		

		updateDuration: function() {	

			var t = this;

			

			if (t.media.duration && t.durationD) {

				t.durationD.html(mejs.Utility.secondsToTimeCode(t.media.duration, t.options.alwaysShowHours, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));

			}		

		}

	});



})(mejs.$);
(function($) {

	$.extend(mejs.MepDefaults, {
		muteText: 'Mute Toggle',
		hideVolumeOnTouchDevices: true
	});

	$.extend(MediaElementPlayer.prototype, {
		buildvolume: function(player, controls, layers, media) {
			
			// Android and iOS don't support volume controls
			if (mejs.MediaFeatures.hasTouch && this.options.hideVolumeOnTouchDevices)
				return;
			
			var t = this,
				mute = 
				$('<div class="mejs-button mejs-volume-button mejs-mute">'+
					'<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
					'<div class="mejs-volume-slider">'+ // outer background
						'<div class="mejs-volume-total"></div>'+ // line background
						'<div class="mejs-volume-current"></div>'+ // current volume
						'<div class="mejs-volume-handle"></div>'+ // handle
					'</div>'+
				'</div>')
				.appendTo(controls),
			volumeSlider = mute.find('.mejs-volume-slider'),
			volumeTotal = mute.find('.mejs-volume-total'),
			volumeCurrent = mute.find('.mejs-volume-current'),
			volumeHandle = mute.find('.mejs-volume-handle'),

			positionVolumeHandle = function(volume) {

				if (!volumeSlider.is(':visible')) {
					volumeSlider.show();
					positionVolumeHandle(volume);
					volumeSlider.hide()
					return;
				}

				var 
				
					// height of the full size volume slider background
					totalHeight = volumeTotal.height(),
					
					// top/left of full size volume slider background
					totalPosition = volumeTotal.position(),
					
					// the new top position based on the current volume
					// 70% volume on 100px height == top:30px
					newTop = totalHeight - (totalHeight * volume);

				// handle
				volumeHandle.css('top', totalPosition.top + newTop - (volumeHandle.height() / 2));

				// show the current visibility
				volumeCurrent.height(totalHeight - newTop );
				volumeCurrent.css('top', totalPosition.top + newTop);
			},
			handleVolumeMove = function(e) {
				var
					railHeight = volumeTotal.height(),
					totalOffset = volumeTotal.offset(),
					totalTop = parseInt(volumeTotal.css('top').replace(/px/,''),10),
					newY = e.pageY - totalOffset.top,
					volume = (railHeight - newY) / railHeight
					
				// the controls just hide themselves (usually when mouse moves too far up)
				if (totalOffset.top == 0 || totalOffset.left == 0)
					return;
					
				// 0-1
				volume = Math.max(0,volume);
				volume = Math.min(volume,1);						

				// TODO: handle vertical and horizontal CSS
				// only allow it to move within the rail
				if (newY < 0)
					newY = 0;
				else if (newY > railHeight)
					newY = railHeight;

				// move the handle to match the mouse
				volumeHandle.css('top', newY - (volumeHandle.height() / 2) + totalTop );

				// show the current visibility
				volumeCurrent.height(railHeight-newY);
				volumeCurrent.css('top',newY+totalTop);

				// set mute status
				if (volume == 0) {
					media.setMuted(true);
					mute.removeClass('mejs-mute').addClass('mejs-unmute');
				} else {
					media.setMuted(false);
					mute.removeClass('mejs-unmute').addClass('mejs-mute');
				}

				volume = Math.max(0,volume);
				volume = Math.min(volume,1);

				// set the volume
				media.setVolume(volume);
			},
			mouseIsDown = false,
			mouseIsOver = false;

			// SLIDER
			mute
				.hover(function() {
					volumeSlider.show();
					mouseIsOver = true;
				}, function() {
					mouseIsOver = false;	
						
					if (!mouseIsDown)	{
						volumeSlider.hide();
					}
				});
			
			volumeSlider
				.bind('mouseover', function() {
					mouseIsOver = true;	
				})
				.bind('mousedown', function (e) {
					handleVolumeMove(e);
					mouseIsDown = true;
						
					return false;
				});
				
			$(document)
				.bind('mouseup', function (e) {
					mouseIsDown = false;
					
					if (!mouseIsOver) {
						volumeSlider.hide();
					}
				})
				.bind('mousemove', function (e) {
					if (mouseIsDown) {
						handleVolumeMove(e);
					}
				});


			// MUTE button
			mute.find('button').click(function() {

				media.setMuted( !media.muted );
				
			});

			// listen for volume change events from other sources
			media.addEventListener('volumechange', function(e) {
				if (!mouseIsDown) {
					if (media.muted) {
						positionVolumeHandle(0);
						mute.removeClass('mejs-mute').addClass('mejs-unmute');
					} else {
						positionVolumeHandle(media.volume);
						mute.removeClass('mejs-unmute').addClass('mejs-mute');
					}
				}
			}, false);

			// set initial volume
			//console.log('init volume',player.options.startVolume);
			positionVolumeHandle(player.options.startVolume);
			
			// shim gets the startvolume as a parameter, but we have to set it on the native <video> and <audio> elements
			if (media.pluginType === 'native') {
				media.setVolume(player.options.startVolume);
			}
		}
	});
	
})(mejs.$);

(function($) {

	

	$.extend(mejs.MepDefaults, {

		usePluginFullScreen: true,

		newWindowCallback: function() { return '';},

		fullscreenText: 'Fullscreen'

	});

	

	$.extend(MediaElementPlayer.prototype, {

		

		isFullScreen: false,

		

		isNativeFullScreen: false,

		

		docStyleOverflow: null,

		

		isInIframe: false,

		

		buildfullscreen: function(player, controls, layers, media) {



			if (!player.isVideo)

				return;

				

			player.isInIframe = (window.location != window.parent.location);

				

			// native events

			if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

				

				player.container.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {

				//player.container.bind('webkitfullscreenchange', function(e) {

				

					

					if (mejs.MediaFeatures.isFullScreen()) {

						player.isNativeFullScreen = true;

						// reset the controls once we are fully in full screen

						player.setControlsSize();

					} else {

						player.isNativeFullScreen = false;

						// when a user presses ESC

						// make sure to put the player back into place								

						player.exitFullScreen();				

					}

				});

			}



			var t = this,		

				normalHeight = 0,

				normalWidth = 0,

				container = player.container,						

				fullscreenBtn = 

					$('<div class="mejs-button mejs-fullscreen-button">' + 

						'<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' + 

					'</div>')

					.appendTo(controls);

				

				if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {

					

					fullscreenBtn.click(function() {

						var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;													

						

						if (isFullScreen) {

							player.exitFullScreen();

						} else {						

							player.enterFullScreen();

						}

					});

					

				} else {



					var hideTimeout = null,

						supportsPointerEvents = (document.documentElement.style.pointerEvents === '');

						

					if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(

						

						// allows clicking through the fullscreen button and controls down directly to Flash

						

						/*

						 When a user puts his mouse over the fullscreen button, the controls are disabled

						 So we put a div over the video and another one on iether side of the fullscreen button

						 that caputre mouse movement

						 and restore the controls once the mouse moves outside of the fullscreen button

						*/

						

						var fullscreenIsDisabled = false,

							restoreControls = function() {

								if (fullscreenIsDisabled) {

									// hide the hovers

									videoHoverDiv.hide();

									controlsLeftHoverDiv.hide();

									controlsRightHoverDiv.hide();

									

									// restore the control bar

									fullscreenBtn.css('pointer-events', '');

									t.controls.css('pointer-events', '');

									

									// store for later

									fullscreenIsDisabled = false;

								}

							},

							videoHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),

							controlsLeftHoverDiv = $('<div class="mejs-fullscreen-hover"  />').appendTo(t.container).mouseover(restoreControls),

							controlsRightHoverDiv = $('<div class="mejs-fullscreen-hover"  />').appendTo(t.container).mouseover(restoreControls),

							positionHoverDivs = function() {

								var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};

								videoHoverDiv.css(style);

								controlsLeftHoverDiv.css(style);

								controlsRightHoverDiv.css(style);

								

								// over video, but not controls

								videoHoverDiv

									.width( t.container.width() )

									.height( t.container.height() - t.controls.height() );

								

								// over controls, but not the fullscreen button

								var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;

									fullScreenBtnWidth = fullscreenBtn.outerWidth(true);

									

								controlsLeftHoverDiv

									.width( fullScreenBtnOffset )

									.height( t.controls.height() )

									.css({top: t.container.height() - t.controls.height()});

									

								// after the fullscreen button

								controlsRightHoverDiv

									.width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )

									.height( t.controls.height() )

									.css({top: t.container.height() - t.controls.height(),

										 left: fullScreenBtnOffset + fullScreenBtnWidth});								

							};

						

						$(document).resize(function() {

							positionHoverDivs();

						});

												

						// on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash

						fullscreenBtn

							.mouseover(function() {

								

								if (!t.isFullScreen) {

									

									var buttonPos = fullscreenBtn.offset(),

										containerPos = player.container.offset();

									

									// move the button in Flash into place

									media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);									

									

									// allows click through

									fullscreenBtn.css('pointer-events', 'none');

									t.controls.css('pointer-events', 'none');

									

									// show the divs that will restore things

									videoHoverDiv.show();

									controlsRightHoverDiv.show();

									controlsLeftHoverDiv.show();

									positionHoverDivs();

									

									fullscreenIsDisabled = true;

								}

							

							});

						

						// restore controls anytime the user enters or leaves fullscreen	

						media.addEventListener('fullscreenchange', function(e) {

							restoreControls();

						});

						

						

						// the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events

						// so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button 

						/*

						$(document).mousemove(function(e) {

							

							// if the mouse is anywhere but the fullsceen button, then restore it all

							if (fullscreenIsDisabled) {

								

								var fullscreenBtnPos = fullscreenBtn.offset();

								



								if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||

									e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)

									) {

								

									fullscreenBtn.css('pointer-events', '');

									t.controls.css('pointer-events', '');

									

									fullscreenIsDisabled = false;

								}

							}

						});

						*/

						

						

					} else {

						

						// the hover state will show the fullscreen button in Flash to hover up and click

						

						fullscreenBtn

							.mouseover(function() {

								

								if (hideTimeout !== null) {

									clearTimeout(hideTimeout);

									delete hideTimeout;

								}

								

								var buttonPos = fullscreenBtn.offset(),

									containerPos = player.container.offset();

									

								media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);

							

							})

							.mouseout(function() {

							

								if (hideTimeout !== null) {

									clearTimeout(hideTimeout);

									delete hideTimeout;

								}

								

								hideTimeout = setTimeout(function() {	

									media.hideFullscreenButton();

								}, 1500);

								

								

							});						

					}

				}

			

			player.fullscreenBtn = fullscreenBtn;	



			$(document).bind('keydown',function (e) {

				if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {

					player.exitFullScreen();

				}

			});

				

		},

		enterFullScreen: function() {

			

			var t = this;

			

			// firefox+flash can't adjust plugin sizes without resetting :(

			if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {

				//t.media.setFullscreen(true);

				//player.isFullScreen = true;

				return;

			}			

						

			// store overflow 

			docStyleOverflow = document.documentElement.style.overflow;

			// set it to not show scroll bars so 100% will work

			document.documentElement.style.overflow = 'hidden';			

		

			// store sizing

			normalHeight = t.container.height();

			normalWidth = t.container.width();

			

			// attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)

			if (t.media.pluginType === 'native') {

				if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

							

					mejs.MediaFeatures.requestFullScreen(t.container[0]);

					//return;

					

				} else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {

					t.media.webkitEnterFullscreen();

					return;

				}

			}

			

			// check for iframe launch

			if (t.isInIframe) {

				var url = t.options.newWindowCallback(this);

				

				

				if (url !== '') {

					

					// launch immediately

					if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {

						t.pause();

						window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');

						return;

					} else {

						setTimeout(function() {

							if (!t.isNativeFullScreen) {

								t.pause();

								window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');								

							}

						}, 250);

					}

				}	

				

			}

			

			// full window code



			



			// make full size

			t.container

				.addClass('mejs-container-fullscreen')

				.width('100%')

				.height('100%');

				//.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});				



			// Only needed for safari 5.1 native full screen, can cause display issues elsewhere

			// Actually, it seems to be needed for IE8, too

			//if (mejs.MediaFeatures.hasTrueNativeFullScreen) {

				setTimeout(function() {

					t.container.css({width: '100%', height: '100%'});

					t.setControlsSize();

				}, 500);

			//}

				

			if (t.pluginType === 'native') {

				t.$media

					.width('100%')

					.height('100%');

			} else {

				t.container.find('object, embed, iframe')

					.width('100%')

					.height('100%');

					

				//if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {

					t.media.setVideoSize($(window).width(),$(window).height());

				//}

			}

			

			t.layers.children('div')

				.width('100%')

				.height('100%');



			if (t.fullscreenBtn) {

				t.fullscreenBtn

					.removeClass('mejs-fullscreen')

					.addClass('mejs-unfullscreen');

			}



			t.setControlsSize();

			t.isFullScreen = true;

		},

		

		exitFullScreen: function() {

			

			var t = this;		

		

			// firefox can't adjust plugins

			if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {				

				t.media.setFullscreen(false);

				//player.isFullScreen = false;

				return;

			}		

		

			// come outo of native fullscreen

			if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {

				mejs.MediaFeatures.cancelFullScreen();

			}	



			// restore scroll bars to document

			document.documentElement.style.overflow = docStyleOverflow;					

				

			t.container

				.removeClass('mejs-container-fullscreen')

				.width(normalWidth)

				.height(normalHeight);

				//.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});

			

			if (t.pluginType === 'native') {

				t.$media

					.width(normalWidth)

					.height(normalHeight);

			} else {

				t.container.find('object embed')

					.width(normalWidth)

					.height(normalHeight);

					

				t.media.setVideoSize(normalWidth, normalHeight);

			}				



			t.layers.children('div')

				.width(normalWidth)

				.height(normalHeight);



			t.fullscreenBtn

				.removeClass('mejs-unfullscreen')

				.addClass('mejs-fullscreen');



			t.setControlsSize();

			t.isFullScreen = false;

		}	

	});



})(mejs.$);


(function($) {

	// add extra default options 
	$.extend(mejs.MepDefaults, {
		// this will automatically turn on a <track>
		startLanguage: '',
		
		tracksText: 'Captions/Subtitles'
	});

	$.extend(MediaElementPlayer.prototype, {
	
		hasChapters: false,

		buildtracks: function(player, controls, layers, media) {
			if (!player.isVideo)
				return;

			if (player.tracks.length == 0)
				return;

			var t= this, i, options = '';

			player.chapters = 
					$('<div class="mejs-chapters mejs-layer"></div>')
						.prependTo(layers).hide();
			player.captions = 
					$('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position"><span class="mejs-captions-text"></span></div></div>')
						.prependTo(layers).hide();
			player.captionsText = player.captions.find('.mejs-captions-text');
			player.captionsButton = 
					$('<div class="mejs-button mejs-captions-button">'+
						'<button type="button" aria-controls="' + t.id + '" title="' + t.options.tracksText + '"></button>'+
						'<div class="mejs-captions-selector">'+
							'<ul>'+
								'<li>'+
									'<input type="radio" name="' + player.id + '_captions" id="' + player.id + '_captions_none" value="none" checked="checked" />' +
									'<label for="' + player.id + '_captions_none">None</label>'+
								'</li>'	+
							'</ul>'+
						'</div>'+
					'</div>')
						.appendTo(controls)
						
						// hover
						.hover(function() {
							$(this).find('.mejs-captions-selector').css('visibility','visible');
						}, function() {
							$(this).find('.mejs-captions-selector').css('visibility','hidden');
						})					
						
						// handle clicks to the language radio buttons
						.delegate('input[type=radio]','click',function() {
							lang = this.value;

							if (lang == 'none') {
								player.selectedTrack = null;
							} else {
								for (i=0; i<player.tracks.length; i++) {
									if (player.tracks[i].srclang == lang) {
										player.selectedTrack = player.tracks[i];
										player.captions.attr('lang', player.selectedTrack.srclang);
										player.displayCaptions();
										break;
									}
								}
							}
						});
						//.bind('mouseenter', function() {
						//	player.captionsButton.find('.mejs-captions-selector').css('visibility','visible')
						//});

			if (!player.options.alwaysShowControls) {
				// move with controls
				player.container
					.bind('mouseenter', function () {
						// push captions above controls
						player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');

					})
					.bind('mouseleave', function () {
						if (!media.paused) {
							// move back to normal place
							player.container.find('.mejs-captions-position').removeClass('mejs-captions-position-hover');
						}
					});
			} else {
				player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
			}

			player.trackToLoad = -1;
			player.selectedTrack = null;
			player.isLoadingTrack = false;

			

			// add to list
			for (i=0; i<player.tracks.length; i++) {
				if (player.tracks[i].kind == 'subtitles') {
					player.addTrackButton(player.tracks[i].srclang, player.tracks[i].label);
				}
			}

			player.loadNextTrack();


			media.addEventListener('timeupdate',function(e) {
				player.displayCaptions();
			}, false);

			media.addEventListener('loadedmetadata', function(e) {
				player.displayChapters();
			}, false);

			player.container.hover(
				function () {
					// chapters
					if (player.hasChapters) {
						player.chapters.css('visibility','visible');
						player.chapters.fadeIn(200);
					}
				},
				function () {
					if (player.hasChapters && !media.paused) {
						player.chapters.fadeOut(200, function() {
							$(this).css('visibility','hidden');
							$(this).css('display','block');
						});
					}
				});
				
			// check for autoplay
			if (player.node.getAttribute('autoplay') !== null) {
				player.chapters.css('visibility','hidden');
			}
		},

		loadNextTrack: function() {
			var t = this;

			t.trackToLoad++;
			if (t.trackToLoad < t.tracks.length) {
				t.isLoadingTrack = true;
				t.loadTrack(t.trackToLoad);
			} else {
				// add done?
				t.isLoadingTrack = false;
			}
		},

		loadTrack: function(index){
			var
				t = this,
				track = t.tracks[index],
				after = function() {

					track.isLoaded = true;

					// create button
					//t.addTrackButton(track.srclang);
					t.enableTrackButton(track.srclang, track.label);

					t.loadNextTrack();

				};

			if (track.isTranslation) {

				// translate the first track
				mejs.TrackFormatParser.translateTrackText(t.tracks[0].entries, t.tracks[0].srclang, track.srclang, t.options.googleApiKey, function(newOne) {

					// store the new translation
					track.entries = newOne;

					after();
				});

			} else {
				$.ajax({
					url: track.src,
					success: function(d) {

						// parse the loaded file
						track.entries = mejs.TrackFormatParser.parse(d);
						after();

						if (track.kind == 'chapters' && t.media.duration > 0) {
							t.drawChapters(track);
						}
					},
					error: function() {
						t.loadNextTrack();
					}
				});
			}
		},

		enableTrackButton: function(lang, label) {
			var t = this;
			
			if (label === '') {
				label = mejs.language.codes[lang] || lang;
			}			

			t.captionsButton
				.find('input[value=' + lang + ']')
					.prop('disabled',false)
				.siblings('label')
					.html( label );

			// auto select
			if (t.options.startLanguage == lang) {
				$('#' + t.id + '_captions_' + lang).click();
			}

			t.adjustLanguageBox();
		},

		addTrackButton: function(lang, label) {
			var t = this;
			if (label === '') {
				label = mejs.language.codes[lang] || lang;
			}

			t.captionsButton.find('ul').append(
				$('<li>'+
					'<input type="radio" name="' + t.id + '_captions" id="' + t.id + '_captions_' + lang + '" value="' + lang + '" disabled="disabled" />' +
					'<label for="' + t.id + '_captions_' + lang + '">' + label + ' (loading)' + '</label>'+
				'</li>')
			);

			t.adjustLanguageBox();

			// remove this from the dropdownlist (if it exists)
			t.container.find('.mejs-captions-translations option[value=' + lang + ']').remove();
		},

		adjustLanguageBox:function() {
			var t = this;
			// adjust the size of the outer box
			t.captionsButton.find('.mejs-captions-selector').height(
				t.captionsButton.find('.mejs-captions-selector ul').outerHeight(true) +
				t.captionsButton.find('.mejs-captions-translations').outerHeight(true)
			);
		},

		displayCaptions: function() {

			if (typeof this.tracks == 'undefined')
				return;

			var
				t = this,
				i,
				track = t.selectedTrack;

			if (track != null && track.isLoaded) {
				for (i=0; i<track.entries.times.length; i++) {
					if (t.media.currentTime >= track.entries.times[i].start && t.media.currentTime <= track.entries.times[i].stop){
						t.captionsText.html(track.entries.text[i]);
						t.captions.show();
						return; // exit out if one is visible;
					}
				}
				t.captions.hide();
			} else {
				t.captions.hide();
			}
		},

		displayChapters: function() {
			var 
				t = this,
				i;

			for (i=0; i<t.tracks.length; i++) {
				if (t.tracks[i].kind == 'chapters' && t.tracks[i].isLoaded) {
					t.drawChapters(t.tracks[i]);
					t.hasChapters = true;
					break;
				}
			}
		},

		drawChapters: function(chapters) {
			var 
				t = this,
				i,
				dur,
				//width,
				//left,
				percent = 0,
				usedPercent = 0;

			t.chapters.empty();

			for (i=0; i<chapters.entries.times.length; i++) {
				dur = chapters.entries.times[i].stop - chapters.entries.times[i].start;
				percent = Math.floor(dur / t.media.duration * 100);
				if (percent + usedPercent > 100 || // too large
					i == chapters.entries.times.length-1 && percent + usedPercent < 100) // not going to fill it in
					{
					percent = 100 - usedPercent;
				}
				//width = Math.floor(t.width * dur / t.media.duration);
				//left = Math.floor(t.width * chapters.entries.times[i].start / t.media.duration);
				//if (left + width > t.width) {
				//	width = t.width - left;
				//}

				t.chapters.append( $(
					'<div class="mejs-chapter" rel="' + chapters.entries.times[i].start + '" style="left: ' + usedPercent.toString() + '%;width: ' + percent.toString() + '%;">' + 
						'<div class="mejs-chapter-block' + ((i==chapters.entries.times.length-1) ? ' mejs-chapter-block-last' : '') + '">' + 
							'<span class="ch-title">' + chapters.entries.text[i] + '</span>' + 
							'<span class="ch-time">' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].start) + '&ndash;' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].stop) + '</span>' + 
						'</div>' +
					'</div>'));
				usedPercent += percent;
			}

			t.chapters.find('div.mejs-chapter').click(function() {
				t.media.setCurrentTime( parseFloat( $(this).attr('rel') ) );
				if (t.media.paused) {
					t.media.play(); 
				}
			});

			t.chapters.show();
		}
	});



	mejs.language = {
		codes:  {
			af:'Afrikaans',
			sq:'Albanian',
			ar:'Arabic',
			be:'Belarusian',
			bg:'Bulgarian',
			ca:'Catalan',
			zh:'Chinese',
			'zh-cn':'Chinese Simplified',
			'zh-tw':'Chinese Traditional',
			hr:'Croatian',
			cs:'Czech',
			da:'Danish',
			nl:'Dutch',
			en:'English',
			et:'Estonian',
			tl:'Filipino',
			fi:'Finnish',
			fr:'French',
			gl:'Galician',
			de:'German',
			el:'Greek',
			ht:'Haitian Creole',
			iw:'Hebrew',
			hi:'Hindi',
			hu:'Hungarian',
			is:'Icelandic',
			id:'Indonesian',
			ga:'Irish',
			it:'Italian',
			ja:'Japanese',
			ko:'Korean',
			lv:'Latvian',
			lt:'Lithuanian',
			mk:'Macedonian',
			ms:'Malay',
			mt:'Maltese',
			no:'Norwegian',
			fa:'Persian',
			pl:'Polish',
			pt:'Portuguese',
			//'pt-pt':'Portuguese (Portugal)',
			ro:'Romanian',
			ru:'Russian',
			sr:'Serbian',
			sk:'Slovak',
			sl:'Slovenian',
			es:'Spanish',
			sw:'Swahili',
			sv:'Swedish',
			tl:'Tagalog',
			th:'Thai',
			tr:'Turkish',
			uk:'Ukrainian',
			vi:'Vietnamese',
			cy:'Welsh',
			yi:'Yiddish'
		}
	};

	/*
	Parses WebVVT format which should be formatted as
	================================
	WEBVTT
	
	1
	00:00:01,1 --> 00:00:05,000
	A line of text

	2
	00:01:15,1 --> 00:02:05,000
	A second line of text
	
	===============================

	Adapted from: http://www.delphiki.com/html5/playr
	*/
	mejs.TrackFormatParser = {
		// match start "chapter-" (or anythingelse)
		pattern_identifier: /^([a-zA-z]+-)?[0-9]+$/,
		pattern_timecode: /^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,

		split2: function (text, regex) {
			// normal version for compliant browsers
			// see below for IE fix
			return text.split(regex);
		},
		parse: function(trackText) {
			var 
				i = 0,
				lines = this.split2(trackText, /\r?\n/),
				entries = {text:[], times:[]},
				timecode,
				text;

			for(; i<lines.length; i++) {
				// check for the line number
				if (this.pattern_identifier.exec(lines[i])){
					// skip to the next line where the start --> end time code should be
					i++;
					timecode = this.pattern_timecode.exec(lines[i]);				
					
					if (timecode && i<lines.length){
						i++;
						// grab all the (possibly multi-line) text that follows
						text = lines[i];
						i++;
						while(lines[i] !== '' && i<lines.length){
							text = text + '\n' + lines[i];
							i++;
						}

						// Text is in a different array so I can use .join
						entries.text.push(text);
						entries.times.push(
						{
							start: mejs.Utility.timeCodeToSeconds(timecode[1]),
							stop: mejs.Utility.timeCodeToSeconds(timecode[3]),
							settings: timecode[5]
						});
					}
				}
			}

			return entries;
		}
	};
	
	// test for browsers with bad String.split method.
	if ('x\n\ny'.split(/\n/gi).length != 3) {
		// add super slow IE8 and below version
		mejs.TrackFormatParser.split2 = function(text, regex) {
			var 
				parts = [], 
				chunk = '',
				i;

			for (i=0; i<text.length; i++) {
				chunk += text.substring(i,i+1);
				if (regex.test(chunk)) {
					parts.push(chunk.replace(regex, ''));
					chunk = '';
				}
			}
			parts.push(chunk);
			return parts;
		}
	}	

})(mejs.$);

/*

* ContextMenu Plugin

* 

*

*/



(function($) {



$.extend(mejs.MepDefaults,

	contextMenuItems = [

		// demo of a fullscreen option

		{ 

			render: function(player) {

				

				// check for fullscreen plugin

				if (typeof player.enterFullScreen == 'undefined')

					return null;

			

				if (player.isFullScreen) {

					return "Turn off Fullscreen";

				} else {

					return "Go Fullscreen";

				}

			},

			click: function(player) {

				if (player.isFullScreen) {

					player.exitFullScreen();

				} else {

					player.enterFullScreen();

				}

			}

		}

		,

		// demo of a mute/unmute button

		{ 

			render: function(player) {

				if (player.media.muted) {

					return "Unmute";

				} else {

					return "Mute";

				}

			},

			click: function(player) {

				if (player.media.muted) {

					player.setMuted(false);

				} else {

					player.setMuted(true);

				}

			}

		},

		// separator

		{

			isSeparator: true

		}

		,

		// demo of simple download video

		{ 

			render: function(player) {

				return "Download Video";

			},

			click: function(player) {

				window.location.href = player.media.currentSrc;

			}

		}	

	]

);





	$.extend(MediaElementPlayer.prototype, {

		buildcontextmenu: function(player, controls, layers, media) {

			

			// create context menu

			player.contextMenu = $('<div class="mejs-contextmenu"></div>')

								.appendTo($('body'))

								.hide();

			

			// create events for showing context menu

			player.container.bind('contextmenu', function(e) {

				if (player.isContextMenuEnabled) {

					e.preventDefault();

					player.renderContextMenu(e.clientX-1, e.clientY-1);

					return false;

				}

			});

			player.container.bind('click', function() {

				player.contextMenu.hide();

			});	

			player.contextMenu.bind('mouseleave', function() {



				//console.log('context hover out');

				player.startContextMenuTimer();

				

			});		

		},

		

		isContextMenuEnabled: true,

		enableContextMenu: function() {

			this.isContextMenuEnabled = true;

		},

		disableContextMenu: function() {

			this.isContextMenuEnabled = false;

		},

		

		contextMenuTimeout: null,

		startContextMenuTimer: function() {

			//console.log('startContextMenuTimer');

			

			var t = this;

			

			t.killContextMenuTimer();

			

			t.contextMenuTimer = setTimeout(function() {

				t.hideContextMenu();

				t.killContextMenuTimer();

			}, 750);

		},

		killContextMenuTimer: function() {

			var timer = this.contextMenuTimer;

			

			//console.log('killContextMenuTimer', timer);

			

			if (timer != null) {				

				clearTimeout(timer);

				delete timer;

				timer = null;

			}

		},		

		

		hideContextMenu: function() {

			this.contextMenu.hide();

		},

		

		renderContextMenu: function(x,y) {

			

			// alway re-render the items so that things like "turn fullscreen on" and "turn fullscreen off" are always written correctly

			var t = this,

				html = '',

				items = t.options.contextMenuItems;

			

			for (var i=0, il=items.length; i<il; i++) {

				

				if (items[i].isSeparator) {

					html += '<div class="mejs-contextmenu-separator"></div>';

				} else {

				

					var rendered = items[i].render(t);

				

					// render can return null if the item doesn't need to be used at the moment

					if (rendered != null) {

						html += '<div class="mejs-contextmenu-item" data-itemindex="' + i + '" id="element-' + (Math.random()*1000000) + '">' + rendered + '</div>';

					}

				}

			}

			

			// position and show the context menu

			t.contextMenu

				.empty()

				.append($(html))

				.css({top:y, left:x})

				.show();

				

			// bind events

			t.contextMenu.find('.mejs-contextmenu-item').each(function() {

							

				// which one is this?

				var $dom = $(this),

					itemIndex = parseInt( $dom.data('itemindex'), 10 ),

					item = t.options.contextMenuItems[itemIndex];

				

				// bind extra functionality?

				if (typeof item.show != 'undefined')

					item.show( $dom , t);

				

				// bind click action

				$dom.click(function() {			

					// perform click action

					if (typeof item.click != 'undefined')

						item.click(t);

					

					// close

					t.contextMenu.hide();				

				});				

			});	

			

			// stop the controls from hiding

			setTimeout(function() {

				t.killControlsTimer('rev3');	

			}, 100);

						

		}

	});

	

})(mejs.$);


