PageSourceSearch

https://www.kicks99.net/wp-content/plugins/wpb-show-core/modules/jplayer/jquery.jplayer.js?v=7Aug24&ver=2.9.2

js kicks99.net collected 2026-09-26 20:14:20 UTC 121,334 bytes, 3,510 lines download raw bytes

vendor: 16,394 bytes, lines 1-497
1/*
2 * jPlayer Plugin for jQuery JavaScript Library
3 * http://www.jplayer.org
4 *
5 * Copyright (c) 2009 - 2014 Happyworm Ltd
6 * Licensed under the MIT license.
7 * http://opensource.org/licenses/MIT
8 *
9 * Author: Mark J Panaghiston
10 * Version: 2.9.2
11 * Date: 14th December 2014
12 */
13
14/* Support for Zepto 1.0 compiled with optional data module.
15 * For AMD or NODE/CommonJS support, you will need to manually switch the related 2 lines in the code below.
16 * Search terms: "jQuery Switch" and "Zepto Switch"
17 */
18
19(function (root, factory) {
20	if (typeof define === 'function' && define.amd) {
21		// AMD. Register as an anonymous module.
22		define(['jquery'], factory); // jQuery Switch
23		// define(['zepto'], factory); // Zepto Switch
24	} else if (typeof exports === 'object') {
25		// Node/CommonJS
26		factory(require('jquery')); // jQuery Switch
27		//factory(require('zepto')); // Zepto Switch
28	} else {
29		// Browser globals
30		if(root.jQuery) { // Use jQuery if available
31			factory(root.jQuery);
32		} else { // Otherwise, use Zepto
33			factory(root.Zepto);
34		}
35	}
36}(this, function ($, undefined) {
37
38	// Adapted from jquery.ui.widget.js (1.8.7): $.widget.bridge - Tweaked $.data(this,XYZ) to $(this).data(XYZ) for Zepto
39	$.fn.jPlayer = function( options ) {
40		var name = "jPlayer";
41		var isMethodCall = typeof options === "string",
42			args = Array.prototype.slice.call( arguments, 1 ),
43			returnValue = this;
44
45		// allow multiple hashes to be passed on init
46		options = !isMethodCall && args.length ?
47			$.extend.apply( null, [ true, options ].concat(args) ) :
48			options;
49
50		// prevent calls to internal methods
51		if ( isMethodCall && options.charAt( 0 ) === "_" ) {
52			return returnValue;
53		}
54
55		if ( isMethodCall ) {
56			this.each(function() {
57				var instance = $(this).data( name ),
58					methodValue = instance && $.isFunction( instance[options] ) ?
59						instance[ options ].apply( instance, args ) :
60						instance;
61				if ( methodValue !== instance && methodValue !== undefined ) {
62					returnValue = methodValue;
63					return false;
64				}
65			});
66		} else {
67			this.each(function() {
68				var instance = $(this).data( name );
69				if ( instance ) {
70					// instance.option( options || {} )._init(); // Orig jquery.ui.widget.js code: Not recommend for jPlayer. ie., Applying new options to an existing instance (via the jPlayer constructor) and performing the _init(). The _init() is what concerns me. It would leave a lot of event handlers acting on jPlayer instance and the interface.
71					instance.option( options || {} ); // The new constructor only changes the options. Changing options only has basic support atm.
72				} else {
73					$(this).data( name, new $.jPlayer( options, this ) );
74				}
75			});
76		}
77
78		return returnValue;
79	};
80
81	$.jPlayer = function( options, element ) {
82		// allow instantiation without initializing for simple inheritance
83		if ( arguments.length ) {
84			this.element = $(element);
85			this.options = $.extend(true, {},
86				this.options,
87				options
88			);
89			var self = this;
90			this.element.bind( "remove.jPlayer", function() {
91				self.destroy();
92			});
93			this._init();
94		}
95	};
96	// End of: (Adapted from jquery.ui.widget.js (1.8.7))
97
98	// Zepto is missing one of the animation methods.
99	if(typeof $.fn.stop !== 'function') {
100		$.fn.stop = function() {};
101	}
102
103	// Emulated HTML5 methods and properties
104	$.jPlayer.emulateMethods = "load play pause";
105	$.jPlayer.emulateStatus = "src readyState networkState currentTime duration paused ended playbackRate";
106	$.jPlayer.emulateOptions = "muted volume";
107
108	// Reserved event names generated by jPlayer that are not part of the HTML5 Media element spec
109	$.jPlayer.reservedEvent = "ready flashreset resize repeat error warning";
110
111	// Events generated by jPlayer
112	$.jPlayer.event = {};
113	$.each(
114		[
115			'ready',
116			'setmedia', // Fires when the media is set
117			'flashreset', // Similar to the ready event if the Flash solution is set to display:none and then shown again or if it's reloaded for another reason by the browser. For example, using CSS position:fixed on Firefox for the full screen feature.
118			'resize', // Occurs when the size changes through a full/restore screen operation or if the size/sizeFull options are changed.
119			'repeat', // Occurs when the repeat status changes. Usually through clicks on the repeat button of the interface.
120			'click', // Occurs when the user clicks on one of the following: poster image, html video, flash video.
121			'error', // Event error code in event.jPlayer.error.type. See $.jPlayer.error
122			'warning', // Event warning code in event.jPlayer.warning.type. See $.jPlayer.warning
123
124			// Other events match HTML5 spec.
125			'loadstart',
126			'progress',
127			'suspend',
128			'abort',
129			'emptied',
130			'stalled',
131			'play',
132			'pause',
133			'loadedmetadata',
134			'loadeddata',
135			'waiting',
136			'playing',
137			'canplay',
138			'canplaythrough',
139			'seeking',
140			'seeked',
141			'timeupdate',
142			'ended',
143			'ratechange',
144			'durationchange',
145			'volumechange'
146		],
147		function() {
148			$.jPlayer.event[ this ] = 'jPlayer_' + this;
149		}
150	);
151
152	$.jPlayer.htmlEvent = [ // These HTML events are bubbled through to the jPlayer event, without any internal action.
153		"loadstart",
154		// "progress", // jPlayer uses internally before bubbling.
155		// "suspend", // jPlayer uses internally before bubbling.
156		"abort",
157		// "error", // jPlayer uses internally before bubbling.
158		"emptied",
159		"stalled",
160		// "play", // jPlayer uses internally before bubbling.
161		// "pause", // jPlayer uses internally before bubbling.
162		"loadedmetadata",
163		// "loadeddata", // jPlayer uses internally before bubbling.
164		// "waiting", // jPlayer uses internally before bubbling.
165		// "playing", // jPlayer uses internally before bubbling.
166		"canplay",
167		"canplaythrough"
168		// "seeking", // jPlayer uses internally before bubbling.
169		// "seeked", // jPlayer uses internally before bubbling.
170		// "timeupdate", // jPlayer uses internally before bubbling.
171		// "ended", // jPlayer uses internally before bubbling.
172		// "ratechange" // jPlayer uses internally before bubbling.
173		// "durationchange" // jPlayer uses internally before bubbling.
174		// "volumechange" // jPlayer uses internally before bubbling.
175	];
176
177	$.jPlayer.pause = function() {
178		$.jPlayer.prototype.destroyRemoved();
179		$.each($.jPlayer.prototype.instances, function(i, element) {
180			if(element.data("jPlayer").status.srcSet) { // Check that media is set otherwise would cause error event.
181				element.jPlayer("pause");
182			}
183		});
184	};
185
186	// Default for jPlayer option.timeFormat
187	$.jPlayer.timeFormat = {
188		showHour: false,
189		showMin: true,
190		showSec: true,
191		padHour: false,
192		padMin: true,
193		padSec: true,
194		sepHour: ":",
195		sepMin: ":",
196		sepSec: ""
197	};
198	var ConvertTime = function() {
199		this.init();
200	};
201	ConvertTime.prototype = {
202		init: function() {
203			this.options = {
204				timeFormat: $.jPlayer.timeFormat
205			};
206		},
207		time: function(s) { // function used on jPlayer.prototype._convertTime to enable per instance options.
208			s = (s && typeof s === 'number') ? s : 0;
209
210			var myTime = new Date(s * 1000),
211				hour = myTime.getUTCHours(),
212				min = this.options.timeFormat.showHour ? myTime.getUTCMinutes() : myTime.getUTCMinutes() + hour * 60,
213				sec = this.options.timeFormat.showMin ? myTime.getUTCSeconds() : myTime.getUTCSeconds() + min * 60,
214				strHour = (this.options.timeFormat.padHour && hour < 10) ? "0" + hour : hour,
215				strMin = (this.options.timeFormat.padMin && min < 10) ? "0" + min : min,
216				strSec = (this.options.timeFormat.padSec && sec < 10) ? "0" + sec : sec,
217				strTime = "";
218
219			strTime += this.options.timeFormat.showHour ? strHour + this.options.timeFormat.sepHour : "";
220			strTime += this.options.timeFormat.showMin ? strMin + this.options.timeFormat.sepMin : "";
221			strTime += this.options.timeFormat.showSec ? strSec + this.options.timeFormat.sepSec : "";
222
223			return strTime;
224		}
225	};
226	var myConvertTime = new ConvertTime();
227	$.jPlayer.convertTime = function(s) {
228		return myConvertTime.time(s);
229	};
230
231	// Adapting jQuery 1.4.4 code for jQuery.browser. Required since jQuery 1.3.2 does not detect Chrome as webkit.
232	$.jPlayer.uaBrowser = function( userAgent ) {
233		var ua = userAgent.toLowerCase();
234
235		// Useragent RegExp
236		var rwebkit = /(webkit)[ \/]([\w.]+)/;
237		var ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/;
238		var rmsie = /(msie) ([\w.]+)/;
239		var rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/;
240
241		var match = rwebkit.exec( ua ) ||
242			ropera.exec( ua ) ||
243			rmsie.exec( ua ) ||
244			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
245			[];
246
247		return { browser: match[1] || "", version: match[2] || "0" };
248	};
249
250	// Platform sniffer for detecting mobile devices
251	$.jPlayer.uaPlatform = function( userAgent ) {
252		var ua = userAgent.toLowerCase();
253
254		// Useragent RegExp
255		var rplatform = /(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/;
256		var rtablet = /(ipad|playbook)/;
257		var randroid = /(android)/;
258		var rmobile = /(mobile)/;
259
260		var platform = rplatform.exec( ua ) || [];
261		var tablet = rtablet.exec( ua ) ||
262			!rmobile.exec( ua ) && randroid.exec( ua ) ||
263			[];
264
265		if(platform[1]) {
266			platform[1] = platform[1].replace(/\s/g, "_"); // Change whitespace to underscore. Enables dot notation.
267		}
268
269		return { platform: platform[1] || "", tablet: tablet[1] || "" };
270	};
271
272	$.jPlayer.browser = {
273	};
274	$.jPlayer.platform = {
275	};
276
277	var browserMatch = $.jPlayer.uaBrowser(navigator.userAgent);
278	if ( browserMatch.browser ) {
279		$.jPlayer.browser[ browserMatch.browser ] = true;
280		$.jPlayer.browser.version = browserMatch.version;
281	}
282	var platformMatch = $.jPlayer.uaPlatform(navigator.userAgent);
283	if ( platformMatch.platform ) {
284		$.jPlayer.platform[ platformMatch.platform ] = true;
285		$.jPlayer.platform.mobile = !platformMatch.tablet;
286		$.jPlayer.platform.tablet = !!platformMatch.tablet;
287	}
288
289	// Internet Explorer (IE) Browser Document Mode Sniffer. Based on code at:
290	// http://msdn.microsoft.com/en-us/library/cc288325%28v=vs.85%29.aspx#GetMode
291	$.jPlayer.getDocMode = function() {
292		var docMode;
293		if ($.jPlayer.browser.msie) {
294			if (document.documentMode) { // IE8 or later
295				docMode = document.documentMode;
296			} else { // IE 5-7
297				docMode = 5; // Assume quirks mode unless proven otherwise
298				if (document.compatMode) {
299					if (document.compatMode === "CSS1Compat") {
300						docMode = 7; // standards mode
301					}
302				}
303			}
304		}
305		return docMode;
306	};
307	$.jPlayer.browser.documentMode = $.jPlayer.getDocMode();
308
309	$.jPlayer.nativeFeatures = {
310		init: function() {
311
312			/* Fullscreen function naming influenced by W3C naming.
313			 * No support for: Mozilla Proposal: https://wiki.mozilla.org/Gecko:FullScreenAPI
314			 */
315
316			var d = document,
317				v = d.createElement('video'),
318				spec = {
319					// http://www.w3.org/TR/fullscreen/
320					w3c: [
321						'fullscreenEnabled',
322						'fullscreenElement',
323						'requestFullscreen',
324						'exitFullscreen',
325						'fullscreenchange',
326						'fullscreenerror'
327					],
328					// https://developer.mozilla.org/en-US/docs/DOM/Using_fullscreen_mode
329					moz: [
330						'mozFullScreenEnabled',
331						'mozFullScreenElement',
332						'mozRequestFullScreen',
333						'mozCancelFullScreen',
334						'mozfullscreenchange',
335						'mozfullscreenerror'
336					],
337					// http://developer.apple.com/library/safari/#documentation/WebKit/Reference/ElementClassRef/Element/Element.html
338					// http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/DocumentAdditionsReference/DocumentAdditions/DocumentAdditions.html
339					webkit: [
340						'',
341						'webkitCurrentFullScreenElement',
342						'webkitRequestFullScreen',
343						'webkitCancelFullScreen',
344						'webkitfullscreenchange',
345						''
346					],
347					// http://developer.apple.com/library/safari/#documentation/AudioVideo/Reference/HTMLVideoElementClassReference/HTMLVideoElement/HTMLVideoElement.html
348					// https://developer.apple.com/library/safari/samplecode/HTML5VideoEventFlow/Listings/events_js.html#//apple_ref/doc/uid/DTS40010085-events_js-DontLinkElementID_5
349					// Events: 'webkitbeginfullscreen' and 'webkitendfullscreen'
350					webkitVideo: [
351						'webkitSupportsFullscreen',
352						'webkitDisplayingFullscreen',
353						'webkitEnterFullscreen',
354						'webkitExitFullscreen',
355						'',
356						''
357					],
358					ms: [
359						'',
360						'msFullscreenElement',
361						'msRequestFullscreen',
362						'msExitFullscreen',
363						'MSFullscreenChange',
364						'MSFullscreenError'
365					]
366				},
367				specOrder = [
368					'w3c',
369					'moz',
370					'webkit',
371					'webkitVideo',
372					'ms'
373				],
374				fs, i, il;
375
376			this.fullscreen = fs = {
377				support: {
378					w3c: !!d[spec.w3c[0]],
379					moz: !!d[spec.moz[0]],
380					webkit: typeof d[spec.webkit[3]] === 'function',
381					webkitVideo: typeof v[spec.webkitVideo[2]] === 'function',
382					ms: typeof v[spec.ms[2]] === 'function'
383				},
384				used: {}
385			};
386
387			// Store the name of the spec being used and as a handy boolean.
388			for(i = 0, il = specOrder.length; i < il; i++) {
389				var n = specOrder[i];
390				if(fs.support[n]) {
391					fs.spec = n;
392					fs.used[n] = true;
393					break;
394				}
395			}
396
397			if(fs.spec) {
398				var s = spec[fs.spec];
399				fs.api = {
400					fullscreenEnabled: true,
401					fullscreenElement: function(elem) {
402						elem = elem ? elem : d; // Video element required for webkitVideo
403						return elem[s[1]];
404					},
405					requestFullscreen: function(elem) {
406						return elem[s[2]](); // Chrome and Opera want parameter (Element.ALLOW_KEYBOARD_INPUT) but Safari fails if flag used.
407					},
408					exitFullscreen: function(elem) {
409						elem = elem ? elem : d; // Video element required for webkitVideo
410						return elem[s[3]]();
411					}
412				};
413				fs.event = {
414					fullscreenchange: s[4],
415					fullscreenerror: s[5]
416				};
417			} else {
418				fs.api = {
419					fullscreenEnabled: false,
420					fullscreenElement: function() {
421						return null;
422					},
423					requestFullscreen: function() {},
424					exitFullscreen: function() {}
425				};
426				fs.event = {};
427			}
428		}
429	};
430	$.jPlayer.nativeFeatures.init();
431
432	// The keyboard control system.
433
434	// The current jPlayer instance in focus.
435	$.jPlayer.focus = null;
436
437	// The list of element node names to ignore with key controls.
438	$.jPlayer.keyIgnoreElementNames = "A INPUT TEXTAREA SELECT BUTTON";
439
440	// The function that deals with key presses.
441	var keyBindings = function(event) {
442		var f = $.jPlayer.focus,
443			ignoreKey;
444
445		// A jPlayer instance must be in focus. ie., keyEnabled and the last one played.
446		if(f) {
447			// What generated the key press?
448			$.each( $.jPlayer.keyIgnoreElementNames.split(/\s+/g), function(i, name) {
449				// The strings should already be uppercase.
450				if(event.target.nodeName.toUpperCase() === name.toUpperCase()) {
451					ignoreKey = true;
452					return false; // exit each.
453				}
454			});
455			if(!ignoreKey) {
456				// See if the key pressed matches any of the bindings.
457				$.each(f.options.keyBindings, function(action, binding) {
458					// The binding could be a null when the default has been disabled. ie., 1st clause in if()
459					if(
460						(binding && $.isFunction(binding.fn)) &&
461						((typeof binding.key === 'number' && event.which === binding.key) ||
462						(typeof binding.key === 'string' && event.key === binding.key))
463					) {
464						event.preventDefault(); // Key being used by jPlayer, so prevent default operation.
465						binding.fn(f);
466						return false; // exit each.
467					}
468				});
469			}
470		}
471	};
472
473	$.jPlayer.keys = function(en) {
474		var event = "keydown.jPlayer";
475		// Remove any binding, just in case enabled more than once.
476		$(document.documentElement).unbind(event);
477		if(en) {
478			$(document.documentElement).bind(event, keyBindings);
479		}
480	};
481
482	// Enable the global key control handler ready for any jPlayer instance with the keyEnabled option enabled.
483	$.jPlayer.keys(true);
484
485	$.jPlayer.prototype = {
486		count: 0, // Static Variable: Change it via prototype.
487		version: { // Static Object
488			script: "2.9.2",
489			needFlash: "2.9.0",
490			flash: "unknown"
491		},
492		options: { // Instanced in $.jPlayer() constructor
493			swfPath: "js", // Path to jquery.jplayer.swf. Can be relative, absolute or server root relative.
494			solution: "html, flash", // Valid solutions: html, flash, aurora. Order defines priority. 1st is highest,
495			supplied: "mp3", // Defines which formats jPlayer will try and support and the priority by the order. 1st is highest,
496			auroraFormats: "wav", // List the aurora.js codecs being loaded externally. Its core supports "wav". Specify format in jPlayer context. EG., The aac.js codec gives the "m4a" format.
497			
497
498			preload: 'none',  // HTML5 Spec values: none, metadata, auto.
499			// WPB-6193 -- default was 'metadata' and now added 'none'.
vendor: 30,797 bytes, lines 500-1341
500
501			volume: 0.8, // The volume. Number 0 to 1.
502			muted: false,
503			remainingDuration: false, // When true, the remaining time is shown in the duration GUI element.
504			toggleDuration: false, // When true, clicks on the duration toggle between the duration and remaining display.
505			captureDuration: true, // When true, clicks on the duration are captured and no longer propagate up the DOM.
506			playbackRate: 1,
507			defaultPlaybackRate: 1,
508			minPlaybackRate: 0.5,
509			maxPlaybackRate: 4,
510			wmode: "opaque", // Valid wmode: window, transparent, opaque, direct, gpu. 
511			backgroundColor: "#000000", // To define the jPlayer div and Flash background color.
512			cssSelectorAncestor: "#jp_container_1",
513			cssSelector: { // * denotes properties that should only be required when video media type required. _cssSelector() would require changes to enable splitting these into Audio and Video defaults.
514				videoPlay: ".jp-video-play", // *
515				play: ".jp-play",
516				pause: ".jp-pause",
517				stop: ".jp-stop",
518				seekBar: ".jp-seek-bar",
519				playBar: ".jp-play-bar",
520				mute: ".jp-mute",
521				unmute: ".jp-unmute",
522				volumeBar: ".jp-volume-bar",
523				volumeBarValue: ".jp-volume-bar-value",
524				volumeMax: ".jp-volume-max",
525				playbackRateBar: ".jp-playback-rate-bar",
526				playbackRateBarValue: ".jp-playback-rate-bar-value",
527				currentTime: ".jp-current-time",
528				duration: ".jp-duration",
529				title: ".jp-title",
530				fullScreen: ".jp-full-screen", // *
531				restoreScreen: ".jp-restore-screen", // *
532				repeat: ".jp-repeat",
533				repeatOff: ".jp-repeat-off",
534				gui: ".jp-gui", // The interface used with autohide feature.
535				noSolution: ".jp-no-solution" // For error feedback when jPlayer cannot find a solution.
536			},
537			stateClass: { // Classes added to the cssSelectorAncestor to indicate the state.
538				playing: "jp-state-playing",
539				seeking: "jp-state-seeking",
540				muted: "jp-state-muted",
541				looped: "jp-state-looped",
542				fullScreen: "jp-state-full-screen",
543				noVolume: "jp-state-no-volume"
544			},
545			useStateClassSkin: false, // A state class skin relies on the state classes to change the visual appearance. The single control toggles the effect, for example: play then pause, mute then unmute.
546			autoBlur: true, // GUI control handlers will drop focus after clicks.
547			smoothPlayBar: false, // Smooths the play bar transitions, which affects clicks and short media with big changes per second.
548			fullScreen: false, // Native Full Screen
549			fullWindow: false,
550			autohide: {
551				restored: false, // Controls the interface autohide feature.
552				full: true, // Controls the interface autohide feature.
553				fadeIn: 200, // Milliseconds. The period of the fadeIn anim.
554				fadeOut: 600, // Milliseconds. The period of the fadeOut anim.
555				hold: 1000 // Milliseconds. The period of the pause before autohide beings.
556			},
557			loop: false,
558			repeat: function(event) { // The default jPlayer repeat event handler
559				if(event.jPlayer.options.loop) {
560					$(this).unbind(".jPlayerRepeat").bind($.jPlayer.event.ended + ".jPlayer.jPlayerRepeat", function() {
561						$(this).jPlayer("play");
562					});
563				} else {
564					$(this).unbind(".jPlayerRepeat");
565				}
566			},
567			nativeVideoControls: {
568				// Works well on standard browsers.
569				// Phone and tablet browsers can have problems with the controls disappearing.
570			},
571			noFullWindow: {
572				msie: /msie [0-6]\./,
573				ipad: /ipad.*?os [0-4]\./,
574				iphone: /iphone/,
575				ipod: /ipod/,
576				android_pad: /android [0-3]\.(?!.*?mobile)/,
577				android_phone: /(?=.*android)(?!.*chrome)(?=.*mobile)/,
578				blackberry: /blackberry/,
579				windows_ce: /windows ce/,
580				iemobile: /iemobile/,
581				webos: /webos/
582			},
583			noVolume: {
584				ipad: /ipad/,
585				iphone: /iphone/,
586				ipod: /ipod/,
587				android_pad: /android(?!.*?mobile)/,
588				android_phone: /android.*?mobile/,
589				blackberry: /blackberry/,
590				windows_ce: /windows ce/,
591				iemobile: /iemobile/,
592				webos: /webos/,
593				playbook: /playbook/
594			},
595			timeFormat: {
596				// Specific time format for this instance. The supported options are defined in $.jPlayer.timeFormat
597				// For the undefined options we use the default from $.jPlayer.timeFormat
598			},
599			keyEnabled: false, // Enables keyboard controls.
600			audioFullScreen: false, // Enables keyboard controls to enter full screen with audio media.
601			keyBindings: { // The key control object, defining the key codes and the functions to execute.
602				// The parameter, f = $.jPlayer.focus, will be checked truethy before attempting to call any of these functions.
603				// Properties may be added to this object, in key/fn pairs, to enable other key controls. EG, for the playlist add-on.
604				play: {
605					key: 80, // p
606					fn: function(f) {
607						if(f.status.paused) {
608							f.play();
609						} else {
610							f.pause();
611						}
612					}
613				},
614				fullScreen: {
615					key: 70, // f
616					fn: function(f) {
617						if(f.status.video || f.options.audioFullScreen) {
618							f._setOption("fullScreen", !f.options.fullScreen);
619						}
620					}
621				},
622				muted: {
623					key: 77, // m
624					fn: function(f) {
625						f._muted(!f.options.muted);
626					}
627				},
628				volumeUp: {
629					key: 190, // .
630					fn: function(f) {
631						f.volume(f.options.volume + 0.1);
632					}
633				},
634				volumeDown: {
635					key: 188, // ,
636					fn: function(f) {
637						f.volume(f.options.volume - 0.1);
638					}
639				},
640				loop: {
641					key: 76, // l
642					fn: function(f) {
643						f._loop(!f.options.loop);
644					}
645				}
646			},
647			verticalVolume: false, // Calculate volume from the bottom of the volume bar. Default is from the left. Also volume affects either width or height.
648			verticalPlaybackRate: false,
649			globalVolume: false, // Set to make volume and muted changes affect all jPlayer instances with this option enabled
650			idPrefix: "jp", // Prefix for the ids of html elements created by jPlayer. For flash, this must not include characters: . - + * / \
651			noConflict: "jQuery",
652			emulateHtml: false, // Emulates the HTML5 Media element on the jPlayer element.
653			consoleAlerts: true, // Alerts are sent to the console.log() instead of alert().
654			errorAlerts: false,
655			warningAlerts: false
656		},
657		optionsAudio: {
658			size: {
659				width: "0px",
660				height: "0px",
661				cssClass: ""
662			},
663			sizeFull: {
664				width: "0px",
665				height: "0px",
666				cssClass: ""
667			}
668		},
669		optionsVideo: {
670			size: {
671				width: "480px",
672				height: "270px",
673				cssClass: "jp-video-270p"
674			},
675			sizeFull: {
676				width: "100%",
677				height: "100%",
678				cssClass: "jp-video-full"
679			}
680		},
681		instances: {}, // Static Object
682		status: { // Instanced in _init()
683			src: "",
684			media: {},
685			paused: true,
686			format: {},
687			formatType: "",
688			waitForPlay: true, // Same as waitForLoad except in case where preloading.
689			waitForLoad: true,
690			srcSet: false,
691			video: false, // True if playing a video
692			seekPercent: 0,
693			currentPercentRelative: 0,
694			currentPercentAbsolute: 0,
695			currentTime: 0,
696			duration: 0,
697			remaining: 0,
698			videoWidth: 0, // Intrinsic width of the video in pixels.
699			videoHeight: 0, // Intrinsic height of the video in pixels.
700			readyState: 0,
701			networkState: 0,
702			playbackRate: 1, // Warning - Now both an option and a status property
703			ended: 0
704
705/*		Persistant status properties created dynamically at _init():
706			width
707			height
708			cssClass
709			nativeVideoControls
710			noFullWindow
711			noVolume
712			playbackRateEnabled // Warning - Technically, we can have both Flash and HTML, so this might not be correct if the Flash is active. That is a niche case.
713*/
714		},
715
716		internal: { // Instanced in _init()
717			ready: false
718			// instance: undefined
719			// domNode: undefined
720			// htmlDlyCmdId: undefined
721			// autohideId: undefined
722			// mouse: undefined
723			// cmdsIgnored
724		},
725		solution: { // Static Object: Defines the solutions built in jPlayer.
726			html: true,
727			aurora: true,
728			flash: true
729		},
730		// 'MPEG-4 support' : canPlayType('video/mp4; codecs="mp4v.20.8"')
731		format: { // Static Object
732			mp3: {
733				codec: 'audio/mpeg',
734				flashCanPlay: true,
735				media: 'audio'
736			},
737			m4a: { // AAC / MP4
738				codec: 'audio/mp4; codecs="mp4a.40.2"',
739				flashCanPlay: true,
740				media: 'audio'
741			},
742			m3u8a: { // AAC / MP4 / Apple HLS
743				codec: 'application/vnd.apple.mpegurl; codecs="mp4a.40.2"',
744				flashCanPlay: false,
745				media: 'audio'
746			},
747			m3ua: { // M3U
748				codec: 'audio/mpegurl',
749				flashCanPlay: false,
750				media: 'audio'
751			},
752			oga: { // OGG
753				codec: 'audio/ogg; codecs="vorbis, opus"',
754				flashCanPlay: false,
755				media: 'audio'
756			},
757			flac: { // FLAC
758				codec: 'audio/x-flac',
759				flashCanPlay: false,
760				media: 'audio'
761			},
762			wav: { // PCM
763				codec: 'audio/wav; codecs="1"',
764				flashCanPlay: false,
765				media: 'audio'
766			},
767			webma: { // WEBM
768				codec: 'audio/webm; codecs="vorbis"',
769				flashCanPlay: false,
770				media: 'audio'
771			},
772			fla: { // FLV / F4A
773				codec: 'audio/x-flv',
774				flashCanPlay: true,
775				media: 'audio'
776			},
777			rtmpa: { // RTMP AUDIO
778				codec: 'audio/rtmp; codecs="rtmp"',
779				flashCanPlay: true,
780				media: 'audio'
781			},
782			m4v: { // H.264 / MP4
783				codec: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
784				flashCanPlay: true,
785				media: 'video'
786			},
787			m3u8v: { // H.264 / AAC / MP4 / Apple HLS
788				codec: 'application/vnd.apple.mpegurl; codecs="avc1.42E01E, mp4a.40.2"',
789				flashCanPlay: false,
790				media: 'video'
791			},
792			m3uv: { // M3U
793				codec: 'audio/mpegurl',
794				flashCanPlay: false,
795				media: 'video'
796			},
797			ogv: { // OGG
798				codec: 'video/ogg; codecs="theora, vorbis"',
799				flashCanPlay: false,
800				media: 'video'
801			},
802			webmv: { // WEBM
803				codec: 'video/webm; codecs="vorbis, vp8"',
804				flashCanPlay: false,
805				media: 'video'
806			},
807			flv: { // FLV / F4V
808				codec: 'video/x-flv',
809				flashCanPlay: true,
810				media: 'video'
811			},
812			rtmpv: { // RTMP VIDEO
813				codec: 'video/rtmp; codecs="rtmp"',
814				flashCanPlay: true,
815				media: 'video'
816			}
817		},
818		_init: function() {
819			var self = this;
820			
821			this.element.empty();
822			
823			this.status = $.extend({}, this.status); // Copy static to unique instance.
824			this.internal = $.extend({}, this.internal); // Copy static to unique instance.
825
826			// Initialize the time format
827			this.options.timeFormat = $.extend({}, $.jPlayer.timeFormat, this.options.timeFormat);
828
829			// On iOS, assume commands will be ignored before user initiates them.
830			this.internal.cmdsIgnored = $.jPlayer.platform.ipad || $.jPlayer.platform.iphone || $.jPlayer.platform.ipod;
831
832			this.internal.domNode = this.element.get(0);
833
834			// Add key bindings focus to 1st jPlayer instanced with key control enabled.
835			if(this.options.keyEnabled && !$.jPlayer.focus) {
836				$.jPlayer.focus = this;
837			}
838
839			// A fix for Android where older (2.3) and even some 4.x devices fail to work when changing the *audio* SRC and then playing immediately.
840			this.androidFix = {
841				setMedia: false, // True when media set
842				play: false, // True when a progress event will instruct the media to play
843				pause: false, // True when a progress event will instruct the media to pause at a time.
844				time: NaN // The play(time) parameter
845			};
846			if($.jPlayer.platform.android) {
847				this.options.preload = this.options.preload !== 'auto' ? 'metadata' : 'auto'; // Default to metadata, but allow auto.
848			}
849
850			this.formats = []; // Array based on supplied string option. Order defines priority.
851			this.solutions = []; // Array based on solution string option. Order defines priority.
852			this.require = {}; // Which media types are required: video, audio.
853			
854			this.htmlElement = {}; // DOM elements created by jPlayer
855			this.html = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
856			this.html.audio = {};
857			this.html.video = {};
858			this.aurora = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
859			this.aurora.formats = [];
860			this.aurora.properties = [];
861			this.flash = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
862			
863			this.css = {};
864			this.css.cs = {}; // Holds the css selector strings
865			this.css.jq = {}; // Holds jQuery selectors. ie., $(css.cs.method)
866
867			this.ancestorJq = []; // Holds jQuery selector of cssSelectorAncestor. Init would use $() instead of [], but it is only 1.4+
868
869			this.options.volume = this._limitValue(this.options.volume, 0, 1); // Limit volume value's bounds.
870
871			// Create the formats array, with prority based on the order of the supplied formats string
872			$.each(this.options.supplied.toLowerCase().split(","), function(index1, value1) {
873				var format = value1.replace(/^\s+|\s+$/g, ""); //trim
874				if(self.format[format]) { // Check format is valid.
875					var dupFound = false;
876					$.each(self.formats, function(index2, value2) { // Check for duplicates
877						if(format === value2) {
878							dupFound = true;
879							return false;
880						}
881					});
882					if(!dupFound) {
883						self.formats.push(format);
884					}
885				}
886			});
887
888			// Create the solutions array, with prority based on the order of the solution string
889			$.each(this.options.solution.toLowerCase().split(","), function(index1, value1) {
890				var solution = value1.replace(/^\s+|\s+$/g, ""); //trim
891				if(self.solution[solution]) { // Check solution is valid.
892					var dupFound = false;
893					$.each(self.solutions, function(index2, value2) { // Check for duplicates
894						if(solution === value2) {
895							dupFound = true;
896							return false;
897						}
898					});
899					if(!dupFound) {
900						self.solutions.push(solution);
901					}
902				}
903			});
904				
905			// Create Aurora.js formats array
906			$.each(this.options.auroraFormats.toLowerCase().split(","), function(index1, value1) {
907				var format = value1.replace(/^\s+|\s+$/g, ""); //trim
908				if(self.format[format]) { // Check format is valid.
909					var dupFound = false;
910					$.each(self.aurora.formats, function(index2, value2) { // Check for duplicates
911						if(format === value2) {
912							dupFound = true;
913							return false;
914						}
915					});
916					if(!dupFound) {
917						self.aurora.formats.push(format);
918					}
919				}
920			});
921
922			this.internal.instance = "jp_" + this.count;
923			this.instances[this.internal.instance] = this.element;
924
925			// Check the jPlayer div has an id and create one if required. Important for Flash to know the unique id for comms.
926			if(!this.element.attr("id")) {
927				this.element.attr("id", this.options.idPrefix + "_jplayer_" + this.count);
928			}
929
930			this.internal.self = $.extend({}, {
931				id: this.element.attr("id"),
932				jq: this.element
933			});
934			this.internal.audio = $.extend({}, {
935				id: this.options.idPrefix + "_audio_" + this.count,
936				jq: undefined
937			});
938			this.internal.video = $.extend({}, {
939				id: this.options.idPrefix + "_video_" + this.count,
940				jq: undefined
941			});
942			this.internal.flash = $.extend({}, {
943				id: this.options.idPrefix + "_flash_" + this.count,
944				jq: undefined,
945				swf: this.options.swfPath + (this.options.swfPath.toLowerCase().slice(-4) !== ".swf" ? (this.options.swfPath && this.options.swfPath.slice(-1) !== "/" ? "/" : "") + "jquery.jplayer.swf" : "")
946			});
947			this.internal.poster = $.extend({}, {
948				id: this.options.idPrefix + "_poster_" + this.count,
949				jq: undefined
950			});
951
952			// Register listeners defined in the constructor
953			$.each($.jPlayer.event, function(eventName,eventType) {
954				if(self.options[eventName] !== undefined) {
955					self.element.bind(eventType + ".jPlayer", self.options[eventName]); // With .jPlayer namespace.
956					self.options[eventName] = undefined; // Destroy the handler pointer copy on the options. Reason, events can be added/removed in other ways so this could be obsolete and misleading.
957				}
958			});
959
960			// Determine if we require solutions for audio, video or both media types.
961			this.require.audio = false;
962			this.require.video = false;
963			$.each(this.formats, function(priority, format) {
964				self.require[self.format[format].media] = true;
965			});
966
967			// Now required types are known, finish the options default settings.
968			if(this.require.video) {
969				this.options = $.extend(true, {},
970					this.optionsVideo,
971					this.options
972				);
973			} else {
974				this.options = $.extend(true, {},
975					this.optionsAudio,
976					this.options
977				);
978			}
979			this._setSize(); // update status and jPlayer element size
980
981			// Determine the status for Blocklisted options.
982			this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls);
983			this.status.noFullWindow = this._uaBlocklist(this.options.noFullWindow);
984			this.status.noVolume = this._uaBlocklist(this.options.noVolume);
985
986			// Create event handlers if native fullscreen is supported
987			if($.jPlayer.nativeFeatures.fullscreen.api.fullscreenEnabled) {
988				this._fullscreenAddEventListeners();
989			}
990
991			// The native controls are only for video and are disabled when audio is also used.
992			this._restrictNativeVideoControls();
993
994			// Create the poster image.
995			this.htmlElement.poster = document.createElement('img');
996			this.htmlElement.poster.id = this.internal.poster.id;
997			this.htmlElement.poster.onload = function() { // Note that this did not work on Firefox 3.6: poster.addEventListener("onload", function() {}, false); Did not investigate x-browser.
998				if(!self.status.video || self.status.waitForPlay) {
999					self.internal.poster.jq.show();
1000				}
1001			};
1002			this.element.append(this.htmlElement.poster);
1003			this.internal.poster.jq = $("#" + this.internal.poster.id);
1004			this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height});
1005			this.internal.poster.jq.hide();
1006			this.internal.poster.jq.bind("click.jPlayer", function() {
1007				self._trigger($.jPlayer.event.click);
1008			});
1009			
1010			// Generate the required media elements
1011			this.html.audio.available = false;
1012			if(this.require.audio) { // If a supplied format is audio
1013				this.htmlElement.audio = document.createElement('audio');
1014				this.htmlElement.audio.id = this.internal.audio.id;
1015				this.html.audio.available = !!this.htmlElement.audio.canPlayType && this._testCanPlayType(this.htmlElement.audio); // Test is for IE9 on Win Server 2008.
1016			}
1017			this.html.video.available = false;
1018			if(this.require.video) { // If a supplied format is video
1019				this.htmlElement.video = document.createElement('video');
1020				this.htmlElement.video.id = this.internal.video.id;
1021				this.html.video.available = !!this.htmlElement.video.canPlayType && this._testCanPlayType(this.htmlElement.video); // Test is for IE9 on Win Server 2008.
1022			}
1023
1024			this.flash.available = this._checkForFlash(10.1);
1025
1026			this.html.canPlay = {};
1027			this.aurora.canPlay = {};
1028			this.flash.canPlay = {};
1029			$.each(this.formats, function(priority, format) {
1030				self.html.canPlay[format] = self.html[self.format[format].media].available && "" !== self.htmlElement[self.format[format].media].canPlayType(self.format[format].codec);
1031				self.aurora.canPlay[format] = ($.inArray(format, self.aurora.formats) > -1);
1032				self.flash.canPlay[format] = self.format[format].flashCanPlay && self.flash.available;
1033			});
1034			this.html.desired = false;
1035			this.aurora.desired = false;
1036			this.flash.desired = false;
1037			$.each(this.solutions, function(solutionPriority, solution) {
1038				if(solutionPriority === 0) {
1039					self[solution].desired = true;
1040				} else {
1041					var audioCanPlay = false;
1042					var videoCanPlay = false;
1043					$.each(self.formats, function(formatPriority, format) {
1044						if(self[self.solutions[0]].canPlay[format]) { // The other solution can play
1045							if(self.format[format].media === 'video') {
1046								videoCanPlay = true;
1047							} else {
1048								audioCanPlay = true;
1049							}
1050						}
1051					});
1052					self[solution].desired = (self.require.audio && !audioCanPlay) || (self.require.video && !videoCanPlay);
1053				}
1054			});
1055			// This is what jPlayer will support, based on solution and supplied.
1056			this.html.support = {};
1057			this.aurora.support = {};
1058			this.flash.support = {};
1059			$.each(this.formats, function(priority, format) {
1060				self.html.support[format] = self.html.canPlay[format] && self.html.desired;
1061				self.aurora.support[format] = self.aurora.canPlay[format] && self.aurora.desired;
1062				self.flash.support[format] = self.flash.canPlay[format] && self.flash.desired;
1063			});
1064			// If jPlayer is supporting any format in a solution, then the solution is used.
1065			this.html.used = false;
1066			this.aurora.used = false;
1067			this.flash.used = false;
1068			$.each(this.solutions, function(solutionPriority, solution) {
1069				$.each(self.formats, function(formatPriority, format) {
1070					if(self[solution].support[format]) {
1071						self[solution].used = true;
1072						return false;
1073					}
1074				});
1075			});
1076
1077			// Init solution active state and the event gates to false.
1078			this._resetActive();
1079			this._resetGate();
1080
1081			// Set up the css selectors for the control and feedback entities.
1082			this._cssSelectorAncestor(this.options.cssSelectorAncestor);
1083			
1084			// If neither html nor aurora nor flash are being used by this browser, then media playback is not possible. Trigger an error event.
1085			if(!(this.html.used || this.aurora.used || this.flash.used)) {
1086				this._error( {
1087					type: $.jPlayer.error.NO_SOLUTION, 
1088					context: "{solution:'" + this.options.solution + "', supplied:'" + this.options.supplied + "'}",
1089					message: $.jPlayer.errorMsg.NO_SOLUTION,
1090					hint: $.jPlayer.errorHint.NO_SOLUTION
1091				});
1092				if(this.css.jq.noSolution.length) {
1093					this.css.jq.noSolution.show();
1094				}
1095			} else {
1096				if(this.css.jq.noSolution.length) {
1097					this.css.jq.noSolution.hide();
1098				}
1099			}
1100
1101			// Add the flash solution if it is being used.
1102			if(this.flash.used) {
1103				var htmlObj,
1104				flashVars = 'jQuery=' + encodeURI(this.options.noConflict) + '&id=' + encodeURI(this.internal.self.id) + '&vol=' + this.options.volume + '&muted=' + this.options.muted;
1105
1106				// Code influenced by SWFObject 2.2: http://code.google.com/p/swfobject/
1107				// Non IE browsers have an initial Flash size of 1 by 1 otherwise the wmode affected the Flash ready event. 
1108
1109				if($.jPlayer.browser.msie && (Number($.jPlayer.browser.version) < 9 || $.jPlayer.browser.documentMode < 9)) {
1110					var objStr = '<object id="' + this.internal.flash.id + '" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="0" height="0" tabindex="-1"></object>';
1111
1112					var paramStr = [
1113						'<param name="movie" value="' + this.internal.flash.swf + '" />',
1114						'<param name="FlashVars" value="' + flashVars + '" />',
1115						'<param name="allowScriptAccess" value="always" />',
1116						'<param name="bgcolor" value="' + this.options.backgroundColor + '" />',
1117						'<param name="wmode" value="' + this.options.wmode + '" />'
1118					];
1119
1120					htmlObj = document.createElement(objStr);
1121					for(var i=0; i < paramStr.length; i++) {
1122						htmlObj.appendChild(document.createElement(paramStr[i]));
1123					}
1124				} else {
1125					var createParam = function(el, n, v) {
1126						var p = document.createElement("param");
1127						p.setAttribute("name", n);	
1128						p.setAttribute("value", v);
1129						el.appendChild(p);
1130					};
1131
1132					htmlObj = document.createElement("object");
1133					htmlObj.setAttribute("id", this.internal.flash.id);
1134					htmlObj.setAttribute("name", this.internal.flash.id);
1135					htmlObj.setAttribute("data", this.internal.flash.swf);
1136					htmlObj.setAttribute("type", "application/x-shockwave-flash");
1137					htmlObj.setAttribute("width", "1"); // Non-zero
1138					htmlObj.setAttribute("height", "1"); // Non-zero
1139					htmlObj.setAttribute("tabindex", "-1");
1140					createParam(htmlObj, "flashvars", flashVars);
1141					createParam(htmlObj, "allowscriptaccess", "always");
1142					createParam(htmlObj, "bgcolor", this.options.backgroundColor);
1143					createParam(htmlObj, "wmode", this.options.wmode);
1144				}
1145
1146				this.element.append(htmlObj);
1147				this.internal.flash.jq = $(htmlObj);
1148			}
1149
1150			// Setup playbackRate ability before using _addHtmlEventListeners()
1151			if(this.html.used && !this.flash.used) { // If only HTML
1152				// Using the audio element capabilities for playbackRate. ie., Assuming video element is the same.
1153				this.status.playbackRateEnabled = this._testPlaybackRate('audio');
1154			} else {
1155				this.status.playbackRateEnabled = false;
1156			}
1157
1158			this._updatePlaybackRate();
1159
1160			// Add the HTML solution if being used.
1161			if(this.html.used) {
1162
1163				// The HTML Audio handlers
1164				if(this.html.audio.available) {
1165					this._addHtmlEventListeners(this.htmlElement.audio, this.html.audio);
1166					this.element.append(this.htmlElement.audio);
1167					this.internal.audio.jq = $("#" + this.internal.audio.id);
1168				}
1169
1170				// The HTML Video handlers
1171				if(this.html.video.available) {
1172					this._addHtmlEventListeners(this.htmlElement.video, this.html.video);
1173					this.element.append(this.htmlElement.video);
1174					this.internal.video.jq = $("#" + this.internal.video.id);
1175					if(this.status.nativeVideoControls) {
1176						this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
1177					} else {
1178						this.internal.video.jq.css({'width':'0px', 'height':'0px'}); // Using size 0x0 since a .hide() causes issues in iOS
1179					}
1180					this.internal.video.jq.bind("click.jPlayer", function() {
1181						self._trigger($.jPlayer.event.click);
1182					});
1183				}
1184			}
1185			
1186			// Add the Aurora.js solution if being used.
1187			if(this.aurora.used) {
1188				// Aurora.js player need to be created for each media, see setMedia function.
1189			}
1190
1191			// Create the bridge that emulates the HTML Media element on the jPlayer DIV
1192			if( this.options.emulateHtml ) {
1193				this._emulateHtmlBridge();
1194			}
1195
1196			if((this.html.used || this.aurora.used) && !this.flash.used) { // If only HTML, then emulate flash ready() call after 100ms.
1197				setTimeout( function() {
1198					self.internal.ready = true;
1199					self.version.flash = "n/a";
1200					self._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option.
1201					self._trigger($.jPlayer.event.ready);
1202				}, 100);
1203			}
1204
1205			// Initialize the interface components with the options.
1206			this._updateNativeVideoControls();
1207			// The other controls are now setup in _cssSelectorAncestor()
1208			if(this.css.jq.videoPlay.length) {
1209				this.css.jq.videoPlay.hide();
1210			}
1211
1212			$.jPlayer.prototype.count++; // Change static variable via prototype.
1213		},
1214		destroy: function() {
1215			// MJP: The background change remains. Would need to store the original to restore it correctly.
1216			// MJP: The jPlayer element's size change remains.
1217
1218			// Clear the media to reset the GUI and stop any downloads. Streams on some browsers had persited. (Chrome)
1219			this.clearMedia();
1220			// Remove the size/sizeFull cssClass from the cssSelectorAncestor
1221			this._removeUiClass();
1222			// Remove the times from the GUI
1223			if(this.css.jq.currentTime.length) {
1224				this.css.jq.currentTime.text("");
1225			}
1226			if(this.css.jq.duration.length) {
1227				this.css.jq.duration.text("");
1228			}
1229			// Remove any bindings from the interface controls.
1230			$.each(this.css.jq, function(fn, jq) {
1231				// Check selector is valid before trying to execute method.
1232				if(jq.length) {
1233					jq.unbind(".jPlayer");
1234				}
1235			});
1236			// Remove the click handlers for $.jPlayer.event.click
1237			this.internal.poster.jq.unbind(".jPlayer");
1238			if(this.internal.video.jq) {
1239				this.internal.video.jq.unbind(".jPlayer");
1240			}
1241			// Remove the fullscreen event handlers
1242			this._fullscreenRemoveEventListeners();
1243			// Remove key bindings
1244			if(this === $.jPlayer.focus) {
1245				$.jPlayer.focus = null;
1246			}
1247			// Destroy the HTML bridge.
1248			if(this.options.emulateHtml) {
1249				this._destroyHtmlBridge();
1250			}
1251			this.element.removeData("jPlayer"); // Remove jPlayer data
1252			this.element.unbind(".jPlayer"); // Remove all event handlers created by the jPlayer constructor
1253			this.element.empty(); // Remove the inserted child elements
1254			
1255			delete this.instances[this.internal.instance]; // Clear the instance on the static instance object
1256		},
1257		destroyRemoved: function() { // Destroy any instances that have gone away.
1258			var self = this;
1259			$.each(this.instances, function(i, element) {
1260				if(self.element !== element) { // Do not destroy this instance.
1261					if(!element.data("jPlayer")) { // Check that element is a real jPlayer.
1262						element.jPlayer("destroy");
1263						delete self.instances[i];
1264					}
1265				}
1266			});
1267		},
1268		enable: function() { // Plan to implement
1269			// options.disabled = false
1270		},
1271		disable: function () { // Plan to implement
1272			// options.disabled = true
1273		},
1274		_testCanPlayType: function(elem) {
1275			// IE9 on Win Server 2008 did not implement canPlayType(), but it has the property.
1276			try {
1277				elem.canPlayType(this.format.mp3.codec); // The type is irrelevant.
1278				return true;
1279			} catch(err) {
1280				return false;
1281			}
1282		},
1283		_testPlaybackRate: function(type) {
1284			// type: String 'audio' or 'video'
1285			var el, rate = 0.5;
1286			type = typeof type === 'string' ? type : 'audio';
1287			el = document.createElement(type);
1288			// Wrapping in a try/catch, just in case older HTML5 browsers throw and error.
1289			try {
1290				if('playbackRate' in el) {
1291					el.playbackRate = rate;
1292					return el.playbackRate === rate;
1293				} else {
1294					return false;
1295				}
1296			} catch(err) {
1297				return false;
1298			}
1299		},
1300		_uaBlocklist: function(list) {
1301			// list : object with properties that are all regular expressions. Property names are irrelevant.
1302			// Returns true if the user agent is matched in list.
1303			var	ua = navigator.userAgent.toLowerCase(),
1304				block = false;
1305
1306			$.each(list, function(p, re) {
1307				if(re && re.test(ua)) {
1308					block = true;
1309					return false; // exit $.each.
1310				}
1311			});
1312			return block;
1313		},
1314		_restrictNativeVideoControls: function() {
1315			// Fallback to noFullWindow when nativeVideoControls is true and audio media is being used. Affects when both media types are used.
1316			if(this.require.audio) {
1317				if(this.status.nativeVideoControls) {
1318					this.status.nativeVideoControls = false;
1319					this.status.noFullWindow = true;
1320				}
1321			}
1322		},
1323		_updateNativeVideoControls: function() {
1324			if(this.html.video.available && this.html.used) {
1325				// Turn the HTML Video controls on/off
1326				this.htmlElement.video.controls = this.status.nativeVideoControls;
1327				// Show/hide the jPlayer GUI.
1328				this._updateAutohide();
1329				// For when option changed. The poster image is not updated, as it is dealt with in setMedia(). Acceptable degradation since seriously doubt these options will change on the fly. Can again review later.
1330				if(this.status.nativeVideoControls && this.require.video) {
1331					this.internal.poster.jq.hide();
1332					this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
1333				} else if(this.status.waitForPlay && this.status.video) {
1334					this.internal.poster.jq.show();
1335					this.internal.video.jq.css({'width': '0px', 'height': '0px'});
1336				}
1337			}
1338		},
1339		_addHtmlEventListeners: function(mediaElement, entity) {
1340			var self = this;
1341			
1341// from here it will add preload to audio tag through jplayer.
vendor: 73,952 bytes, lines 1341-3510
1341
1342			mediaElement.preload = this.options.preload;
1343			mediaElement.muted = this.options.muted;
1344			mediaElement.volume = this.options.volume;
1345
1346			if(this.status.playbackRateEnabled) {
1347				mediaElement.defaultPlaybackRate = this.options.defaultPlaybackRate;
1348				mediaElement.playbackRate = this.options.playbackRate;
1349			}
1350
1351			// Create the event listeners
1352			// Only want the active entity to affect jPlayer and bubble events.
1353			// Using entity.gate so that object is referenced and gate property always current
1354			
1355			mediaElement.addEventListener("progress", function() {
1356				if(entity.gate) {
1357					if(self.internal.cmdsIgnored && this.readyState > 0) { // Detect iOS executed the command
1358						self.internal.cmdsIgnored = false;
1359					}
1360					self._getHtmlStatus(mediaElement);
1361					self._updateInterface();
1362					self._trigger($.jPlayer.event.progress);
1363				}
1364			}, false);
1365			mediaElement.addEventListener("loadeddata", function() {
1366				if(entity.gate) {
1367					self.androidFix.setMedia = false; // Disable the fix after the first progress event.
1368					if(self.androidFix.play) { // Play Android audio - performing the fix.
1369						self.androidFix.play = false;
1370						self.play(self.androidFix.time);
1371					}
1372					if(self.androidFix.pause) { // Pause Android audio at time - performing the fix.
1373						self.androidFix.pause = false;
1374						self.pause(self.androidFix.time);
1375					}
1376					self._trigger($.jPlayer.event.loadeddata);
1377				}
1378			}, false);
1379			mediaElement.addEventListener("timeupdate", function() {
1380				if(entity.gate) {
1381					self._getHtmlStatus(mediaElement);
1382					self._updateInterface();
1383					self._trigger($.jPlayer.event.timeupdate);
1384				}
1385			}, false);
1386			mediaElement.addEventListener("durationchange", function() {
1387				if(entity.gate) {
1388					self._getHtmlStatus(mediaElement);
1389					self._updateInterface();
1390					self._trigger($.jPlayer.event.durationchange);
1391				}
1392			}, false);
1393			mediaElement.addEventListener("play", function() {
1394				if(entity.gate) {
1395					self._updateButtons(true);
1396					self._html_checkWaitForPlay(); // So the native controls update this variable and puts the hidden interface in the correct state. Affects toggling native controls.
1397					self._trigger($.jPlayer.event.play);
1398				}
1399			}, false);
1400			mediaElement.addEventListener("playing", function() {
1401				if(entity.gate) {
1402					self._updateButtons(true);
1403					self._seeked();
1404					self._trigger($.jPlayer.event.playing);
1405				}
1406			}, false);
1407			mediaElement.addEventListener("pause", function() {
1408				if(entity.gate) {
1409					self._updateButtons(false);
1410					self._trigger($.jPlayer.event.pause);
1411				}
1412			}, false);
1413			mediaElement.addEventListener("waiting", function() {
1414				if(entity.gate) {
1415					self._seeking();
1416					self._trigger($.jPlayer.event.waiting);
1417				}
1418			}, false);
1419			mediaElement.addEventListener("seeking", function() {
1420				if(entity.gate) {
1421					self._seeking();
1422					self._trigger($.jPlayer.event.seeking);
1423				}
1424			}, false);
1425			mediaElement.addEventListener("seeked", function() {
1426				if(entity.gate) {
1427					self._seeked();
1428					self._trigger($.jPlayer.event.seeked);
1429				}
1430			}, false);
1431			mediaElement.addEventListener("volumechange", function() {
1432				if(entity.gate) {
1433					// Read the values back from the element as the Blackberry PlayBook shares the volume with the physical buttons master volume control.
1434					// However, when tested 6th July 2011, those buttons do not generate an event. The physical play/pause button does though.
1435					self.options.volume = mediaElement.volume;
1436					self.options.muted = mediaElement.muted;
1437					self._updateMute();
1438					self._updateVolume();
1439					self._trigger($.jPlayer.event.volumechange);
1440				}
1441			}, false);
1442			mediaElement.addEventListener("ratechange", function() {
1443				if(entity.gate) {
1444					self.options.defaultPlaybackRate = mediaElement.defaultPlaybackRate;
1445					self.options.playbackRate = mediaElement.playbackRate;
1446					self._updatePlaybackRate();
1447					self._trigger($.jPlayer.event.ratechange);
1448				}
1449			}, false);
1450			mediaElement.addEventListener("suspend", function() { // Seems to be the only way of capturing that the iOS4 browser did not actually play the media from the page code. ie., It needs a user gesture.
1451				if(entity.gate) {
1452					self._seeked();
1453					self._trigger($.jPlayer.event.suspend);
1454				}
1455			}, false);
1456			mediaElement.addEventListener("ended", function() {
1457				if(entity.gate) {
1458					// Order of the next few commands are important. Change the time and then pause.
1459					// Solves a bug in Firefox, where issuing pause 1st causes the media to play from the start. ie., The pause is ignored.
1460					if(!$.jPlayer.browser.webkit) { // Chrome crashes if you do this in conjunction with a setMedia command in an ended event handler. ie., The playlist demo.
1461						self.htmlElement.media.currentTime = 0; // Safari does not care about this command. ie., It works with or without this line. (Both Safari and Chrome are Webkit.)
1462					}
1463					self.htmlElement.media.pause(); // Pause otherwise a click on the progress bar will play from that point, when it shouldn't, since it stopped playback.
1464					self._updateButtons(false);
1465					self._getHtmlStatus(mediaElement, true); // With override true. Otherwise Chrome leaves progress at full.
1466					self._updateInterface();
1467					self._trigger($.jPlayer.event.ended);
1468				}
1469			}, false);
1470			mediaElement.addEventListener("error", function() {
1471				if(entity.gate) {
1472					self._updateButtons(false);
1473					self._seeked();
1474					if(self.status.srcSet) { // Deals with case of clearMedia() causing an error event.
1475						clearTimeout(self.internal.htmlDlyCmdId); // Clears any delayed commands used in the HTML solution.
1476						self.status.waitForLoad = true; // Allows the load operation to try again.
1477						self.status.waitForPlay = true; // Reset since a play was captured.
1478						if(self.status.video && !self.status.nativeVideoControls) {
1479							self.internal.video.jq.css({'width':'0px', 'height':'0px'});
1480						}
1481						if(self._validString(self.status.media.poster) && !self.status.nativeVideoControls) {
1482							self.internal.poster.jq.show();
1483						}
1484						if(self.css.jq.videoPlay.length) {
1485							self.css.jq.videoPlay.show();
1486						}
1487						self._error( {
1488							type: $.jPlayer.error.URL,
1489							context: self.status.src, // this.src shows absolute urls. Want context to show the url given.
1490							message: $.jPlayer.errorMsg.URL,
1491							hint: $.jPlayer.errorHint.URL
1492						});
1493					}
1494				}
1495			}, false);
1496			// Create all the other event listeners that bubble up to a jPlayer event from html, without being used by jPlayer.
1497			$.each($.jPlayer.htmlEvent, function(i, eventType) {
1498				mediaElement.addEventListener(this, function() {
1499					if(entity.gate) {
1500						self._trigger($.jPlayer.event[eventType]);
1501					}
1502				}, false);
1503			});
1504		},
1505		_addAuroraEventListeners : function(player, entity) {
1506			var self = this;
1507			//player.preload = this.options.preload;
1508			//player.muted = this.options.muted;
1509			player.volume = this.options.volume * 100;
1510
1511			// Create the event listeners
1512			// Only want the active entity to affect jPlayer and bubble events.
1513			// Using entity.gate so that object is referenced and gate property always current
1514			
1515			player.on("progress", function() {
1516				if(entity.gate) {
1517					if(self.internal.cmdsIgnored && this.readyState > 0) { // Detect iOS executed the command
1518						self.internal.cmdsIgnored = false;
1519					}
1520					self._getAuroraStatus(player);
1521					self._updateInterface();
1522					self._trigger($.jPlayer.event.progress);
1523					// Progress with song duration, we estimate timeupdate need to be triggered too.
1524					if (player.duration > 0) {
1525						self._trigger($.jPlayer.event.timeupdate);
1526					}
1527				}
1528			}, false);
1529			player.on("ready", function() {
1530				if(entity.gate) {
1531					self._trigger($.jPlayer.event.loadeddata);
1532				}
1533			}, false);
1534			player.on("duration", function() {
1535				if(entity.gate) {
1536					self._getAuroraStatus(player);
1537					self._updateInterface();
1538					self._trigger($.jPlayer.event.durationchange);
1539				}
1540			}, false);
1541			player.on("end", function() {
1542				if(entity.gate) {
1543					// Order of the next few commands are important. Change the time and then pause.
1544					self._updateButtons(false);
1545					self._getAuroraStatus(player, true);
1546					self._updateInterface();
1547					self._trigger($.jPlayer.event.ended);
1548				}
1549			}, false);
1550			player.on("error", function() {
1551				if(entity.gate) {
1552					self._updateButtons(false);
1553					self._seeked();
1554					if(self.status.srcSet) { // Deals with case of clearMedia() causing an error event.
1555						self.status.waitForLoad = true; // Allows the load operation to try again.
1556						self.status.waitForPlay = true; // Reset since a play was captured.
1557						if(self.status.video && !self.status.nativeVideoControls) {
1558							self.internal.video.jq.css({'width':'0px', 'height':'0px'});
1559						}
1560						if(self._validString(self.status.media.poster) && !self.status.nativeVideoControls) {
1561							self.internal.poster.jq.show();
1562						}
1563						if(self.css.jq.videoPlay.length) {
1564							self.css.jq.videoPlay.show();
1565						}
1566						self._error( {
1567							type: $.jPlayer.error.URL,
1568							context: self.status.src, // this.src shows absolute urls. Want context to show the url given.
1569							message: $.jPlayer.errorMsg.URL,
1570							hint: $.jPlayer.errorHint.URL
1571						});
1572					}
1573				}
1574			}, false);
1575		},
1576		_getHtmlStatus: function(media, override) {
1577			var ct = 0, cpa = 0, sp = 0, cpr = 0;
1578
1579			// Fixes the duration bug in iOS, where the durationchange event occurs when media.duration is not always correct.
1580			// Fixes the initial duration bug in BB OS7, where the media.duration is infinity and displays as NaN:NaN due to Date() using inifity.
1581			if(isFinite(media.duration)) {
1582				this.status.duration = media.duration;
1583			}
1584
1585			ct = media.currentTime;
1586			cpa = (this.status.duration > 0) ? 100 * ct / this.status.duration : 0;
1587			if((typeof media.seekable === "object") && (media.seekable.length > 0)) {
1588				sp = (this.status.duration > 0) ? 100 * media.seekable.end(media.seekable.length-1) / this.status.duration : 100;
1589				cpr = (this.status.duration > 0) ? 100 * media.currentTime / media.seekable.end(media.seekable.length-1) : 0; // Duration conditional for iOS duration bug. ie., seekable.end is a NaN in that case.
1590			} else {
1591				sp = 100;
1592				cpr = cpa;
1593			}
1594			
1595			if(override) {
1596				ct = 0;
1597				cpr = 0;
1598				cpa = 0;
1599			}
1600
1601			this.status.seekPercent = sp;
1602			this.status.currentPercentRelative = cpr;
1603			this.status.currentPercentAbsolute = cpa;
1604			this.status.currentTime = ct;
1605
1606			this.status.remaining = this.status.duration - this.status.currentTime;
1607
1608			this.status.videoWidth = media.videoWidth;
1609			this.status.videoHeight = media.videoHeight;
1610
1611			this.status.readyState = media.readyState;
1612			this.status.networkState = media.networkState;
1613			this.status.playbackRate = media.playbackRate;
1614			this.status.ended = media.ended;
1615		},
1616		_getAuroraStatus: function(player, override) {
1617			var ct = 0, cpa = 0, sp = 0, cpr = 0;
1618
1619			this.status.duration = player.duration / 1000;
1620
1621			ct = player.currentTime / 1000;
1622			cpa = (this.status.duration > 0) ? 100 * ct / this.status.duration : 0;
1623			if(player.buffered > 0) {
1624				sp = (this.status.duration > 0) ? (player.buffered * this.status.duration) / this.status.duration : 100;
1625				cpr = (this.status.duration > 0) ? ct / (player.buffered * this.status.duration) : 0;
1626			} else {
1627				sp = 100;
1628				cpr = cpa;
1629			}
1630			
1631			if(override) {
1632				ct = 0;
1633				cpr = 0;
1634				cpa = 0;
1635			}
1636
1637			this.status.seekPercent = sp;
1638			this.status.currentPercentRelative = cpr;
1639			this.status.currentPercentAbsolute = cpa;
1640			this.status.currentTime = ct;
1641
1642			this.status.remaining = this.status.duration - this.status.currentTime;
1643
1644			this.status.readyState = 4; // status.readyState;
1645			this.status.networkState = 0; // status.networkState;
1646			this.status.playbackRate = 1; // status.playbackRate;
1647			this.status.ended = false; // status.ended;
1648		},
1649		_resetStatus: function() {
1650			this.status = $.extend({}, this.status, $.jPlayer.prototype.status); // Maintains the status properties that persist through a reset.
1651		},
1652		_trigger: function(eventType, error, warning) { // eventType always valid as called using $.jPlayer.event.eventType
1653			var event = $.Event(eventType);
1654			event.jPlayer = {};
1655			event.jPlayer.version = $.extend({}, this.version);
1656			event.jPlayer.options = $.extend(true, {}, this.options); // Deep copy
1657			event.jPlayer.status = $.extend(true, {}, this.status); // Deep copy
1658			event.jPlayer.html = $.extend(true, {}, this.html); // Deep copy
1659			event.jPlayer.aurora = $.extend(true, {}, this.aurora); // Deep copy
1660			event.jPlayer.flash = $.extend(true, {}, this.flash); // Deep copy
1661			if(error) {
1662				event.jPlayer.error = $.extend({}, error);
1663			}
1664			if(warning) {
1665				event.jPlayer.warning = $.extend({}, warning);
1666			}
1667			this.element.trigger(event);
1668		},
1669		jPlayerFlashEvent: function(eventType, status) { // Called from Flash
1670			if(eventType === $.jPlayer.event.ready) {
1671				if(!this.internal.ready) {
1672					this.internal.ready = true;
1673					this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Once Flash generates the ready event, minimise to zero as it is not affected by wmode anymore.
1674
1675					this.version.flash = status.version;
1676					if(this.version.needFlash !== this.version.flash) {
1677						this._error( {
1678							type: $.jPlayer.error.VERSION,
1679							context: this.version.flash,
1680							message: $.jPlayer.errorMsg.VERSION + this.version.flash,
1681							hint: $.jPlayer.errorHint.VERSION
1682						});
1683					}
1684					this._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option.
1685					this._trigger(eventType);
1686				} else {
1687					// This condition occurs if the Flash is hidden and then shown again.
1688					// Firefox also reloads the Flash if the CSS position changes. position:fixed is used for full screen.
1689
1690					// Only do this if the Flash is the solution being used at the moment. Affects Media players where both solution may be being used.
1691					if(this.flash.gate) {
1692
1693						// Send the current status to the Flash now that it is ready (available) again.
1694						if(this.status.srcSet) {
1695
1696							// Need to read original status before issuing the setMedia command.
1697							var	currentTime = this.status.currentTime,
1698								paused = this.status.paused; 
1699
1700							this.setMedia(this.status.media);
1701							this.volumeWorker(this.options.volume);
1702							if(currentTime > 0) {
1703								if(paused) {
1704									this.pause(currentTime);
1705								} else {
1706									this.play(currentTime);
1707								}
1708							}
1709						}
1710						this._trigger($.jPlayer.event.flashreset);
1711					}
1712				}
1713			}
1714			if(this.flash.gate) {
1715				switch(eventType) {
1716					case $.jPlayer.event.progress:
1717						this._getFlashStatus(status);
1718						this._updateInterface();
1719						this._trigger(eventType);
1720						break;
1721					case $.jPlayer.event.timeupdate:
1722						this._getFlashStatus(status);
1723						this._updateInterface();
1724						this._trigger(eventType);
1725						break;
1726					case $.jPlayer.event.play:
1727						this._seeked();
1728						this._updateButtons(true);
1729						this._trigger(eventType);
1730						break;
1731					case $.jPlayer.event.pause:
1732						this._updateButtons(false);
1733						this._trigger(eventType);
1734						break;
1735					case $.jPlayer.event.ended:
1736						this._updateButtons(false);
1737						this._trigger(eventType);
1738						break;
1739					case $.jPlayer.event.click:
1740						this._trigger(eventType); // This could be dealt with by the default
1741						break;
1742					case $.jPlayer.event.error:
1743						this.status.waitForLoad = true; // Allows the load operation to try again.
1744						this.status.waitForPlay = true; // Reset since a play was captured.
1745						if(this.status.video) {
1746							this.internal.flash.jq.css({'width':'0px', 'height':'0px'});
1747						}
1748						if(this._validString(this.status.media.poster)) {
1749							this.internal.poster.jq.show();
1750						}
1751						if(this.css.jq.videoPlay.length && this.status.video) {
1752							this.css.jq.videoPlay.show();
1753						}
1754						if(this.status.video) { // Set up for another try. Execute before error event.
1755							this._flash_setVideo(this.status.media);
1756						} else {
1757							this._flash_setAudio(this.status.media);
1758						}
1759						this._updateButtons(false);
1760						this._error( {
1761							type: $.jPlayer.error.URL,
1762							context:status.src,
1763							message: $.jPlayer.errorMsg.URL,
1764							hint: $.jPlayer.errorHint.URL
1765						});
1766						break;
1767					case $.jPlayer.event.seeking:
1768						this._seeking();
1769						this._trigger(eventType);
1770						break;
1771					case $.jPlayer.event.seeked:
1772						this._seeked();
1773						this._trigger(eventType);
1774						break;
1775					case $.jPlayer.event.ready:
1776						// The ready event is handled outside the switch statement.
1777						// Captured here otherwise 2 ready events would be generated if the ready event handler used setMedia.
1778						break;
1779					default:
1780						this._trigger(eventType);
1781				}
1782			}
1783			return false;
1784		},
1785		_getFlashStatus: function(status) {
1786			this.status.seekPercent = status.seekPercent;
1787			this.status.currentPercentRelative = status.currentPercentRelative;
1788			this.status.currentPercentAbsolute = status.currentPercentAbsolute;
1789			this.status.currentTime = status.currentTime;
1790			this.status.duration = status.duration;
1791			this.status.remaining = status.duration - status.currentTime;
1792
1793			this.status.videoWidth = status.videoWidth;
1794			this.status.videoHeight = status.videoHeight;
1795
1796			// The Flash does not generate this information in this release
1797			this.status.readyState = 4; // status.readyState;
1798			this.status.networkState = 0; // status.networkState;
1799			this.status.playbackRate = 1; // status.playbackRate;
1800			this.status.ended = false; // status.ended;
1801		},
1802		_updateButtons: function(playing) {
1803			if(playing === undefined) {
1804				playing = !this.status.paused;
1805			} else {
1806				this.status.paused = !playing;
1807			}
1808			// Apply the state classes. (For the useStateClassSkin:true option)
1809			if(playing) {
1810				this.addStateClass('playing');
1811			} else {
1812				this.removeStateClass('playing');
1813			}
1814			if(!this.status.noFullWindow && this.options.fullWindow) {
1815				this.addStateClass('fullScreen');
1816			} else {
1817				this.removeStateClass('fullScreen');
1818			}
1819			if(this.options.loop) {
1820				this.addStateClass('looped');
1821			} else {
1822				this.removeStateClass('looped');
1823			}
1824			// Toggle the GUI element pairs. (For the useStateClassSkin:false option)
1825			if(this.css.jq.play.length && this.css.jq.pause.length) {
1826				if(playing) {
1827					this.css.jq.play.hide();
1828					this.css.jq.pause.show();
1829				} else {
1830					this.css.jq.play.show();
1831					this.css.jq.pause.hide();
1832				}
1833			}
1834			if(this.css.jq.restoreScreen.length && this.css.jq.fullScreen.length) {
1835				if(this.status.noFullWindow) {
1836					this.css.jq.fullScreen.hide();
1837					this.css.jq.restoreScreen.hide();
1838				} else if(this.options.fullWindow) {
1839					this.css.jq.fullScreen.hide();
1840					this.css.jq.restoreScreen.show();
1841				} else {
1842					this.css.jq.fullScreen.show();
1843					this.css.jq.restoreScreen.hide();
1844				}
1845			}
1846			if(this.css.jq.repeat.length && this.css.jq.repeatOff.length) {
1847				if(this.options.loop) {
1848					this.css.jq.repeat.hide();
1849					this.css.jq.repeatOff.show();
1850				} else {
1851					this.css.jq.repeat.show();
1852					this.css.jq.repeatOff.hide();
1853				}
1854			}
1855		},
1856		_updateInterface: function() {
1857			if(this.css.jq.seekBar.length) {
1858				this.css.jq.seekBar.width(this.status.seekPercent+"%");
1859			}
1860			if(this.css.jq.playBar.length) {
1861				if(this.options.smoothPlayBar) {
1862					this.css.jq.playBar.stop().animate({
1863						width: this.status.currentPercentAbsolute+"%"
1864					}, 250, "linear");
1865				} else {
1866					this.css.jq.playBar.width(this.status.currentPercentRelative+"%");
1867				}
1868			}
1869			var currentTimeText = '';
1870			if(this.css.jq.currentTime.length) {
1871				currentTimeText = this._convertTime(this.status.currentTime);
1872				if(currentTimeText !== this.css.jq.currentTime.text()) {
1873					this.css.jq.currentTime.text(this._convertTime(this.status.currentTime));
1874				}
1875			}
1876			var durationText = '',
1877				duration = this.status.duration,
1878				remaining = this.status.remaining;
1879			if(this.css.jq.duration.length) {
1880				if(typeof this.status.media.duration === 'string') {
1881					durationText = this.status.media.duration;
1882				} else {
1883					if(typeof this.status.media.duration === 'number') {
1884						duration = this.status.media.duration;
1885						remaining = duration - this.status.currentTime;
1886					}
1887					if(this.options.remainingDuration) {
1888						durationText = (remaining > 0 ? '-' : '') + this._convertTime(remaining);
1889					} else {
1890						durationText = this._convertTime(duration);
1891					}
1892				}
1893				if(durationText !== this.css.jq.duration.text()) {
1894					this.css.jq.duration.text(durationText);
1895				}
1896			}
1897		},
1898		_convertTime: ConvertTime.prototype.time,
1899		_seeking: function() {
1900			if(this.css.jq.seekBar.length) {
1901				this.css.jq.seekBar.addClass("jp-seeking-bg");
1902			}
1903			this.addStateClass('seeking');
1904		},
1905		_seeked: function() {
1906			if(this.css.jq.seekBar.length) {
1907				this.css.jq.seekBar.removeClass("jp-seeking-bg");
1908			}
1909			this.removeStateClass('seeking');
1910		},
1911		_resetGate: function() {
1912			this.html.audio.gate = false;
1913			this.html.video.gate = false;
1914			this.aurora.gate = false;
1915			this.flash.gate = false;
1916		},
1917		_resetActive: function() {
1918			this.html.active = false;
1919			this.aurora.active = false;
1920			this.flash.active = false;
1921		},
1922		_escapeHtml: function(s) {
1923			return s.split('&').join('&amp;').split('<').join('&lt;').split('>').join('&gt;').split('"').join('&quot;');
1924		},
1925		_qualifyURL: function(url) {
1926			var el = document.createElement('div');
1927			el.innerHTML= '<a href="' + this._escapeHtml(url) + '">x</a>';
1928			return el.firstChild.href;
1929		},
1930		_absoluteMediaUrls: function(media) {
1931			var self = this;
1932			$.each(media, function(type, url) {
1933				if(url && self.format[type] && url.substr(0, 5) !== "data:") {
1934					media[type] = self._qualifyURL(url);
1935				}
1936			});
1937			return media;
1938		},
1939		addStateClass: function(state) {
1940			if(this.ancestorJq.length) {
1941				this.ancestorJq.addClass(this.options.stateClass[state]);
1942			}
1943		},
1944		removeStateClass: function(state) {
1945			if(this.ancestorJq.length) {
1946				this.ancestorJq.removeClass(this.options.stateClass[state]);
1947			}
1948		},
1949		setMedia: function(media) {
1950		
1951			/*	media[format] = String: URL of format. Must contain all of the supplied option's video or audio formats.
1952			 *	media.poster = String: Video poster URL.
1953			 *	media.track = Array: Of objects defining the track element: kind, src, srclang, label, def.
1954			 *	media.stream = Boolean: * NOT IMPLEMENTED * Designating actual media streams. ie., "false/undefined" for files. Plan to refresh the flash every so often.
1955			 */
1956
1957			var	self = this,
1958				supported = false,
1959				posterChanged = this.status.media.poster !== media.poster; // Compare before reset. Important for OSX Safari as this.htmlElement.poster.src is absolute, even if original poster URL was relative.
1960
1961			this._resetMedia();
1962			this._resetGate();
1963			this._resetActive();
1964
1965			// Clear the Android Fix.
1966			this.androidFix.setMedia = false;
1967			this.androidFix.play = false;
1968			this.androidFix.pause = false;
1969
1970			// Convert all media URLs to absolute URLs.
1971			media = this._absoluteMediaUrls(media);
1972
1973			$.each(this.formats, function(formatPriority, format) {
1974				var isVideo = self.format[format].media === 'video';
1975				$.each(self.solutions, function(solutionPriority, solution) {
1976					if(self[solution].support[format] && self._validString(media[format])) { // Format supported in solution and url given for format.
1977						var isHtml = solution === 'html';
1978						var isAurora = solution === 'aurora';
1979
1980						if(isVideo) {
1981							if(isHtml) {
1982								self.html.video.gate = true;
1983								self._html_setVideo(media);
1984								self.html.active = true;
1985							} else {
1986								self.flash.gate = true;
1987								self._flash_setVideo(media);
1988								self.flash.active = true;
1989							}
1990							if(self.css.jq.videoPlay.length) {
1991								self.css.jq.videoPlay.show();
1992							}
1993							self.status.video = true;
1994						} else {
1995							if(isHtml) {
1996								self.html.audio.gate = true;
1997								self._html_setAudio(media);
1998								self.html.active = true;
1999
2000								// Setup the Android Fix - Only for HTML audio.
2001								if($.jPlayer.platform.android) {
2002									self.androidFix.setMedia = true;
2003								}
2004							} else if(isAurora) {
2005								self.aurora.gate = true;
2006								self._aurora_setAudio(media);
2007								self.aurora.active = true;
2008							} else {
2009								self.flash.gate = true;
2010								self._flash_setAudio(media);
2011								self.flash.active = true;
2012							}
2013							if(self.css.jq.videoPlay.length) {
2014								self.css.jq.videoPlay.hide();
2015							}
2016							self.status.video = false;
2017						}
2018						
2019						supported = true;
2020						return false; // Exit $.each
2021					}
2022				});
2023				if(supported) {
2024					return false; // Exit $.each
2025				}
2026			});
2027
2028			if(supported) {
2029				if(!(this.status.nativeVideoControls && this.html.video.gate)) {
2030					// Set poster IMG if native video controls are not being used
2031					// Note: With IE the IMG onload event occurs immediately when cached.
2032					// Note: Poster hidden by default in _resetMedia()
2033					if(this._validString(media.poster)) {
2034						if(posterChanged) { // Since some browsers do not generate img onload event.
2035							this.htmlElement.poster.src = media.poster;
2036						} else {
2037							this.internal.poster.jq.show();
2038						}
2039					}
2040				}
2041				if(typeof media.title === 'string') {
2042					if(this.css.jq.title.length) {
2043						this.css.jq.title.html(media.title);
2044					}
2045					if(this.htmlElement.audio) {
2046						this.htmlElement.audio.setAttribute('title', media.title);
2047					}
2048					if(this.htmlElement.video) {
2049						this.htmlElement.video.setAttribute('title', media.title);
2050					}
2051				}
2052				this.status.srcSet = true;
2053				this.status.media = $.extend({}, media);
2054				this._updateButtons(false);
2055				this._updateInterface();
2056				this._trigger($.jPlayer.event.setmedia);
2057			} else { // jPlayer cannot support any formats provided in this browser
2058				// Send an error event
2059				this._error( {
2060					type: $.jPlayer.error.NO_SUPPORT,
2061					context: "{supplied:'" + this.options.supplied + "'}",
2062					message: $.jPlayer.errorMsg.NO_SUPPORT,
2063					hint: $.jPlayer.errorHint.NO_SUPPORT
2064				});
2065			}
2066		},
2067		_resetMedia: function() {
2068			this._resetStatus();
2069			this._updateButtons(false);
2070			this._updateInterface();
2071			this._seeked();
2072			this.internal.poster.jq.hide();
2073
2074			clearTimeout(this.internal.htmlDlyCmdId);
2075
2076			if(this.html.active) {
2077				this._html_resetMedia();
2078			} else if(this.aurora.active) {
2079				this._aurora_resetMedia();
2080			} else if(this.flash.active) {
2081				this._flash_resetMedia();
2082			}
2083		},
2084		clearMedia: function() {
2085			this._resetMedia();
2086
2087			if(this.html.active) {
2088				this._html_clearMedia();
2089			} else if(this.aurora.active) {
2090				this._aurora_clearMedia();
2091			} else if(this.flash.active) {
2092				this._flash_clearMedia();
2093			}
2094
2095			this._resetGate();
2096			this._resetActive();
2097		},
2098		load: function() {
2099			if(this.status.srcSet) {
2100				if(this.html.active) {
2101					this._html_load();
2102				} else if(this.aurora.active) {
2103					this._aurora_load();
2104				} else if(this.flash.active) {
2105					this._flash_load();
2106				}
2107			} else {
2108				this._urlNotSetError("load");
2109			}
2110		},
2111		focus: function() {
2112			if(this.options.keyEnabled) {
2113				$.jPlayer.focus = this;
2114			}
2115		},
2116		play: function(time) {
2117			var guiAction = typeof time === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
2118			if(guiAction && this.options.useStateClassSkin && !this.status.paused) {
2119				this.pause(time); // The time would be the click event, but passing it over so info is not lost.
2120			} else {
2121				time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler
2122				if(this.status.srcSet) {
2123					this.focus();
2124					if(this.html.active) {
2125						this._html_play(time);
2126					} else if(this.aurora.active) {
2127						this._aurora_play(time);
2128					} else if(this.flash.active) {
2129						this._flash_play(time);
2130					}
2131				} else {
2132					this._urlNotSetError("play");
2133				}
2134			}
2135		},
2136		videoPlay: function() { // Handles clicks on the play button over the video poster
2137			this.play();
2138		},
2139		pause: function(time) {
2140			time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler
2141			if(this.status.srcSet) {
2142				if(this.html.active) {
2143					this._html_pause(time);
2144				} else if(this.aurora.active) {
2145					this._aurora_pause(time);
2146				} else if(this.flash.active) {
2147					this._flash_pause(time);
2148				}
2149			} else {
2150				this._urlNotSetError("pause");
2151			}
2152		},
2153		tellOthers: function(command, conditions) {
2154			var self = this,
2155				hasConditions = typeof conditions === 'function',
2156				args = Array.prototype.slice.call(arguments); // Convert arguments to an Array.
2157
2158			if(typeof command !== 'string') { // Ignore, since no command.
2159				return; // Return undefined to maintain chaining.
2160			}
2161			if(hasConditions) {
2162				args.splice(1, 1); // Remove the conditions from the arguments
2163			}
2164
2165			$.jPlayer.prototype.destroyRemoved();
2166			$.each(this.instances, function() {
2167				// Remember that "this" is the instance's "element" in the $.each() loop.
2168				if(self.element !== this) { // Do not tell my instance.
2169					if(!hasConditions || conditions.call(this.data("jPlayer"), self)) {
2170						this.jPlayer.apply(this, args);
2171					}
2172				}
2173			});
2174		},
2175		pauseOthers: function(time) {
2176			this.tellOthers("pause", function() {
2177				// In the conditions function, the "this" context is the other instance's jPlayer object.
2178				return this.status.srcSet;
2179			}, time);
2180		},
2181		stop: function() {
2182			if(this.status.srcSet) {
2183				if(this.html.active) {
2184					this._html_pause(0);
2185				} else if(this.aurora.active) {
2186					this._aurora_pause(0);
2187				} else if(this.flash.active) {
2188					this._flash_pause(0);
2189				}
2190			} else {
2191				this._urlNotSetError("stop");
2192			}
2193		},
2194		playHead: function(p) {
2195			p = this._limitValue(p, 0, 100);
2196			if(this.status.srcSet) {
2197				if(this.html.active) {
2198					this._html_playHead(p);
2199				} else if(this.aurora.active) {
2200					this._aurora_playHead(p);
2201				} else if(this.flash.active) {
2202					this._flash_playHead(p);
2203				}
2204			} else {
2205				this._urlNotSetError("playHead");
2206			}
2207		},
2208		_muted: function(muted) {
2209			this.mutedWorker(muted);
2210			if(this.options.globalVolume) {
2211				this.tellOthers("mutedWorker", function() {
2212					// Check the other instance has global volume enabled.
2213					return this.options.globalVolume;
2214				}, muted);
2215			}
2216		},
2217		mutedWorker: function(muted) {
2218			this.options.muted = muted;
2219			if(this.html.used) {
2220				this._html_setProperty('muted', muted);
2221			}
2222			if(this.aurora.used) {
2223				this._aurora_mute(muted);
2224			}
2225			if(this.flash.used) {
2226				this._flash_mute(muted);
2227			}
2228
2229			// The HTML solution generates this event from the media element itself.
2230			if(!this.html.video.gate && !this.html.audio.gate) {
2231				this._updateMute(muted);
2232				this._updateVolume(this.options.volume);
2233				this._trigger($.jPlayer.event.volumechange);
2234			}
2235		},
2236		mute: function(mute) { // mute is either: undefined (true), an event object (true) or a boolean (muted).
2237			var guiAction = typeof mute === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
2238			if(guiAction && this.options.useStateClassSkin && this.options.muted) {
2239				this._muted(false);
2240			} else {
2241				mute = mute === undefined ? true : !!mute;
2242				this._muted(mute);
2243			}
2244		},
2245		unmute: function(unmute) { // unmute is either: undefined (true), an event object (true) or a boolean (!muted).
2246			unmute = unmute === undefined ? true : !!unmute;
2247			this._muted(!unmute);
2248		},
2249		_updateMute: function(mute) {
2250			if(mute === undefined) {
2251				mute = this.options.muted;
2252			}
2253			if(mute) {
2254				this.addStateClass('muted');
2255			} else {
2256				this.removeStateClass('muted');
2257			}
2258			if(this.css.jq.mute.length && this.css.jq.unmute.length) {
2259				if(this.status.noVolume) {
2260					this.css.jq.mute.hide();
2261					this.css.jq.unmute.hide();
2262				} else if(mute) {
2263					this.css.jq.mute.hide();
2264					this.css.jq.unmute.show();
2265				} else {
2266					this.css.jq.mute.show();
2267					this.css.jq.unmute.hide();
2268				}
2269			}
2270		},
2271		volume: function(v) {
2272			this.volumeWorker(v);
2273			if(this.options.globalVolume) {
2274				this.tellOthers("volumeWorker", function() {
2275					// Check the other instance has global volume enabled.
2276					return this.options.globalVolume;
2277				}, v);
2278			}
2279		},
2280		volumeWorker: function(v) {
2281			v = this._limitValue(v, 0, 1);
2282			this.options.volume = v;
2283
2284			if(this.html.used) {
2285				this._html_setProperty('volume', v);
2286			}
2287			if(this.aurora.used) {
2288				this._aurora_volume(v);
2289			}
2290			if(this.flash.used) {
2291				this._flash_volume(v);
2292			}
2293
2294			// The HTML solution generates this event from the media element itself.
2295			if(!this.html.video.gate && !this.html.audio.gate) {
2296				this._updateVolume(v);
2297				this._trigger($.jPlayer.event.volumechange);
2298			}
2299		},
2300		volumeBar: function(e) { // Handles clicks on the volumeBar
2301			if(this.css.jq.volumeBar.length) {
2302				// Using $(e.currentTarget) to enable multiple volume bars
2303				var $bar = $(e.currentTarget),
2304					offset = $bar.offset(),
2305					x = e.pageX - offset.left,
2306					w = $bar.width(),
2307					y = $bar.height() - e.pageY + offset.top,
2308					h = $bar.height();
2309				if(this.options.verticalVolume) {
2310					this.volume(y/h);
2311				} else {
2312					this.volume(x/w);
2313				}
2314			}
2315			if(this.options.muted) {
2316				this._muted(false);
2317			}
2318		},
2319		_updateVolume: function(v) {
2320			if(v === undefined) {
2321				v = this.options.volume;
2322			}
2323			v = this.options.muted ? 0 : v;
2324
2325			if(this.status.noVolume) {
2326				this.addStateClass('noVolume');
2327				if(this.css.jq.volumeBar.length) {
2328					this.css.jq.volumeBar.hide();
2329				}
2330				if(this.css.jq.volumeBarValue.length) {
2331					this.css.jq.volumeBarValue.hide();
2332				}
2333				if(this.css.jq.volumeMax.length) {
2334					this.css.jq.volumeMax.hide();
2335				}
2336			} else {
2337				this.removeStateClass('noVolume');
2338				if(this.css.jq.volumeBar.length) {
2339					this.css.jq.volumeBar.show();
2340				}
2341				if(this.css.jq.volumeBarValue.length) {
2342					this.css.jq.volumeBarValue.show();
2343					this.css.jq.volumeBarValue[this.options.verticalVolume ? "height" : "width"]((v*100)+"%");
2344				}
2345				if(this.css.jq.volumeMax.length) {
2346					this.css.jq.volumeMax.show();
2347				}
2348			}
2349		},
2350		volumeMax: function() { // Handles clicks on the volume max
2351			this.volume(1);
2352			if(this.options.muted) {
2353				this._muted(false);
2354			}
2355		},
2356		_cssSelectorAncestor: function(ancestor) {
2357			var self = this;
2358			this.options.cssSelectorAncestor = ancestor;
2359			this._removeUiClass();
2360			this.ancestorJq = ancestor ? $(ancestor) : []; // Would use $() instead of [], but it is only 1.4+
2361			if(ancestor && this.ancestorJq.length !== 1) { // So empty strings do not generate the warning.
2362				this._warning( {
2363					type: $.jPlayer.warning.CSS_SELECTOR_COUNT,
2364					context: ancestor,
2365					message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.ancestorJq.length + " found for cssSelectorAncestor.",
2366					hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT
2367				});
2368			}
2369			this._addUiClass();
2370			$.each(this.options.cssSelector, function(fn, cssSel) {
2371				self._cssSelector(fn, cssSel);
2372			});
2373
2374			// Set the GUI to the current state.
2375			this._updateInterface();
2376			this._updateButtons();
2377			this._updateAutohide();
2378			this._updateVolume();
2379			this._updateMute();
2380		},
2381		_cssSelector: function(fn, cssSel) {
2382			var self = this;
2383			if(typeof cssSel === 'string') {
2384				if($.jPlayer.prototype.options.cssSelector[fn]) {
2385					if(this.css.jq[fn] && this.css.jq[fn].length) {
2386						this.css.jq[fn].unbind(".jPlayer");
2387					}
2388					this.options.cssSelector[fn] = cssSel;
2389					this.css.cs[fn] = this.options.cssSelectorAncestor + " " + cssSel;
2390
2391					if(cssSel) { // Checks for empty string
2392						this.css.jq[fn] = $(this.css.cs[fn]);
2393					} else {
2394						this.css.jq[fn] = []; // To comply with the css.jq[fn].length check before its use. As of jQuery 1.4 could have used $() for an empty set. 
2395					}
2396
2397					if(this.css.jq[fn].length && this[fn]) {
2398						var handler = function(e) {
2399							e.preventDefault();
2400							self[fn](e);
2401							if(self.options.autoBlur) {
2402								$(this).blur();
2403							} else {
2404								$(this).focus(); // Force focus for ARIA.
2405							}
2406						};
2407						this.css.jq[fn].bind("click.jPlayer", handler); // Using jPlayer namespace
2408					}
2409
2410					if(cssSel && this.css.jq[fn].length !== 1) { // So empty strings do not generate the warning. ie., they just remove the old one.
2411						this._warning( {
2412							type: $.jPlayer.warning.CSS_SELECTOR_COUNT,
2413							context: this.css.cs[fn],
2414							message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.css.jq[fn].length + " found for " + fn + " method.",
2415							hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT
2416						});
2417					}
2418				} else {
2419					this._warning( {
2420						type: $.jPlayer.warning.CSS_SELECTOR_METHOD,
2421						context: fn,
2422						message: $.jPlayer.warningMsg.CSS_SELECTOR_METHOD,
2423						hint: $.jPlayer.warningHint.CSS_SELECTOR_METHOD
2424					});
2425				}
2426			} else {
2427				this._warning( {
2428					type: $.jPlayer.warning.CSS_SELECTOR_STRING,
2429					context: cssSel,
2430					message: $.jPlayer.warningMsg.CSS_SELECTOR_STRING,
2431					hint: $.jPlayer.warningHint.CSS_SELECTOR_STRING
2432				});
2433			}
2434		},
2435		duration: function(e) {
2436			if(this.options.toggleDuration) {
2437				if(this.options.captureDuration) {
2438					e.stopPropagation();
2439				}
2440				this._setOption("remainingDuration", !this.options.remainingDuration);
2441			}
2442		},
2443		seekBar: function(e) { // Handles clicks on the seekBar
2444			if(this.css.jq.seekBar.length) {
2445				// Using $(e.currentTarget) to enable multiple seek bars
2446				var $bar = $(e.currentTarget),
2447					offset = $bar.offset(),
2448					x = e.pageX - offset.left,
2449					w = $bar.width(),
2450					p = 100 * x / w;
2451				this.playHead(p);
2452			}
2453		},
2454		playbackRate: function(pbr) {
2455			this._setOption("playbackRate", pbr);
2456		},
2457		playbackRateBar: function(e) { // Handles clicks on the playbackRateBar
2458			if(this.css.jq.playbackRateBar.length) {
2459				// Using $(e.currentTarget) to enable multiple playbackRate bars
2460				var $bar = $(e.currentTarget),
2461					offset = $bar.offset(),
2462					x = e.pageX - offset.left,
2463					w = $bar.width(),
2464					y = $bar.height() - e.pageY + offset.top,
2465					h = $bar.height(),
2466					ratio, pbr;
2467				if(this.options.verticalPlaybackRate) {
2468					ratio = y/h;
2469				} else {
2470					ratio = x/w;
2471				}
2472				pbr = ratio * (this.options.maxPlaybackRate - this.options.minPlaybackRate) + this.options.minPlaybackRate;
2473				this.playbackRate(pbr);
2474			}
2475		},
2476		_updatePlaybackRate: function() {
2477			var pbr = this.options.playbackRate,
2478				ratio = (pbr - this.options.minPlaybackRate) / (this.options.maxPlaybackRate - this.options.minPlaybackRate);
2479			if(this.status.playbackRateEnabled) {
2480				if(this.css.jq.playbackRateBar.length) {
2481					this.css.jq.playbackRateBar.show();
2482				}
2483				if(this.css.jq.playbackRateBarValue.length) {
2484					this.css.jq.playbackRateBarValue.show();
2485					this.css.jq.playbackRateBarValue[this.options.verticalPlaybackRate ? "height" : "width"]((ratio*100)+"%");
2486				}
2487			} else {
2488				if(this.css.jq.playbackRateBar.length) {
2489					this.css.jq.playbackRateBar.hide();
2490				}
2491				if(this.css.jq.playbackRateBarValue.length) {
2492					this.css.jq.playbackRateBarValue.hide();
2493				}
2494			}
2495		},
2496		repeat: function(event) { // Handle clicks on the repeat button
2497			var guiAction = typeof event === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
2498			if(guiAction && this.options.useStateClassSkin && this.options.loop) {
2499				this._loop(false);
2500			} else {
2501				this._loop(true);
2502			}
2503		},
2504		repeatOff: function() { // Handle clicks on the repeatOff button
2505			this._loop(false);
2506		},
2507		_loop: function(loop) {
2508			if(this.options.loop !== loop) {
2509				this.options.loop = loop;
2510				this._updateButtons();
2511				this._trigger($.jPlayer.event.repeat);
2512			}
2513		},
2514
2515		// Options code adapted from ui.widget.js (1.8.7).  Made changes so the key can use dot notation. To match previous getData solution in jPlayer 1.
2516		option: function(key, value) {
2517			var options = key;
2518
2519			 // Enables use: options().  Returns a copy of options object
2520			if ( arguments.length === 0 ) {
2521				return $.extend( true, {}, this.options );
2522			}
2523
2524			if(typeof key === "string") {
2525				var keys = key.split(".");
2526
2527				 // Enables use: options("someOption")  Returns a copy of the option. Supports dot notation.
2528				if(value === undefined) {
2529
2530					var opt = $.extend(true, {}, this.options);
2531					for(var i = 0; i < keys.length; i++) {
2532						if(opt[keys[i]] !== undefined) {
2533							opt = opt[keys[i]];
2534						} else {
2535							this._warning( {
2536								type: $.jPlayer.warning.OPTION_KEY,
2537								context: key,
2538								message: $.jPlayer.warningMsg.OPTION_KEY,
2539								hint: $.jPlayer.warningHint.OPTION_KEY
2540							});
2541							return undefined;
2542						}
2543					}
2544					return opt;
2545				}
2546
2547				 // Enables use: options("someOptionObject", someObject}).  Creates: {someOptionObject:someObject}
2548				 // Enables use: options("someOption", someValue).  Creates: {someOption:someValue}
2549				 // Enables use: options("someOptionObject.someOption", someValue).  Creates: {someOptionObject:{someOption:someValue}}
2550
2551				options = {};
2552				var opts = options;
2553
2554				for(var j = 0; j < keys.length; j++) {
2555					if(j < keys.length - 1) {
2556						opts[keys[j]] = {};
2557						opts = opts[keys[j]];
2558					} else {
2559						opts[keys[j]] = value;
2560					}
2561				}
2562			}
2563
2564			 // Otherwise enables use: options(optionObject).  Uses original object (the key)
2565
2566			this._setOptions(options);
2567
2568			return this;
2569		},
2570		_setOptions: function(options) {
2571			var self = this;
2572			$.each(options, function(key, value) { // This supports the 2 level depth that the options of jPlayer has. Would review if we ever need more depth.
2573				self._setOption(key, value);
2574			});
2575
2576			return this;
2577		},
2578		_setOption: function(key, value) {
2579			var self = this;
2580
2581			// The ability to set options is limited at this time.
2582
2583			switch(key) {
2584				case "volume" :
2585					this.volume(value);
2586					break;
2587				case "muted" :
2588					this._muted(value);
2589					break;
2590				case "globalVolume" :
2591					this.options[key] = value;
2592					break;
2593				case "cssSelectorAncestor" :
2594					this._cssSelectorAncestor(value); // Set and refresh all associations for the new ancestor.
2595					break;
2596				case "cssSelector" :
2597					$.each(value, function(fn, cssSel) {
2598						self._cssSelector(fn, cssSel); // NB: The option is set inside this function, after further validity checks.
2599					});
2600					break;
2601				case "playbackRate" :
2602					this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate, this.options.maxPlaybackRate);
2603					if(this.html.used) {
2604						this._html_setProperty('playbackRate', value);
2605					}
2606					this._updatePlaybackRate();
2607					break;
2608				case "defaultPlaybackRate" :
2609					this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate, this.options.maxPlaybackRate);
2610					if(this.html.used) {
2611						this._html_setProperty('defaultPlaybackRate', value);
2612					}
2613					this._updatePlaybackRate();
2614					break;
2615				case "minPlaybackRate" :
2616					this.options[key] = value = this._limitValue(value, 0.1, this.options.maxPlaybackRate - 0.1);
2617					this._updatePlaybackRate();
2618					break;
2619				case "maxPlaybackRate" :
2620					this.options[key] = value = this._limitValue(value, this.options.minPlaybackRate + 0.1, 16);
2621					this._updatePlaybackRate();
2622					break;
2623				case "fullScreen" :
2624					if(this.options[key] !== value) { // if changed
2625						var wkv = $.jPlayer.nativeFeatures.fullscreen.used.webkitVideo;
2626						if(!wkv || wkv && !this.status.waitForPlay) {
2627							if(!wkv) { // No sensible way to unset option on these devices.
2628								this.options[key] = value;
2629							}
2630							if(value) {
2631								this._requestFullscreen();
2632							} else {
2633								this._exitFullscreen();
2634							}
2635							if(!wkv) {
2636								this._setOption("fullWindow", value);
2637							}
2638						}
2639					}
2640					break;
2641				case "fullWindow" :
2642					if(this.options[key] !== value) { // if changed
2643						this._removeUiClass();
2644						this.options[key] = value;
2645						this._refreshSize();
2646					}
2647					break;
2648				case "size" :
2649					if(!this.options.fullWindow && this.options[key].cssClass !== value.cssClass) {
2650						this._removeUiClass();
2651					}
2652					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2653					this._refreshSize();
2654					break;
2655				case "sizeFull" :
2656					if(this.options.fullWindow && this.options[key].cssClass !== value.cssClass) {
2657						this._removeUiClass();
2658					}
2659					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2660					this._refreshSize();
2661					break;
2662				case "autohide" :
2663					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2664					this._updateAutohide();
2665					break;
2666				case "loop" :
2667					this._loop(value);
2668					break;
2669				case "remainingDuration" :
2670					this.options[key] = value;
2671					this._updateInterface();
2672					break;
2673				case "toggleDuration" :
2674					this.options[key] = value;
2675					break;
2676				case "nativeVideoControls" :
2677					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2678					this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls);
2679					this._restrictNativeVideoControls();
2680					this._updateNativeVideoControls();
2681					break;
2682				case "noFullWindow" :
2683					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2684					this.status.nativeVideoControls = this._uaBlocklist(this.options.nativeVideoControls); // Need to check again as noFullWindow can depend on this flag and the restrict() can override it.
2685					this.status.noFullWindow = this._uaBlocklist(this.options.noFullWindow);
2686					this._restrictNativeVideoControls();
2687					this._updateButtons();
2688					break;
2689				case "noVolume" :
2690					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2691					this.status.noVolume = this._uaBlocklist(this.options.noVolume);
2692					this._updateVolume();
2693					this._updateMute();
2694					break;
2695				case "emulateHtml" :
2696					if(this.options[key] !== value) { // To avoid multiple event handlers being created, if true already.
2697						this.options[key] = value;
2698						if(value) {
2699							this._emulateHtmlBridge();
2700						} else {
2701							this._destroyHtmlBridge();
2702						}
2703					}
2704					break;
2705				case "timeFormat" :
2706					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
2707					break;
2708				case "keyEnabled" :
2709					this.options[key] = value;
2710					if(!value && this === $.jPlayer.focus) {
2711						$.jPlayer.focus = null;
2712					}
2713					break;
2714				case "keyBindings" :
2715					this.options[key] = $.extend(true, {}, this.options[key], value); // store a merged DEEP copy of it, incase not all properties changed.
2716					break;
2717				case "audioFullScreen" :
2718					this.options[key] = value;
2719					break;
2720				case "autoBlur" :
2721					this.options[key] = value;
2722					break;
2723			}
2724
2725			return this;
2726		},
2727		// End of: (Options code adapted from ui.widget.js)
2728
2729		_refreshSize: function() {
2730			this._setSize(); // update status and jPlayer element size
2731			this._addUiClass(); // update the ui class
2732			this._updateSize(); // update internal sizes
2733			this._updateButtons();
2734			this._updateAutohide();
2735			this._trigger($.jPlayer.event.resize);
2736		},
2737		_setSize: function() {
2738			// Determine the current size from the options
2739			if(this.options.fullWindow) {
2740				this.status.width = this.options.sizeFull.width;
2741				this.status.height = this.options.sizeFull.height;
2742				this.status.cssClass = this.options.sizeFull.cssClass;
2743			} else {
2744				this.status.width = this.options.size.width;
2745				this.status.height = this.options.size.height;
2746				this.status.cssClass = this.options.size.cssClass;
2747			}
2748
2749			// Set the size of the jPlayer area.
2750			this.element.css({'width': this.status.width, 'height': this.status.height});
2751		},
2752		_addUiClass: function() {
2753			if(this.ancestorJq.length) {
2754				this.ancestorJq.addClass(this.status.cssClass);
2755			}
2756		},
2757		_removeUiClass: function() {
2758			if(this.ancestorJq.length) {
2759				this.ancestorJq.removeClass(this.status.cssClass);
2760			}
2761		},
2762		_updateSize: function() {
2763			// The poster uses show/hide so can simply resize it.
2764			this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height});
2765
2766			// Video html or flash resized if necessary at this time, or if native video controls being used.
2767			if(!this.status.waitForPlay && this.html.active && this.status.video || this.html.video.available && this.html.used && this.status.nativeVideoControls) {
2768				this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
2769			}
2770			else if(!this.status.waitForPlay && this.flash.active && this.status.video) {
2771				this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height});
2772			}
2773		},
2774		_updateAutohide: function() {
2775			var	self = this,
2776				event = "mousemove.jPlayer",
2777				namespace = ".jPlayerAutohide",
2778				eventType = event + namespace,
2779				handler = function(event) {
2780					var moved = false,
2781						deltaX, deltaY;
2782					if(typeof self.internal.mouse !== "undefined") {
2783						//get the change from last position to this position
2784						deltaX = self.internal.mouse.x - event.pageX;
2785						deltaY = self.internal.mouse.y - event.pageY;
2786						moved = (Math.floor(deltaX) > 0) || (Math.floor(deltaY)>0); 
2787					} else {
2788						moved = true;
2789					}
2790					// store current position for next method execution
2791					self.internal.mouse = {
2792							x : event.pageX,
2793							y : event.pageY
2794					};
2795					// if mouse has been actually moved, do the gui fadeIn/fadeOut
2796					if (moved) {
2797						self.css.jq.gui.fadeIn(self.options.autohide.fadeIn, function() {
2798							clearTimeout(self.internal.autohideId);
2799							self.internal.autohideId = setTimeout( function() {
2800								self.css.jq.gui.fadeOut(self.options.autohide.fadeOut);
2801							}, self.options.autohide.hold);
2802						});
2803					}
2804				};
2805
2806			if(this.css.jq.gui.length) {
2807
2808				// End animations first so that its callback is executed now.
2809				// Otherwise an in progress fadeIn animation still has the callback to fadeOut again.
2810				this.css.jq.gui.stop(true, true);
2811
2812				// Removes the fadeOut operation from the fadeIn callback.
2813				clearTimeout(this.internal.autohideId);
2814				// undefine mouse
2815				delete this.internal.mouse;
2816
2817				this.element.unbind(namespace);
2818				this.css.jq.gui.unbind(namespace);
2819
2820				if(!this.status.nativeVideoControls) {
2821					if(this.options.fullWindow && this.options.autohide.full || !this.options.fullWindow && this.options.autohide.restored) {
2822						this.element.bind(eventType, handler);
2823						this.css.jq.gui.bind(eventType, handler);
2824						this.css.jq.gui.hide();
2825					} else {
2826						this.css.jq.gui.show();
2827					}
2828				} else {
2829					this.css.jq.gui.hide();
2830				}
2831			}
2832		},
2833		fullScreen: function(event) {
2834			var guiAction = typeof event === "object"; // Flags GUI click events so we know this was not a direct command, but an action taken by the user on the GUI.
2835			if(guiAction && this.options.useStateClassSkin && this.options.fullScreen) {
2836				this._setOption("fullScreen", false);
2837			} else {
2838				this._setOption("fullScreen", true);
2839			}
2840		},
2841		restoreScreen: function() {
2842			this._setOption("fullScreen", false);
2843		},
2844		_fullscreenAddEventListeners: function() {
2845			var self = this,
2846				fs = $.jPlayer.nativeFeatures.fullscreen;
2847
2848			if(fs.api.fullscreenEnabled) {
2849				if(fs.event.fullscreenchange) {
2850					// Create the event handler function and store it for removal.
2851					if(typeof this.internal.fullscreenchangeHandler !== 'function') {
2852						this.internal.fullscreenchangeHandler = function() {
2853							self._fullscreenchange();
2854						};
2855					}
2856					document.addEventListener(fs.event.fullscreenchange, this.internal.fullscreenchangeHandler, false);
2857				}
2858				// No point creating handler for fullscreenerror.
2859				// Either logic avoids fullscreen occurring (w3c/moz), or their is no event on the browser (webkit).
2860			}
2861		},
2862		_fullscreenRemoveEventListeners: function() {
2863			var fs = $.jPlayer.nativeFeatures.fullscreen;
2864			if(this.internal.fullscreenchangeHandler) {
2865				document.removeEventListener(fs.event.fullscreenchange, this.internal.fullscreenchangeHandler, false);
2866			}
2867		},
2868		_fullscreenchange: function() {
2869			// If nothing is fullscreen, then we cannot be in fullscreen mode.
2870			if(this.options.fullScreen && !$.jPlayer.nativeFeatures.fullscreen.api.fullscreenElement()) {
2871				this._setOption("fullScreen", false);
2872			}
2873		},
2874		_requestFullscreen: function() {
2875			// Either the container or the jPlayer div
2876			var e = this.ancestorJq.length ? this.ancestorJq[0] : this.element[0],
2877				fs = $.jPlayer.nativeFeatures.fullscreen;
2878
2879			// This method needs the video element. For iOS and Android.
2880			if(fs.used.webkitVideo) {
2881				e = this.htmlElement.video;
2882			}
2883
2884			if(fs.api.fullscreenEnabled) {
2885				fs.api.requestFullscreen(e);
2886			}
2887		},
2888		_exitFullscreen: function() {
2889
2890			var fs = $.jPlayer.nativeFeatures.fullscreen,
2891				e;
2892
2893			// This method needs the video element. For iOS and Android.
2894			if(fs.used.webkitVideo) {
2895				e = this.htmlElement.video;
2896			}
2897
2898			if(fs.api.fullscreenEnabled) {
2899				fs.api.exitFullscreen(e);
2900			}
2901		},
2902		_html_initMedia: function(media) {
2903			// Remove any existing track elements
2904			var $media = $(this.htmlElement.media).empty();
2905
2906			// Create any track elements given with the media, as an Array of track Objects.
2907			$.each(media.track || [], function(i,v) {
2908				var track = document.createElement('track');
2909				track.setAttribute("kind", v.kind ? v.kind : "");
2910				track.setAttribute("src", v.src ? v.src : "");
2911				track.setAttribute("srclang", v.srclang ? v.srclang : "");
2912				track.setAttribute("label", v.label ? v.label : "");
2913				if(v.def) {
2914					track.setAttribute("default", v.def);
2915				}
2916				$media.append(track);
2917			});
2918
2919			this.htmlElement.media.src = this.status.src;
2920
2921			if(this.options.preload !== 'none') {
2922				this._html_load(); // See function for comments
2923			}
2924			this._trigger($.jPlayer.event.timeupdate); // The flash generates this event for its solution.
2925		},
2926		_html_setFormat: function(media) {
2927			var self = this;
2928			// Always finds a format due to checks in setMedia()
2929			$.each(this.formats, function(priority, format) {
2930				if(self.html.support[format] && media[format]) {
2931					self.status.src = media[format];
2932					self.status.format[format] = true;
2933					self.status.formatType = format;
2934					return false;
2935				}
2936			});
2937		},
2938		_html_setAudio: function(media) {
2939			this._html_setFormat(media);
2940			this.htmlElement.media = this.htmlElement.audio;
2941			this._html_initMedia(media);
2942		},
2943		_html_setVideo: function(media) {
2944			this._html_setFormat(media);
2945			if(this.status.nativeVideoControls) {
2946				this.htmlElement.video.poster = this._validString(media.poster) ? media.poster : "";
2947			}
2948			this.htmlElement.media = this.htmlElement.video;
2949			this._html_initMedia(media);
2950		},
2951		_html_resetMedia: function() {
2952			if(this.htmlElement.media) {
2953				if(this.htmlElement.media.id === this.internal.video.id && !this.status.nativeVideoControls) {
2954					this.internal.video.jq.css({'width':'0px', 'height':'0px'});
2955				}
2956				this.htmlElement.media.pause();
2957			}
2958		},
2959		_html_clearMedia: function() {
2960			if(this.htmlElement.media) {
2961				this.htmlElement.media.src = "about:blank";
2962				// The following load() is only required for Firefox 3.6 (PowerMacs).
2963				// Recent HTMl5 browsers only require the src change. Due to changes in W3C spec and load() effect.
2964				this.htmlElement.media.load(); // Stops an old, "in progress" download from continuing the download. Triggers the loadstart, error and emptied events, due to the empty src. Also an abort event if a download was in progress.
2965			}
2966		},
2967		_html_load: function() {
2968			// This function remains to allow the early HTML5 browsers to work, such as Firefox 3.6
2969			// A change in the W3C spec for the media.load() command means that this is no longer necessary.
2970			// This command should be removed and actually causes minor undesirable effects on some browsers. Such as loading the whole file and not only the metadata.
2971			if(this.status.waitForLoad) {
2972				this.status.waitForLoad = false;
2973				this.htmlElement.media.load();
2974			}
2975			clearTimeout(this.internal.htmlDlyCmdId);
2976		},
2977		_html_play: function(time) {
2978			var self = this,
2979				media = this.htmlElement.media;
2980
2981			this.androidFix.pause = false; // Cancel the pause fix.
2982
2983			this._html_load(); // Loads if required and clears any delayed commands.
2984
2985			// Setup the Android Fix.
2986			if(this.androidFix.setMedia) {
2987				this.androidFix.play = true;
2988				this.androidFix.time = time;
2989
2990			} else if(!isNaN(time)) {
2991
2992				// Attempt to play it, since iOS has been ignoring commands
2993				if(this.internal.cmdsIgnored) {
2994					media.play();
2995				}
2996
2997				try {
2998					// !media.seekable is for old HTML5 browsers, like Firefox 3.6.
2999					// Checking seekable.length is important for iOS6 to work with setMedia().play(time)
3000					if(!media.seekable || typeof media.seekable === "object" && media.seekable.length > 0) {
3001						media.currentTime = time;
3002						media.play();
3003					} else {
3004						throw 1;
3005					}
3006				} catch(err) {
3007					this.internal.htmlDlyCmdId = setTimeout(function() {
3008						self.play(time);
3009					}, 250);
3010					return; // Cancel execution and wait for the delayed command.
3011				}
3012			} else {
3013				media.play();
3014			}
3015			this._html_checkWaitForPlay();
3016		},
3017		_html_pause: function(time) {
3018			var self = this,
3019				media = this.htmlElement.media;
3020
3021			this.androidFix.play = false; // Cancel the play fix.
3022
3023			if(time > 0) { // We do not want the stop() command, which does pause(0), causing a load operation.
3024				this._html_load(); // Loads if required and clears any delayed commands.
3025			} else {
3026				clearTimeout(this.internal.htmlDlyCmdId);
3027			}
3028
3029			// Order of these commands is important for Safari (Win) and IE9. Pause then change currentTime.
3030			media.pause();
3031
3032			// Setup the Android Fix.
3033			if(this.androidFix.setMedia) {
3034				this.androidFix.pause = true;
3035				this.androidFix.time = time;
3036
3037			} else if(!isNaN(time)) {
3038				try {
3039					if(!media.seekable || typeof media.seekable === "object" && media.seekable.length > 0) {
3040						media.currentTime = time;
3041					} else {
3042						throw 1;
3043					}
3044				} catch(err) {
3045					this.internal.htmlDlyCmdId = setTimeout(function() {
3046						self.pause(time);
3047					}, 250);
3048					return; // Cancel execution and wait for the delayed command.
3049				}
3050			}
3051			if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
3052				this._html_checkWaitForPlay();
3053			}
3054		},
3055		_html_playHead: function(percent) {
3056			var self = this,
3057				media = this.htmlElement.media;
3058
3059			this._html_load(); // Loads if required and clears any delayed commands.
3060
3061			// This playHead() method needs a refactor to apply the android fix.
3062
3063			try {
3064				if(typeof media.seekable === "object" && media.seekable.length > 0) {
3065					media.currentTime = percent * media.seekable.end(media.seekable.length-1) / 100;
3066				} else if(media.duration > 0 && !isNaN(media.duration)) {
3067					media.currentTime = percent * media.duration / 100;
3068				} else {
3069					throw "e";
3070				}
3071			} catch(err) {
3072				this.internal.htmlDlyCmdId = setTimeout(function() {
3073					self.playHead(percent);
3074				}, 250);
3075				return; // Cancel execution and wait for the delayed command.
3076			}
3077			if(!this.status.waitForLoad) {
3078				this._html_checkWaitForPlay();
3079			}
3080		},
3081		_html_checkWaitForPlay: function() {
3082			if(this.status.waitForPlay) {
3083				this.status.waitForPlay = false;
3084				if(this.css.jq.videoPlay.length) {
3085					this.css.jq.videoPlay.hide();
3086				}
3087				if(this.status.video) {
3088					this.internal.poster.jq.hide();
3089					this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
3090				}
3091			}
3092		},
3093		_html_setProperty: function(property, value) {
3094			if(this.html.audio.available) {
3095				this.htmlElement.audio[property] = value;
3096			}
3097			if(this.html.video.available) {
3098				this.htmlElement.video[property] = value;
3099			}
3100		},
3101		_aurora_setAudio: function(media) {
3102			var self = this;            
3103			
3104			// Always finds a format due to checks in setMedia()
3105			$.each(this.formats, function(priority, format) {
3106				if(self.aurora.support[format] && media[format]) {
3107					self.status.src = media[format];
3108					self.status.format[format] = true;
3109					self.status.formatType = format;
3110			
3111					return false;
3112				}
3113			});
3114			
3115			this.aurora.player = new AV.Player.fromURL(this.status.src);
3116			this._addAuroraEventListeners(this.aurora.player, this.aurora);
3117
3118			if(this.options.preload === 'auto') {
3119				this._aurora_load();
3120				this.status.waitForLoad = false;
3121			}
3122		},
3123		_aurora_resetMedia: function() {
3124			if (this.aurora.player) {
3125				this.aurora.player.stop();
3126			}
3127		},
3128		_aurora_clearMedia: function() {
3129			// Nothing to clear.
3130		},
3131		_aurora_load: function() {
3132			if(this.status.waitForLoad) {
3133				this.status.waitForLoad = false;
3134				this.aurora.player.preload();
3135			}
3136		},
3137		_aurora_play: function(time) {
3138			if (!this.status.waitForLoad) {
3139				if (!isNaN(time)) {
3140					this.aurora.player.seek(time);
3141				}
3142			}
3143			if (!this.aurora.player.playing) {
3144				this.aurora.player.play();
3145			}
3146			this.status.waitForLoad = false;
3147			this._aurora_checkWaitForPlay();
3148			
3149			// No event from the player, update UI now.
3150			this._updateButtons(true);
3151			this._trigger($.jPlayer.event.play);
3152		},
3153		_aurora_pause: function(time) {
3154			if (!isNaN(time)) {
3155				this.aurora.player.seek(time * 1000);
3156			}
3157			this.aurora.player.pause();
3158			
3159			if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
3160				this._aurora_checkWaitForPlay();
3161			}
3162			
3163			// No event from the player, update UI now.
3164			this._updateButtons(false);
3165			this._trigger($.jPlayer.event.pause);
3166		},
3167		_aurora_playHead: function(percent) {
3168			if(this.aurora.player.duration > 0) {
3169				// The seek() sould be in milliseconds, but the only codec that works with seek (aac.js) uses seconds.
3170				this.aurora.player.seek(percent * this.aurora.player.duration / 100); // Using seconds
3171			}
3172				
3173			if(!this.status.waitForLoad) {
3174				this._aurora_checkWaitForPlay();
3175			}
3176		},
3177		_aurora_checkWaitForPlay: function() {
3178			if(this.status.waitForPlay) {
3179				this.status.waitForPlay = false;
3180			}
3181		},
3182		_aurora_volume: function(v) {
3183			this.aurora.player.volume = v * 100;
3184		},
3185		_aurora_mute: function(m) {
3186			if (m) {
3187				this.aurora.properties.lastvolume = this.aurora.player.volume;
3188				this.aurora.player.volume = 0;
3189			} else {
3190				this.aurora.player.volume = this.aurora.properties.lastvolume;
3191			}
3192			this.aurora.properties.muted = m;
3193		},
3194		_flash_setAudio: function(media) {
3195			var self = this;
3196			try {
3197				// Always finds a format due to checks in setMedia()
3198				$.each(this.formats, function(priority, format) {
3199					if(self.flash.support[format] && media[format]) {
3200						switch (format) {
3201							case "m4a" :
3202							case "fla" :
3203								self._getMovie().fl_setAudio_m4a(media[format]);
3204								break;
3205							case "mp3" :
3206								self._getMovie().fl_setAudio_mp3(media[format]);
3207								break;
3208							case "rtmpa":
3209								self._getMovie().fl_setAudio_rtmp(media[format]);
3210								break;
3211						}
3212						self.status.src = media[format];
3213						self.status.format[format] = true;
3214						self.status.formatType = format;
3215						return false;
3216					}
3217				});
3218
3219				if(this.options.preload === 'auto') {
3220					this._flash_load();
3221					this.status.waitForLoad = false;
3222				}
3223			} catch(err) { this._flashError(err); }
3224		},
3225		_flash_setVideo: function(media) {
3226			var self = this;
3227			try {
3228				// Always finds a format due to checks in setMedia()
3229				$.each(this.formats, function(priority, format) {
3230					if(self.flash.support[format] && media[format]) {
3231						switch (format) {
3232							case "m4v" :
3233							case "flv" :
3234								self._getMovie().fl_setVideo_m4v(media[format]);
3235								break;
3236							case "rtmpv":
3237								self._getMovie().fl_setVideo_rtmp(media[format]);
3238								break;		
3239						}
3240						self.status.src = media[format];
3241						self.status.format[format] = true;
3242						self.status.formatType = format;
3243						return false;
3244					}
3245				});
3246
3247				if(this.options.preload === 'auto') {
3248					this._flash_load();
3249					this.status.waitForLoad = false;
3250				}
3251			} catch(err) { this._flashError(err); }
3252		},
3253		_flash_resetMedia: function() {
3254			this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Must do via CSS as setting attr() to zero causes a jQuery error in IE.
3255			this._flash_pause(NaN);
3256		},
3257		_flash_clearMedia: function() {
3258			try {
3259				this._getMovie().fl_clearMedia();
3260			} catch(err) { this._flashError(err); }
3261		},
3262		_flash_load: function() {
3263			try {
3264				this._getMovie().fl_load();
3265			} catch(err) { this._flashError(err); }
3266			this.status.waitForLoad = false;
3267		},
3268		_flash_play: function(time) {
3269			try {
3270				this._getMovie().fl_play(time);
3271			} catch(err) { this._flashError(err); }
3272			this.status.waitForLoad = false;
3273			this._flash_checkWaitForPlay();
3274		},
3275		_flash_pause: function(time) {
3276			try {
3277				this._getMovie().fl_pause(time);
3278			} catch(err) { this._flashError(err); }
3279			if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
3280				this.status.waitForLoad = false;
3281				this._flash_checkWaitForPlay();
3282			}
3283		},
3284		_flash_playHead: function(p) {
3285			try {
3286				this._getMovie().fl_play_head(p);
3287			} catch(err) { this._flashError(err); }
3288			if(!this.status.waitForLoad) {
3289				this._flash_checkWaitForPlay();
3290			}
3291		},
3292		_flash_checkWaitForPlay: function() {
3293			if(this.status.waitForPlay) {
3294				this.status.waitForPlay = false;
3295				if(this.css.jq.videoPlay.length) {
3296					this.css.jq.videoPlay.hide();
3297				}
3298				if(this.status.video) {
3299					this.internal.poster.jq.hide();
3300					this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height});
3301				}
3302			}
3303		},
3304		_flash_volume: function(v) {
3305			try {
3306				this._getMovie().fl_volume(v);
3307			} catch(err) { this._flashError(err); }
3308		},
3309		_flash_mute: function(m) {
3310			try {
3311				this._getMovie().fl_mute(m);
3312			} catch(err) { this._flashError(err); }
3313		},
3314		_getMovie: function() {
3315			return document[this.internal.flash.id];
3316		},
3317		_getFlashPluginVersion: function() {
3318
3319			// _getFlashPluginVersion() code influenced by:
3320			// - FlashReplace 1.01: http://code.google.com/p/flashreplace/
3321			// - SWFObject 2.2: http://code.google.com/p/swfobject/
3322
3323			var version = 0,
3324				flash;
3325			if(window.ActiveXObject) {
3326				try {
3327					flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
3328					if (flash) { // flash will return null when ActiveX is disabled
3329						var v = flash.GetVariable("$version");
3330						if(v) {
3331							v = v.split(" ")[1].split(",");
3332							version = parseInt(v[0], 10) + "." + parseInt(v[1], 10);
3333						}
3334					}
3335				} catch(e) {}
3336			}
3337			else if(navigator.plugins && navigator.mimeTypes.length > 0) {
3338				flash = navigator.plugins["Shockwave Flash"];
3339				if(flash) {
3340					version = navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/, "$1");
3341				}
3342			}
3343			return version * 1; // Converts to a number
3344		},
3345		_checkForFlash: function (version) {
3346			var flashOk = false;
3347			if(this._getFlashPluginVersion() >= version) {
3348				flashOk = true;
3349			}
3350			return flashOk;
3351		},
3352		_validString: function(url) {
3353			return (url && typeof url === "string"); // Empty strings return false
3354		},
3355		_limitValue: function(value, min, max) {
3356			return (value < min) ? min : ((value > max) ? max : value);
3357		},
3358		_urlNotSetError: function(context) {
3359			this._error( {
3360				type: $.jPlayer.error.URL_NOT_SET,
3361				context: context,
3362				message: $.jPlayer.errorMsg.URL_NOT_SET,
3363				hint: $.jPlayer.errorHint.URL_NOT_SET
3364			});
3365		},
3366		_flashError: function(error) {
3367			var errorType;
3368			if(!this.internal.ready) {
3369				errorType = "FLASH";
3370			} else {
3371				errorType = "FLASH_DISABLED";
3372			}
3373			this._error( {
3374				type: $.jPlayer.error[errorType],
3375				context: this.internal.flash.swf,
3376				message: $.jPlayer.errorMsg[errorType] + error.message,
3377				hint: $.jPlayer.errorHint[errorType]
3378			});
3379			// Allow the audio player to recover if display:none and then shown again, or with position:fixed on Firefox.
3380			// This really only affects audio in a media player, as an audio player could easily move the jPlayer element away from such issues.
3381			this.internal.flash.jq.css({'width':'1px', 'height':'1px'});
3382		},
3383		_error: function(error) {
3384			this._trigger($.jPlayer.event.error, error);
3385			if(this.options.errorAlerts) {
3386				this._alert("Error!" + (error.message ? "\n" + error.message : "") + (error.hint ? "\n" + error.hint : "") + "\nContext: " + error.context);
3387			}
3388		},
3389		_warning: function(warning) {
3390			this._trigger($.jPlayer.event.warning, undefined, warning);
3391			if(this.options.warningAlerts) {
3392				this._alert("Warning!" + (warning.message ? "\n" + warning.message : "") + (warning.hint ? "\n" + warning.hint : "") + "\nContext: " + warning.context);
3393			}
3394		},
3395		_alert: function(message) {
3396			var msg = "jPlayer " + this.version.script + " : id='" + this.internal.self.id +"' : " + message;
3397			if(!this.options.consoleAlerts) {
3398				alert(msg);
3399			} else if(window.console && window.console.log) {
3400				window.console.log(msg);
3401			}
3402		},
3403		_emulateHtmlBridge: function() {
3404			var self = this;
3405
3406			// Emulate methods on jPlayer's DOM element.
3407			$.each( $.jPlayer.emulateMethods.split(/\s+/g), function(i, name) {
3408				self.internal.domNode[name] = function(arg) {
3409					self[name](arg);
3410				};
3411
3412			});
3413
3414			// Bubble jPlayer events to its DOM element.
3415			$.each($.jPlayer.event, function(eventName,eventType) {
3416				var nativeEvent = true;
3417				$.each( $.jPlayer.reservedEvent.split(/\s+/g), function(i, name) {
3418					if(name === eventName) {
3419						nativeEvent = false;
3420						return false;
3421					}
3422				});
3423				if(nativeEvent) {
3424					self.element.bind(eventType + ".jPlayer.jPlayerHtml", function() { // With .jPlayer & .jPlayerHtml namespaces.
3425						self._emulateHtmlUpdate();
3426						var domEvent = document.createEvent("Event");
3427						domEvent.initEvent(eventName, false, true);
3428						self.internal.domNode.dispatchEvent(domEvent);
3429					});
3430				}
3431				// The error event would require a special case
3432			});
3433
3434			// IE9 has a readyState property on all elements. The document should have it, but all (except media) elements inherit it in IE9. This conflicts with Popcorn, which polls the readyState.
3435		},
3436		_emulateHtmlUpdate: function() {
3437			var self = this;
3438
3439			$.each( $.jPlayer.emulateStatus.split(/\s+/g), function(i, name) {
3440				self.internal.domNode[name] = self.status[name];
3441			});
3442			$.each( $.jPlayer.emulateOptions.split(/\s+/g), function(i, name) {
3443				self.internal.domNode[name] = self.options[name];
3444			});
3445		},
3446		_destroyHtmlBridge: function() {
3447			var self = this;
3448
3449			// Bridge event handlers are also removed by destroy() through .jPlayer namespace.
3450			this.element.unbind(".jPlayerHtml"); // Remove all event handlers created by the jPlayer bridge. So you can change the emulateHtml option.
3451
3452			// Remove the methods and properties
3453			var emulated = $.jPlayer.emulateMethods + " " + $.jPlayer.emulateStatus + " " + $.jPlayer.emulateOptions;
3454			$.each( emulated.split(/\s+/g), function(i, name) {
3455				delete self.internal.domNode[name];
3456			});
3457		}
3458	};
3459
3460	$.jPlayer.error = {
3461		FLASH: "e_flash",
3462		FLASH_DISABLED: "e_flash_disabled",
3463		NO_SOLUTION: "e_no_solution",
3464		NO_SUPPORT: "e_no_support",
3465		URL: "e_url",
3466		URL_NOT_SET: "e_url_not_set",
3467		VERSION: "e_version"
3468	};
3469
3470	$.jPlayer.errorMsg = {
3471		FLASH: "jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ", // Used in: _flashError()
3472		FLASH_DISABLED: "jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ", // Used in: _flashError()
3473		NO_SOLUTION: "No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.", // Used in: _init()
3474		NO_SUPPORT: "It is not possible to play any media format provided in setMedia() on this browser using your current options.", // Used in: setMedia()
3475		URL: "Media URL could not be loaded.", // Used in: jPlayerFlashEvent() and _addHtmlEventListeners()
3476		URL_NOT_SET: "Attempt to issue media playback commands, while no media url is set.", // Used in: load(), play(), pause(), stop() and playHead()
3477		VERSION: "jPlayer " + $.jPlayer.prototype.version.script + " needs Jplayer.swf version " + $.jPlayer.prototype.version.needFlash + " but found " // Used in: jPlayerReady()
3478	};
3479
3480	$.jPlayer.errorHint = {
3481		FLASH: "Check your swfPath option and that Jplayer.swf is there.",
3482		FLASH_DISABLED: "Check that you have not display:none; the jPlayer entity or any ancestor.",
3483		NO_SOLUTION: "Review the jPlayer options: support and supplied.",
3484		NO_SUPPORT: "Video or audio formats defined in the supplied option are missing.",
3485		URL: "Check media URL is valid.",
3486		URL_NOT_SET: "Use setMedia() to set the media URL.",
3487		VERSION: "Update jPlayer files."
3488	};
3489
3490	$.jPlayer.warning = {
3491		CSS_SELECTOR_COUNT: "e_css_selector_count",
3492		CSS_SELECTOR_METHOD: "e_css_selector_method",
3493		CSS_SELECTOR_STRING: "e_css_selector_string",
3494		OPTION_KEY: "e_option_key"
3495	};
3496
3497	$.jPlayer.warningMsg = {
3498		CSS_SELECTOR_COUNT: "The number of css selectors found did not equal one: ",
3499		CSS_SELECTOR_METHOD: "The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",
3500		CSS_SELECTOR_STRING: "The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",
3501		OPTION_KEY: "The option requested in jPlayer('option') is undefined."
3502	};
3503
3504	$.jPlayer.warningHint = {
3505		CSS_SELECTOR_COUNT: "Check your css selector and the ancestor.",
3506		CSS_SELECTOR_METHOD: "Check your method name.",
3507		CSS_SELECTOR_STRING: "Check your css selector is a string.",
3508		OPTION_KEY: "Check your option name."
3509	};
3510}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.