text: (function(webshim, $){
  	"use strict";
  	if(!window.console){return;}
  	var mediaelement = webshim.mediaelement;
  	var hasFlash = swfmini.hasFlashPlayerVersion('10.0.3');
  	var hasNative = webshim.support.mediaelement;
  	var url = location.protocol+'//'+location.hostname;
  	var tests = {
  		urlInValid: {
  			level: 1,
  			test: (function(){
  				var reg = /^[a-z0-9\,\.\:\/\-_\;\?#\+\*\!\(\)\$\;\&\=\+]+$/i;
  				return function(src){
  					return (src.src && !reg.test(src.src));
  				};
  			})(),
  			srcTest: {poster: 1, srces: 1},
  			message: "URL has invalid characters. Remove any special characters and mutated vowels."
  		},
  		noHeaderTest: {
  			level: 5,
  			test: function(src){
  				return src.computedContainer != 'video/youtube' && !src.ajax && !src.httpError;
  			},
  			srcTest: {srces: 1},
  			message: "Could not run HTTP network tests (cross-domain) for all sources. Check manually."
  		},
  		hasNoTypeAttribute: {
  			level: 4,
  			test: function(src){
  				return !src.declaredType && !src.typeNotRequired;
  			},
  			srcTest: {srces: 1},
  			message: "The source element has no type attribute specified. Browser needs to download file before testing compatibility. Add a proper type attribute."
  		},
  		couldNotComputeTypeDeclaredTypeAbsent: {
  			level: 1,
  			test: function(src){
  				return (!src.computedContainer && !src.declaredType);
  			},
  			srcTest: {srces: 1},
  			message: "The source element has no type attribute specified and the extensions seems unknown. Add a proper type attribute."
  		},
  		httpError: {
  			level: 2.5,
  			test: function(src){
  
  				if(!src.ajax || src.decode.swf.success || src.decode.native.success){
  					return 'not testable';
  				} else {
  					return !!(src.httpError && !src.httpErrorText);
  				}
  			},
  			srcTest: {srces: 1},
  			message: "There was an unknown http error. Check source/URL."
  		},
  		fileEncoding: {
  			test: function(){
  				return 'This test does not test file encoding, framerate compatibility, moov index, encoding profiles. So there is room to fail!';
  			},
  			srcTest: {srces: 1}
  		},
  
  		explicitHttpError: {
  			level: 1,
  			test: function(src){
  				if(!src.ajax || src.decode.swf.success || src.decode.native.success){
  					return 'not testable';
  				} else {
  					return !!(src.httpErrorText);
  				}
  			},
  			srcTest: {srces: 1},
  			message: "There was a http error. Check source/URL."
  		},
  		charsetInContentType: {
  			level: 2.5,
  			test: function(src){
  				if(!src.ajax || src.httpError){
  					return 'not testable';
  				} else {
  					return src.headerType && (/charset=/i).test(src.headerType);
  				}
  			},
  			srcTest: {srces: 1},
  			message: "Content-Type header of media file sends charset. Remove charset information."
  		},
  		explicitTypeMix: {
  			level: 3,
  			test: function(src){
  				if(src.declaredContainer && src.headerType){
  					return src.headerType != src.declaredType;
  				} else {
  					return 'not testable';
  				}
  			},
  			srcTest: {srces: 1},
  			message: "Content-Type header and attribute type do not match. Set same and proper type value."
  		},
  		noContentType: {
  			level: 2.5,
  			test: function(src){
  				if(src.ajax && !src.httpError){
  					return !(src.headerType);
  				} else {
  					return 'not testable';
  				}
  			},
  			srcTest: {srces: 1},
  			message: "Content-Type header for media file is either empty or application/octet-stream."
  		},
  		noContentLength: {
  			level: 3,
  			test: function(src){
  				if(src.ajax && !src.httpError){
  					return !(src.headers['Content-Length']);
  				} else {
  					return 'not testable';
  				}
  			},
  			srcTest: {srces: 1},
  			message: "Content-Length header for media file does not send value."
  		},
  		noRange: {
  			level: 3,
  			test: function(src){
  				if(src.ajax && !src.httpError){
  					return !(src.headers['Accept-Ranges']);
  				} else {
  					return 'not testable';
  				}
  			},
  			srcTest: {srces: 1},
  			message: "Accept-Ranges header for media file does not send value. Make sure server supports Range requests in bytes"
  		},
  		explicitNoRange: {
  			level: 2.5,
  			test: function(src){
  				if(src.ajax && !src.httpError){
  					return (src.headers['Accept-Ranges'] == 'none');
  				} else {
  					return 'not testable';
  				}
  			},
  			srcTest: {srces: 1},
  			message: "Server does not support Range requests. Make sure server supports Range requests in bytes"
  		},
  		doubleEncoded: {
  			level: 1,
  			test: function(src){
  				if(src.ajax && !src.httpError){
  					return ((/[defalte|gzip]/i).test(src.headers['Content-Encoding']));
  				} else {
  					return 'not testable';
  				}
  			},
  			srcTest: {srces: 1},
  			message: "Content of media file is encoded with gzip/defalte. Make sure to not encode it. It's already encoded."
  		},
  		mediaAttachment: {
  			level: 1,
  			test: function(src){
  				if(src.ajax && !src.httpError){
  					return (/attach/i.test(src.headers['Content-Disposition']));
  				} else {
  					return 'not testable';
  				}
  			},
  			srcTest: {srces: 1},
  			message: "Content-Disposition header wants media file to be downloaded, but not to be played."
  		},
  		badTypeMix: {
  			level: 1,
  			test: function(src, infos){
  				var ret = false;
  
  				var isPlayableHtml, isPlayableHeader;
  				var htmlContainer = src.declaredContainer || src.computedContainer;
  				var headerContainer = src.headerContainer;
  				if(headerContainer && htmlContainer){
  					if(headerContainer != htmlContainer){
  						isPlayableHtml = mediaelement.swfMimeTypes.indexOf(htmlContainer) != -1;
  						isPlayableHeader = mediaelement.swfMimeTypes.indexOf(headerContainer) != -1;
  						if(isPlayableHtml != isPlayableHeader){
  							ret = true;
  						}
  
  						if(!ret && infos.element.canPlayType){
  
  							isPlayableHtml = !!infos.element.canPlayType(htmlContainer);
  							isPlayableHeader = !!infos.element.canPlayType(headerContainer);
  							if(isPlayableHtml != isPlayableHeader){
  								ret = true;
  							}
  						}
  					}
  				} else {
  					ret = 'not testable';
  				}
  
  				return ret;
  			},
  			srcTest: {srces: 1},
  			message: "Content-Type header and attribute type do not match and are quite different. Set same and proper type value."
  		},
  
  		typeMix: {
  			level: 2.5,
  			test: function(src, infos){
  				var ret = false;
  
  				var isPlayableComputed, isPlayableDeclared;
  				if(!src.headerContainer && src.declaredContainer && src.computedContainer && src.computedContainer != src.declaredContainer){
  					isPlayableComputed = mediaelement.swfMimeTypes.indexOf(src.computedContainer) != -1;
  					isPlayableDeclared = mediaelement.swfMimeTypes.indexOf(src.declaredContainer) != -1;
  					if(isPlayableComputed != isPlayableDeclared){
  						ret = true;
  					}
  
  					if(!ret && infos.element.canPlayType){
  
  						isPlayableComputed = !!infos.element.canPlayType(src.computedContainer);
  						isPlayableDeclared = !!infos.element.canPlayType(src.declaredContainer);
  						if(isPlayableComputed != isPlayableDeclared){
  							ret = true;
  						}
  					}
  				}
  
  				return ret;
  			},
  			srcTest: {srces: 1},
  			message: "Computed type and declared type are different. Needs manual check."
  		},
  		hasNoPlayableSrc: {
  			level: 1,
  			test: function(infos){
  				var hasPlayable = false;
  
  				$.each(infos.srces, function(i, src){
  					var pluginContainer = src.declaredContainer || src.computedContainer;
  					var nativeContainer = src.headerContainer || pluginContainer;
  
  					if(mediaelement.swfMimeTypes.indexOf(pluginContainer) != -1){
  						hasPlayable = true;
  						return false;
  					}
  
  					if(infos.element.canPlayType && infos.element.canPlayType(pluginContainer) && infos.element.canPlayType(nativeContainer)){
  						hasPlayable = true;
  						return false;
  					}
  				});
  
  				return !hasPlayable;
  			},
  			message: "Mediaelement has no source to be played in browser or by plugin. Use at least a video/mp4 source."
  		},
  		endJump: {
  			level: 2.5,
  			test: function(src){
  				return src.decode.swf.endJump || src.decode.native.endJump;
  			},
  			srcTest: {srces: 1},
  			message: 'src jumped to end too soon. Check negative timestamps: https://bugzilla.mozilla.org/show_bug.cgi?id=868797'
  		},
  		swfTimeout: {
  			level: 3,
  			test: function(src){
  				return src.decode.swf.timeout;
  			},
  			srcTest: {srces: 1},
  			message: 'Could not run decode tests. Maybe moovposition is on end?'
  		},
  		moovPosition: {
  			level: 2,
  			test: function(src){
  				if(src.decode.swf.moovposition){
  					return src.decode.swf.moovposition > 300;
  				}
  				return false;
  			},
  			srcTest: {srces: 1}
  		},
  		tabletDecode: {
  			level: 2,
  			test: function(infos){
  				var hasSwfSuccess = false;
  				var hasPlayableh264 = false;
  				if(hasFlash){
  					$.each(infos.srces, function(i, src){
  						var swfDecode = src.decode.swf;
  
  						if(('videocodecid' in swfDecode)){
  							hasSwfSuccess = true;
  						}
  						if(swfDecode.videocodecid != 'avc1' || swfDecode.avclevel > 31 || swfDecode.height * swfDecode.width > 921600){
  							return;
  						}
  						hasPlayableh264 = true;
  						return false;
  					});
  				}
  
  				return (!hasSwfSuccess) ?  false : !hasPlayableh264;
  			},
  			message: 'Not playable on more than 25% of smartphone and more than 15% of tablet devices. In case you want to support 75% of smartphone- and 90% of tablet devices you need to provide a source encoded with H.264, High Profile (HP), Level 3.1, up to 1280 * 720.'
  		},
  		allTabletDecode: {
  			level: 3,
  			test: function(infos){
  				var hasSwfSuccess = false;
  				var hasPlayableh264 = false;
  				if(hasFlash){
  					$.each(infos.srces, function(i, src){
  						var swfDecode = src.decode.swf;
  
  						if(('videocodecid' in swfDecode)){
  							hasSwfSuccess = true;
  						}
  						if(swfDecode.videocodecid != 'avc1' || swfDecode.avcprofile > 77 || swfDecode.avclevel > 31 || swfDecode.height * swfDecode.width > 921600){
  							return;
  						}
  						hasPlayableh264 = true;
  						return false;
  					});
  				}
  
  				return (!hasSwfSuccess) ?  false : !hasPlayableh264;
  			},
  			message: 'Not playable on more than 15% of smartphone and more than 5% of tablet devices. In case you want to support 90% of smartphone- and 99% of tablet devices you need to provide a source encoded with H.264, Main Profile (HP), Level 3.1, up to 1280 * 720.'
  		},
  		smartphoneDecode: {
  			level: 3.5,
  			test: function(infos){
  				var hasSwfSuccess = false;
  				var hasPlayableh264 = false;
  				if(hasFlash){
  
  					$.each(infos.srces, function(i, src){
  						var swfDecode = src.decode.swf;
  
  						if(('videocodecid' in swfDecode)){
  							hasSwfSuccess = true;
  						}
  						if(swfDecode.videocodecid != 'avc1' || swfDecode.avcprofile > 77 || swfDecode.avclevel > 30 || swfDecode.height * swfDecode.width > 345600){
  							return;
  						}
  						hasPlayableh264 = true;
  						return false;
  					});
  				}
  
  				return (!hasSwfSuccess) ?  false : !hasPlayableh264;
  			},
  			message: 'Not playable on more than 10% of smartphones: In case you want to support 90% of smartphone- and 99% of tablet devices you need to provide a source encoded with H.264, Main Profile (HP), Level 3.1, up to 720 * 404 / 640 * 480.'
  		},
  		notAllSmartphoneDecode: {
  			level: 4,
  			test: function(infos){
  				var hasSwfSuccess = false;
  				var hasPlayableh264 = false;
  
  				if(hasFlash){
  					$.each(infos.srces, function(i, src){
  						var swfDecode = src.decode.swf;
  						if(('videocodecid' in swfDecode)){
  							hasSwfSuccess = true;
  						}
  						if(swfDecode.videocodecid != 'avc1' || swfDecode.avcprofile > 66 || swfDecode.avclevel > 30 || swfDecode.height * swfDecode.width > 307200){
  							return;
  						}
  						hasPlayableh264 = true;
  						return false;
  					});
  				}
  
  
  				return (!hasSwfSuccess) ?  false : !hasPlayableh264;
  			},
  			message: 'Not playable on more than 1% of smartphones: In case you want to support 99% of all devices you need to provide a source encoded with H.264, Baseline Profile (BP), Level 3.0, up to 720 * 404 / 640 * 480. You might want to use multiple sources to satisfy quality and maximum device compatibility.'
  		},
  		needsFlashInstalled: {
  			level: 1,
  			test: function(infos){
  				var flashCanPlay = false;
  				var nativeCanPlay = false;
  				if(!hasFlash){
  					$.each(infos.srces, function(i, src){
  						var pluginContainer = src.declaredContainer || src.computedContainer;
  						var nativeContainer = src.headerContainer || pluginContainer;
  
  						if(mediaelement.swfMimeTypes.indexOf(pluginContainer) != -1){
  							flashCanPlay = true;
  						}
  
  						if(infos.element.canPlayType && (pluginContainer == 'video/youtube' || (infos.element.canPlayType(pluginContainer) && infos.element.canPlayType(nativeContainer)))){
  							nativeCanPlay = true;
  							return false;
  						}
  					});
  				}
  
  				return flashCanPlay && !nativeCanPlay;
  			},
  			message: "While media file could be played by flash plugin, Browser has no flash installed. Use at least a video/mp4 source and install flash. Or add additionally a video/webm file."
  		},
  		hasNoSwfPlayableSrc: {
  			level: 1,
  			test: function(infos){
  				var hasPlayable = false;
  
  				$.each(infos.srces, function(i, src){
  					var pluginContainer = src.declaredContainer || src.computedContainer;
  
  					if(mediaelement.swfMimeTypes.indexOf(pluginContainer) != -1){
  						hasPlayable = true;
  						return false;
  					}
  
  				});
  
  				return !hasPlayable;
  			},
  			message: "Mediaelement has no source to be played by fallback plugin. Use at least a video/mp4 source."
  		},
  		hasNoNativePlayableSrc: {
  			level: 4,
  			test: function(infos){
  				var hasPlayable = false;
  
  				if(infos.element.canPlayType){
  					$.each(infos.srces, function(i, src){
  						var pluginContainer = src.declaredContainer || src.computedContainer;
  						var nativeContainer = src.headerContainer || pluginContainer;
  
  						if(pluginContainer == 'video/youtube' || (infos.element.canPlayType(pluginContainer) && infos.element.canPlayType(nativeContainer))){
  							hasPlayable = true;
  							return false;
  						}
  
  					});
  				}
  
  				return !hasPlayable;
  			},
  			message: "Mediaelement has no source to be played native. Use at least a video/mp4 and a video/webm source."
  		},
  		misLeadingAttrMode: {
  			level: 2,
  			test: function(infos){
  				return (infos.srces.length > 1 && infos.srces[0].attrMode);
  			},
  			message: "Mediaelement has a src attribute and some source child elements. Only src attribute is used."
  		},
  		emptySrc: {
  			level: 2,
  			test: function(src){
  				return src.src && !src.attrSrc;
  			},
  			srcTest: {poster: 1, srces: 1},
  			message: "The src or poster attribute is an empty string, which is not allowed."
  		}
  	};
  
  	function runMediaTest(src, container, provider, infos){
  		var timeoutTimer, playTimer;
  		var promise = $.Deferred();
  		var $container = $('#wsmediatestcontainer');
  		var $element = $('<div />').css({width: 320, height: 120, float: 'left'});
  		var $media = $(document.createElement(infos.nodeName))
  			.attr({
  				src: src.src,
  				'data-type': container,
  				'controls': 'controls',
  				preload: 'none'
  			})
  		;
  		var resolvePromise = function(){
  			$media.pause();
  			setTimeout(function(){
  				$element.remove();
  				if(!$('video, audio', $container).length){
  					$container.remove();
  				}
  			}, 9);
  			setTimeout(function(){
  				promise.resolve();
  			}, 99);
  		};
  		var runEnded = function(e){
  			var duration = $media.prop('duration');
  			var currentTime = $media.prop('currentTime');
  
  			if(duration && duration > 5){
  				if(currentTime > 0 && currentTime < 5){
  					resolvePromise();
  				} else if(e.type == 'ended' || currentTime >= duration -1){
  					src.decode[provider].endJump = true;
  					resolvePromise();
  				}
  			} else {
  				resolvePromise();
  			}
  		};
  		var resolve = function(e){
  			clearTimeout(timeoutTimer);
  			if(e){
  				if(e.type == 'loadedmetadata'){
  
  					if(provider == 'swf'){
  						try {
  							src.decode[provider] = 	$media.getShadowElement().find('object, embed')[0].api_get('meta');
  						} catch(e){}
  					}
  					if(!src.decode[provider] || $.isEmptyObject(src.decode[provider])){
  						src.decode[provider] = {
  							duration: $media.prop('duration'),
  							height: $media.prop('videoHeight'),
  							width: $media.prop('videoWidth')
  							//todo at test for seekable
  							//,seekable: ($media.prop('seekable') || []).length
  						};
  					}
  					src.decode[provider].success = true;
  				} else {
  					src.decode[provider] = {
  						error: $media.prop('error'),
  						mediaError: $media.data('mediaerror'),
  						success: false
  					};
  				}
  
  			} else {
  				src.decode[provider] = {
  					success: false,
  					timeout: true
  				};
  			}
  			setTimeout(function(){
  				$media.play();
  			}, 9);
  			$media.on('ended timeupdate', runEnded);
  			clearTimeout(playTimer);
  
  			setTimeout(resolvePromise, 300);
  		};
  
  		if(!$container.length){
  			$container = $('<div id="wsmediatestcontainer" />')
  				.css({position: 'fixed', top: 0, left: 0, right: 0, padding: 10, zIndex: 9999999999})
  				.prependTo('body')
  			;
  		}
  
  		$media
  			.on('mediaerror loadedmetadata', resolve)
  			.appendTo($element)
  		;
  
  		if(provider == 'native'){
  			$media.on('error', resolve);
  		}
  
  		$element.appendTo($container);
  		timeoutTimer = setTimeout(resolve, 40000);
  		playTimer = setTimeout(function(){
  			$media.prop('muted', true);
  			$media.play();
  		}, 200);
  		$media.mediaLoad();
  		return promise;
  	}
  
  	function runDecodeTest(src, infos){
  		var promises = [];
  		var type = src.declaredContainer || src.computedContainer || src.headerContainer || '';
  		var preferFlash = webshim.cfg.mediaelement.preferFlash;
  		if(hasNative && infos.element.canPlayType(type)){
  			webshim.cfg.mediaelement.preferFlash = false;
  			promises.push(runMediaTest(src, type, 'native', infos));
  		} else {
  			src.decode.native = {success: false, notsupported: true};
  		}
  		if(hasFlash && !(/youtube|rtmp/i.test(type)) && mediaelement.swfMimeTypes.indexOf(type) != -1){
  			webshim.cfg.mediaelement.preferFlash = true;
  			promises.push(runMediaTest(src, type, 'swf', infos));
  		} else {
  			src.decode.swf = {success: false, notsupported: type != 'video/youtube'};
  		}
  		webshim.cfg.mediaelement.preferFlash = preferFlash;
  		return $.when.apply($, promises);
  	}
  
  	var runningDecodeTests = 0;
  	var decodeObj = {};
  	function runDeferredeDcodeTest(src, infos){
  
  		var promise = $.Deferred();
  		var onRun = function(){
  			if(!runningDecodeTests){
  				runningDecodeTests++;
  				$(decodeObj).off('finish', onRun);
  				runDecodeTest(src, infos).always(function(){
  					promise.resolve();
  					runningDecodeTests--;
  					$(decodeObj).trigger('finish');
  				});
  			}
  
  		};
  		if(runningDecodeTests){
  			$(decodeObj).on('finish', onRun);
  		} else {
  			onRun();
  		}
  
  		src.decode.promise = promise.promise();
  	}
  
  	function getSrcInfo(elem, infos){
  		var ajax;
  		var src = {
  			src: $.prop(elem, 'src'),
  			attrSrc: $.trim($.attr(elem, 'src')),
  			declaredType: $.attr(elem, 'type') || $(elem).attr('data-type') || '',
  			errors: {},
  			decode: {
  				native: {},
  				swf: {}
  			}
  		};
  		src.declaredContainer = src.declaredType.split(';')[0].trim();
  		try {
  			src.computedContainer = mediaelement.getTypeForSrc( src.src, infos.nodeName);
  		} catch(e){
  			src.computedContainer = '';
  		}
  
  		if(!src.src.indexOf(url)){
  
  			try {
  				src.headerType = '';
  				src.headers = {};
  				ajax = $.ajax({
  					url: src.src,
  					type: 'head',
  
  					success: function(){
  						src.headerType = ajax.getResponseHeader('Content-Type') || '';
  						if((/^\s*application\/octet\-stream\s*$/i).test(src.headerType)){
  							src.headerType = '';
  							src.errors.octetStream = 'octetStream';
  						}
  						src.headerContainer = $.trim(src.headerType.split(';')[0]);
  						['Location', 'Content-Type', 'Content-Length', 'Accept-Ranges', 'Content-Disposition', 'Content-Encoding'].forEach(function(name){
  							src.headers[name] = ajax.getResponseHeader(name) || '';
  						});
  
  					},
  					error: function(xhr, status, statusText){
  						src.httpError = status;
  						src.httpErrorText = statusText;
  					}
  				});
  				src.ajax = ajax;
  			} catch(e){}
  		} else {
  			src.cors = true;
  		}
  
  		runDeferredeDcodeTest(src, infos);
  
  		return src;
  	}
  
  	function resolveSrces(infos){
  		var src;
  		var srces = [];
  		var ajaxes = [];
  		var $sources = $('source', infos.element);
  		var promises = [];
  		var mainPromise = $.Deferred();
  		var i = 0;
  		var resolve = function(){
  			i++;
  			if(i > 1){
  				mainPromise.resolve();
  			}
  		};
  
  		if($.prop(infos.element, 'src')){
  			src = getSrcInfo(infos.element, infos);
  			src.attrMode = true;
  			src.typeNotRequired = true;
  			srces.push(src);
  		}
  
  		$sources.each(function(i){
  			var src = getSrcInfo(this, infos);
  			src.typeNotRequired = !!(i && i >= $sources.length - 1);
  
  			srces.push(src);
  
  			if(src.ajax){
  				ajaxes.push(src.ajax);
  			}
  			if(src.decode.promise){
  				promises.push(src.decode.promise);
  			}
  		});
  
  		infos.srces = srces;
  		$.when.apply($, promises).always(resolve);
  		$.when.apply($, ajaxes).done(resolve).fail(function(){
  			setTimeout(resolve, 200);
  		});
  
  		return mainPromise.promise();
  	}
  
  
  
  	function runTests(infos){
  
  		$.each(tests, function(name, obj){
  			var localMessage;
  			var failed = false;
  			var message = obj.message || name;
  			if(obj.srcTest){
  				if(obj.srcTest.poster){
  					localMessage = obj.test(infos.poster, infos);
  					if(localMessage){
  						if(typeof localMessage == 'string'){
  							infos.poster.errors[name] = localMessage;
  						} else {
  							infos.poster.errors[name] = message;
  							failed = true;
  						}
  					}
  				}
  
  				if(obj.srcTest.srces){
  					infos.srces.forEach(function(src){
  						localMessage = obj.test(src, infos);
  						if(localMessage){
  							if(typeof localMessage == 'string'){
  								src.errors[name] = localMessage;
  							} else {
  								src.errors[name] = message;
  								failed = true;
  							}
  						}
  					});
  
  				}
  			} else {
  				failed = obj.test(infos);
  			}
  
  			if(failed){
  				infos.errors.push({
  					message: message,
  					level: obj.level,
  					name: name
  				});
  			}
  		});
  
  		infos.errors.sort(function(a, b){
  			return a.level > b.level;
  		});
  		console.log('---- Media Test Start ----');
  		console.log('Testing results for mediaelement network + markup debugger. For detailed information expand the following object:', infos);
  		if(infos.errors.length){
  			if(infos.errors[0].level < 3){
  				console.log('Found '+ infos.errors.length + ' errors/warnings with at least 1 critical issue.');
  			} else if(infos.errors[0].level < 4) {
  				console.log('Found '+ infos.errors.length + ' errors/warnings.');
  			} else {
  				console.log('Found '+ infos.errors.length + ' warnings but no critical issue.');
  			}
  			infos.errors.forEach(function(error){
  				var type = 'log';
  				if(console.error && console.warn){
  					if(error.level < 3){
  						type = 'error';
  					} else if(error.level < 4){
  						type = 'warn';
  					}
  				}
  				console[type](error.message, 'priority level: '+ error.level, error.name);
  			});
  		} else {
  			console.log('Congratulations: No errors found for video.');
  		}
  		console.log('---- Media Test End ----');
  		console.log('----');
  	}
  
  	function getMediaInfo(elem){
  		var infos = {
  			element: elem,
  			nodeName: elem.nodeName.toLowerCase(),
  			errors: [],
  			poster: {
  				src: $.prop(elem, 'poster'),
  				attrSrc: $.trim($.attr(elem, 'poster')),
  				errors: {}
  			},
  			mediaError: $.prop(elem, 'error'),
  			wsError: $(elem).data('mediaerror')
  		};
  		var promise = resolveSrces(infos);
  		var initTests = function(){
  			runTests(infos);
  		};
  		promise.always(initTests);
  	}
  
  	var timedMediaInfo = function(i){
  		var elem = this;
  		setTimeout(function(){
  			getMediaInfo(elem);
  		}, i * 100);
  	};
  
  	console.log('Running mediaelement debugger. Only run these tests in development never in production. set webshim.setOptions("debug", false); to remove. Debugger only tests media on same domain and does not test all file encoding issues. So there is still room to fail!');
  
  
  	if(webshim.cfg.extendNative){
  		console.log('mediaelement debugger does not detect all problems with extendNative set to true. Please set webshim.setOptions("extendNative", false);');
  	}
  	webshim.addReady(function(context, $insertedElement){
  		$('video, audio', context)
  			.add($insertedElement.filter('video, audio'))
  			.each(timedMediaInfo)
  		;
  	});
  	webshim.mediaelement.getMediaInfo = getMediaInfo;
  })(webshim, webshim.$);
  