text: // 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;
  	},
  
  	unregisterPluginElement: function (id) {
  		delete this.pluginMediaElements[id];
  		delete this.htmlMediaElements[id];
  	},
  
  	// 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];
  
  		if(!pluginMediaElement){
              return;
          }
          
  		// 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);
  	}
  };
  
  /*
  Default options
  */
  mejs.MediaElementDefaults = {
  	// allows testing on HTML5, flash, silverlight
  	// auto: attempts to detect what the browser can do
  	// auto_plugin: prefer plugins and then attempt native HTML5
  	// 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,
  	// use plugin for browsers that have trouble with Basic Authentication on HTTPS sites
  	httpsBasicAuthSite: 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',
  	// streamer for RTMP streaming
  	flashStreamer: '',
  	// set to 'always' for CDN version
  	flashScriptAccess: 'sameDomain',	
  	// turns on the smoothing filter in Flash
  	enablePluginSmoothing: false,
  	// enabled pseudo-streaming (seek) on .mp4 files
  	enablePseudoStreaming: false,
  	// start query parameter sent to server for pseudo-streaming
  	pseudoStreamingStartQueryParam: 'start',
  	// 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 = {},
  			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 mejs.MediaElementDefaults) {
  			options[prop] = mejs.MediaElementDefaults[prop];
  		}
  		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,
  			media;
  			
  		// 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'));
  					media = n.getAttribute('media');
  
  					if (!media || !window.matchMedia || (window.matchMedia && window.matchMedia(media).matches)) {
  						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' : '';
  			};
  		}		
  		
  		// special case for Chromium to specify natively supported video codecs (i.e. WebM and Theora) 
  		if (mejs.MediaFeatures.isChromium) { 
  			htmlMediaElement.canPlayType = function(type) { 
  				return (type.match(/video\/(webm|ogv|ogg)/gi) !== null) ? 'maybe' : ''; 
  			}; 
  		}
  
  		// test for native playback first
  		if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'native')  && !(mejs.MediaFeatures.isBustedNativeHTTPS && options.httpsBasicAuthSite === true)) {
  						
  			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 (mediaFiles[i].type == "video/m3u8" || 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/, '') !== ''
  					// special case for m4a supported by detecting mp4 support
  					|| htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/m4a/,'mp4')).replace(/no/, '') !== '') {
  					result.method = 'native';
  					result.url = mediaFiles[i].url;
  					break;
  				}
  			}			
  			
  			if (result.method === 'native') {
  				if (result.url !== null) {
  					htmlMediaElement.src = result.url;
  				}
  			
  				// if `auto_plugin` mode, then cache the native result but try plugins.
  				if (options.mode !== 'auto_plugin') {
  					return result;
  				}
  			}
  		}
  
  		// if native playback didn't work, then test plugins
  		if (options.mode === 'auto' || options.mode === 'auto_plugin' || 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.toLowerCase() == pluginInfo.types[l].toLowerCase()) {
  									result.method = pluginName;
  									result.url = mediaFiles[i].url;
  									return result;
  								}
  							}
  						}
  					}
  				}
  			}
  		}
  		
  		// at this point, being in 'auto_plugin' mode implies that we tried plugins but failed.
  		// if we have native support then return that.
  		if (options.mode === 'auto_plugin' && result.method === 'native') {
  			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) {
  		// 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) {
  		url = url.split('?')[0];
  		var
  			ext = url.substring(url.lastIndexOf('.') + 1).toLowerCase(),
  			av = /(mp4|m4v|ogg|ogv|m3u8|webm|webmv|flv|wmv|mpeg|mov)/gi.test(ext) ? 'video/' : 'audio/';
  		return this.getTypeFromExtension(ext, av);
  	},
  	
  	getTypeFromExtension: function(ext, av) {
  		av = av || '';
  		
  		switch (ext) {
  			case 'mp4':
  			case 'm4v':
  			case 'm4a':
  			case 'f4v':
  			case 'f4a':
  				return av + 'mp4';
  			case 'flv':
  				return av + 'x-flv';
  			case 'webm':
  			case 'webma':
  			case 'webmv':	
  				return av + 'webm';
  			case 'ogg':
  			case 'oga':
  			case 'ogv':	
  				return av + 'ogg';
  			case 'm3u8':
  				return 'application/x-mpegurl';
  			case 'ts':
  				return av + 'mp2t';
  			default:
  				return av + ext;
  		}
  	},
  
  	createErrorMessage: function(playback, options, poster) {
  		var 
  			htmlMediaElement = playback.htmlMediaElement,
  			errorContainer = document.createElement('div'),
  			errorContent = options.customError;
  			
  		errorContainer.className = 'me-cannotplay';
  
  		try {
  			errorContainer.style.width = htmlMediaElement.width + 'px';
  			errorContainer.style.height = htmlMediaElement.height + 'px';
  		} catch (e) {}
  
  		if (!errorContent) {
  			errorContent = '<a href="' + playback.url + '">';
  
  			if (poster !== '') {
  				errorContent += '<img src="' + poster + '" width="100%" height="100%" alt="" />';
  			}
  
  			errorContent += '<span>' + mejs.i18n.t('Download File') + '</span></a>';
  		}
  
  		errorContainer.innerHTML = errorContent;
  
  		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;
  
  		// copy tagName from html media element
  		pluginMediaElement.tagName = htmlMediaElement.tagName
  
  		// copy attributes from html media element to plugin media element
  		for (var i = 0; i < htmlMediaElement.attributes.length; i++) {
  			var attribute = htmlMediaElement.attributes[i];
  			if (attribute.specified) {
  				pluginMediaElement.setAttribute(attribute.name, attribute.value);
  			}
  		}
  
  		// check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
  		node = htmlMediaElement.parentNode;
  
  		while (node !== null && node.tagName != null && node.tagName.toLowerCase() !== 'body' && 
  				node.parentNode != null && node.parentNode.tagName != null && node.parentNode.constructor != null && node.parentNode.constructor.name === "ShadowRoot") {
  			if (node.parentNode.tagName.toLowerCase() === 'p') {
  				node.parentNode.parentNode.insertBefore(node, node.parentNode);
  				break;
  			}
  			node = node.parentNode;
  		}
  
  		if (playback.isVideo) {
  			width = (options.pluginWidth > 0) ? options.pluginWidth : (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
  			height = (options.pluginHeight > 0) ? options.pluginHeight : (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,
  			'jsinitfunction=' + "mejs.MediaPluginBridge.initPlugin",
  			'jscallbackfunction=' + "mejs.MediaPluginBridge.fireEvent",
  			'isvideo=' + ((playback.isVideo) ? "true" : "false"),
  			'autoplay=' + ((autoplay) ? "true" : "false"),
  			'preload=' + preload,
  			'width=' + width,
  			'startvolume=' + options.startVolume,
  			'timerrate=' + options.timerRate,
  			'flashstreamer=' + options.flashStreamer,
  			'height=' + height,
  			'pseudostreamstart=' + options.pseudoStreamingStartQueryParam];
  
  		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 (options.enablePseudoStreaming) {
  			initVars.push('pseudostreaming=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 + '" class="mejs-shim">' +
  '<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 + '" class="mejs-shim">' +
  '<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="' + options.flashScriptAccess + '" />' +
  '<param name="allowFullScreen" value="true" />' +
  '<param name="scale" value="default" />' + 
  '</object>';
  
  				} else {
  
  					container.innerHTML =
  '<embed id="' + pluginid + '" name="' + pluginid + '" ' +
  'play="true" ' +
  'loop="false" ' +
  'quality="high" ' +
  'bgcolor="#000000" ' +
  'wmode="transparent" ' +
  'allowScriptAccess="' + options.flashScriptAccess + '" ' +
  '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 + '" ' +
  'scale="default"' + 
  'class="mejs-shim"></embed>';
  				}
  				break;
  			
  			case 'youtube':
  			
  				
  				var videoId;
  				// youtu.be url from share button
  				if (playback.url.lastIndexOf("youtu.be") != -1) {
  					videoId = playback.url.substr(playback.url.lastIndexOf('/')+1);
  					if (videoId.indexOf('?') != -1) {
  						videoId = videoId.substr(0, videoId.indexOf('?'));
  					}
  				}
  				else {
  					videoId = playback.url.substr(playback.url.lastIndexOf('=')+1);
  				}
  				youtubeSettings = {
  						container: container,
  						containerId: container.id,
  						pluginMediaElement: pluginMediaElement,
  						pluginId: pluginid,
  						videoId: videoId,
  						height: height,
  						width: width	
  					};				
  				
  				// favor iframe version of YouTube
  				if (window.postMessage) {
  					mejs.YouTubeApi.enqueueIframe(youtubeSettings);		
  				} else if (mejs.PluginDetector.hasPluginVersion('flash', [10,0,0]) ) {
  					mejs.YouTubeApi.createFlash(youtubeSettings, options);
  				}
  				
  				break;
  			
  			// DEMO Code. Does NOT work.
  			case 'vimeo':
  				var player_id = pluginid + "_player";
  				pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/')+1);
  				
  				container.innerHTML ='<iframe src="//player.vimeo.com/video/' + pluginMediaElement.vimeoid + '?api=1&portrait=0&byline=0&title=0&player_id=' + player_id + '" width="' + width +'" height="' + height +'" frameborder="0" class="mejs-shim" id="' + player_id + '" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
  				if (typeof($f) == 'function') { // froogaloop available
  					var player = $f(container.childNodes[0]);
  					
  					player.addEvent('ready', function() {
  						
  						player.playVideo = function() {
  							player.api( 'play' );
  						} 
  						player.stopVideo = function() {
  							player.api( 'unload' );
  						} 
  						player.pauseVideo = function() {
  							player.api( 'pause' );
  						} 
  						player.seekTo = function( seconds ) {
  							player.api( 'seekTo', seconds );
  						}
  						player.setVolume = function( volume ) {
  							player.api( 'setVolume', volume );
  						}
  						player.setMuted = function( muted ) {
  							if( muted ) {
  								player.lastVolume = player.api( 'getVolume' );
  								player.api( 'setVolume', 0 );
  							} else {
  								player.api( 'setVolume', player.lastVolume );
  								delete player.lastVolume;
  							}
  						}						
  
  						function createEvent(player, pluginMediaElement, eventName, e) {
  							var event = {
  								type: eventName,
  								target: pluginMediaElement
  							};
  							if (eventName == 'timeupdate') {
  								pluginMediaElement.currentTime = event.currentTime = e.seconds;
  								pluginMediaElement.duration = event.duration = e.duration;
  							}
  							pluginMediaElement.dispatchEvent(event);
  						}
  
  						player.addEvent('play', function() {
  							createEvent(player, pluginMediaElement, 'play');
  							createEvent(player, pluginMediaElement, 'playing');
  						});
  
  						player.addEvent('pause', function() {
  							createEvent(player, pluginMediaElement, 'pause');
  						});
  
  						player.addEvent('finish', function() {
  							createEvent(player, pluginMediaElement, 'ended');
  						});
  
  						player.addEvent('playProgress', function(e) {
  							createEvent(player, pluginMediaElement, 'timeupdate', e);
  						});
  
  						pluginMediaElement.pluginElement = container;
  						pluginMediaElement.pluginApi = player;
  
  						// init mejs
  						mejs.MediaPluginBridge.initPlugin(pluginid);
  					});
  				}
  				else {
  					console.warn("You need to include froogaloop for vimeo to work");
  				}
  				break;			
  		}
  		// hide original element
  		htmlMediaElement.style.display = 'none';
  		// prevent browser from autoplaying when using a plugin
  		htmlMediaElement.removeAttribute('autoplay');
  
  		// 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 = "//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,wmode:'transparent'},
  			events: {
  				'onReady': function() {
  					
  					// wrapper to match
  					player.setVideoSize = function(width, height) {
  						player.setSize(width, height);
  					}
  					
  					// hook up iframe object to MEjs
  					settings.pluginMediaElement.pluginApi = player;
  					settings.pluginMediaElement.pluginElement = document.getElementById(settings.containerId);
  					
  					// 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 event = {
  			type: eventName,
  			target: pluginMediaElement
  		};
  
  		if (player && player.getDuration) {
  			
  			// time 
  			pluginMediaElement.currentTime = event.currentTime = player.getCurrentTime();
  			pluginMediaElement.duration = event.duration = player.getDuration();
  			
  			// state
  			event.paused = pluginMediaElement.paused;
  			event.ended = pluginMediaElement.ended;			
  			
  			// sound
  			event.muted = player.isMuted();
  			event.volume = player.getVolume() / 100;
  			
  			// progress
  			event.bytesTotal = player.getVideoBytesTotal();
  			event.bufferedBytes = player.getVideoBytesLoaded();
  			
  			// fake the W3C buffered TimeRange
  			var bufferedTime = event.bufferedBytes / event.bytesTotal * event.duration;
  			
  			event.target.buffered = event.buffered = {
  				start: function(index) {
  					return 0;
  				},
  				end: function (index) {
  					return bufferedTime;
  				},
  				length: 1
  			};
  
  		}
  		
  		// send event up the chain
  		pluginMediaElement.dispatchEvent(event);
  	},	
  	
  	iFrameReady: function() {
  		
  		this.isLoaded = true;
  		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; " class="mejs-shim">' +
  				'<param name="allowScriptAccess" value="sameDomain">' +
  				'<param name="wmode" value="transparent">' +
  			'</object>';
  		*/
  
  		var specialIEContainer,
  			youtubeUrl = '//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 + '" class="mejs-shim">' +
  	'<param name="movie" value="' + youtubeUrl + '" />' +
  	'<param name="wmode" value="transparent" />' +
  	'<param name="allowScriptAccess" value="' + options.flashScriptAccess + '" />' +
  	'<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; " class="mejs-shim">' +
  				'<param name="allowScriptAccess" value="' + options.flashScriptAccess + '">' +
  				'<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);
  		
  		mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'canplay');
  	},
  	
  	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
  window.onYouTubePlayerAPIReady = function() {
  	mejs.YouTubeApi.iFrameReady();
  };
  // FLASH
  window.onYouTubePlayerReady = function(id) {
  	mejs.YouTubeApi.flashReady(id);
  };
  
  window.mejs = mejs;
  window.MediaElement = mejs.MediaElement;
  