/*
unFocus.EventManager, version 1.0 (2007/09/11)
Copyright: 2005-2007, Kevin Newman (http://www.unfocus.com/Projects/)

This file is part of unFocus.History Keeper.

unFocus.History Keeper is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at your option) any later version.

unFocus.History Keeper is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
// Package: unFocus.Utilities
// make sure faux-namespace is available before adding to it
if (!window.unFocus) var unFocus = {};

/** Class: EventManager
 *	Provides the interface and functionality to a Subscriber/Subscriber Pattern.
 * 
 **/
/*
Constructor: EventManager
	The Constructor (Prototype) function.

Parameters:
	[type1 [, type2 [, etc.]]] - Optionally sets up an empty array for each named event.
*/
unFocus.EventManager = function() {
	this._listeners = {};
	for (var i = 0; i < arguments.length; i++) {
		this._listeners[arguments[i]] = [];
	}
};

unFocus.EventManager.prototype = {
	/*
	Method: addEventListener
		Adds an event listener to the specified type.
	
	Parameters:
		$name		- The event name.
		$listener	- The function to be called when the event fires.
	*/
	addEventListener: function($name, $listener) {
		// check that listener is not in list
		for (var i = 0; i < this._listeners[$name].length; i++)
			if (this._listeners[$name][i] == $listener) return;
		// add listener to appropriate list
		this._listeners[$name].push($listener);
	},
	/*
	Method: removeEventListener
		Removes an event listener.
	
	Parameters:
		$name		- The event name.
		$listener	- The function to be removed.
	*/
	removeEventListener: function($name, $listener) {
		// search for the listener method
		for (var i = 0; i < this._listeners[$name].length; i++) {
			if (this._listeners[$name][i] == $listener) {
				this._listeners.splice(i,1);
				return;
			}
		}
	},
	/* Method: notifyListeners
		Notifies the listeners of an event.
	
	Parameters:
		$name	- The name of event to fire.
		$data	- The object to pass to the subscribed method (the Event Object).
	*/
	notifyListeners: function($name, $data) {
		for (var i = 0; i < this._listeners[$name].length; i++)
			this._listeners[$name][i]($data);
	}
};

/*
unFocus.History, version 2.0 (beta 1) (2009/04/15)
Copyright: 2005-2009, Kevin Newman (http://www.unfocus.com/)

This file is part of unFocus.History Keeper.

unFocus.History Keeper is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at your option) any later version.

unFocus.History Keeper is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
	Class: unFocus.History
		A singleton with subscriber interface (<unFocus.EventManager>) 
		that keeps a history and provides deep links for Flash and AJAX apps
*/
unFocus.History = (function() {

function Keeper() {
	
	var _this = this,
		// set the poll interval here.
		_pollInterval = 200, _intervalID,
		_currentHash;

	/*
	method: _getHash
		A private method that gets the Hash from the location.hash property.
	 
	returns:
		a string containing the current hash from the url
	*/
	var _getHash = function() {
		return location.hash.substring(1);
	};
	// get initial hash
	_currentHash = _getHash();
	
	/*
	method: _setHash
		A private method that sets the Hash on the location string (the current url).
	*/
	var _setHash = function($newHash) {
		window.location.hash = $newHash;
	};
	
	/*
	method: _watchHash
		A private method that is called every n miliseconds (<_pollInterval>) to check if the hash has changed.
		This is the primary Hash change detection method for most browsers. It doesn't work to detect the hash
		change in IE 5.5+ or various other browsers. Workarounds like the iframe method are used for those 
		browsers (IE 5.0 will use an anchor creation hack).
	*/
	function _watchHash() {
		var $newHash = _getHash();
		if (_currentHash != $newHash) {
			_currentHash = $newHash;
			_this.notifyListeners("historyChange", $newHash);
		}
	}
	// Put the hash check on a timer.
	if (setInterval) _intervalID = setInterval(_watchHash, _pollInterval);
	
	/*
	method: getCurrentBookmark
		A public method to retrieve the current history string.
	
	returns:
		The current History Hash
	*/
	_this.getCurrent = function() {
		return _currentHash;
	};
	
	/*
	method: addHistory
		A public method to add a new history, and set the deep link. This method should be given a string.
		It does no serialization.
	
	returns:
		Boolean - true if supported and set, false if not
	*/
	_this.addHistory = function addHistory($newHash) {
		if (_currentHash != $newHash) {
			_currentHash = $newHash;
			_setHash($newHash);
			_this.notifyListeners("historyChange",$newHash);
		}
		return true;
	};

	/**
	 * These are the platform specific override methods. Since some platforms (IE 5.5+, Safari)
	 * require almost completely different techniques to create history entries, browser detection is
	 * used and the appropriate method is created. The bugs these fixes address are very tied to the
	 * specific implementations of these browsers, and not necessarily the underlying html engines.
	 * Sometimes, bugs related to history management can be tied even to a specific skin in browsers
	 * like Opera.
	 */
	// Safari 2.04 and less (and WebKit less than 420 - these hacks are not needed by the most recent nightlies)
	// :TODO: consider whether this aught to check for Safari or WebKit - is this a safar problem, or a does it
	// happen in other WebKit based software? OmniWeb (WebKit 420+) seems to work, though there's a sync issue.
	if (/WebKit\/\d+/.test(navigator.appVersion) && navigator.appVersion.match(/WebKit\/(\d+)/)[1] < 420) {
		// this will hold the old history states, since they can't be reliably taken from the location object
		var _unFocusHistoryLength = history.length,
			_historyStates = {}, _form,
			_recentlyAdded = false;
		
		// Setting the hash directly in Safari seems to cause odd content refresh behavior.
		// We'll use a form to submit to a #hash location instead. I'm assuming this works,
		// since I saw it done this way in SwfAddress (gotta give credit where credit it due ;-) ).
		function _createSafariSetHashForm() {
			_form = document.createElement("form");
			_form.id = "unFocusHistoryForm";
			_form.method = "get";
			document.body.insertBefore(_form,document.body.firstChild);
		}
		
		// override the old _setHash method to use the new form
		_setHash = function($newHash) {
			_historyStates[_unFocusHistoryLength] = $newHash;
			_form.action = "#" + _getHash();
			_form.submit();
		};
		
		// override the old _getHash method, since Safari doesn't update location.hash (fixed in nightlies)
		_getHash = function() {
			return _historyStates[_unFocusHistoryLength];
		};
		
		// set initial history entry
		_historyStates[_unFocusHistoryLength] = _currentHash;
		
		function addHistorySafari($newHash) {
			if (_currentHash != $newHash) {
				_currentHash = $newHash;
				_unFocusHistoryLength = history.length+1;
				_recentlyAdded = true;
				_setHash($newHash);
				_this.notifyListeners("historyChange",$newHash);
				_recentlyAdded = false;
			}
			return true;
		}
		
		// provide alternative addHistory
		_this.addHistory = function($newHash) { // adds history and bookmark hash
			// setup the form fix
			_createSafariSetHashForm();
			
			// replace with slimmer version...
			// :TODO: rethink this - it's adding an extra scope to the chain, which might
			// actually cost more at runtime than a simple if statement. Can this be done
			// without adding to the scope chain? The replaced scope holds no values. Does
			// it keep it's place in the scope chain?
			_this.addHistory = addHistorySafari;
			
			// ...do first call
			return _this.addHistory($newHash);
		};
		function _watchHistoryLength() {
			if (!_recentlyAdded) {
				var _historyLength = history.length;
				if (_historyLength != _unFocusHistoryLength) {
					_unFocusHistoryLength = _historyLength;
					
					var $newHash = _getHash();
					if (_currentHash != $newHash) {
						_currentHash = $newHash;
						_this.notifyListeners("historyChange", $newHash);
					}
				}
			}
		};
		
		// since it doesn't work, might as well cancel the location.hash check
		clearInterval(_intervalID);
		// watch the history.length prop for changes instead
		_intervalID = setInterval(_watchHistoryLength, _pollInterval);
		
	// IE 5.5+ Windows
	} else if (typeof ActiveXObject != "undefined" && window.print && 
			   !window.opera && navigator.userAgent.match(/MSIE (\d+\.\d+)/)[1] >= 5.5) {
		
		// :HACK: Quick and dirty IE8 support (makes IE8 use standard timer method).
		if (navigator.userAgent.match(/MSIE (\d+\.\d+)/)[1] >= 8)
			return;
		
		/* iframe references */
		var _historyFrameObj, _historyFrameRef;
		
		/*
		method: _createHistoryFrame
			
			This is for IE only for now.
		*/
		function _createHistoryFrame() {
			var $historyFrameName = "unFocusHistoryFrame";
			_historyFrameObj = document.createElement("iframe");
			_historyFrameObj.setAttribute("name", $historyFrameName);
			_historyFrameObj.setAttribute("id", $historyFrameName);
			// :NOTE: _Very_ experimental
			_historyFrameObj.setAttribute("src", 'javascript:;');
			_historyFrameObj.style.position = "absolute";
			_historyFrameObj.style.top = "-900px";
			document.body.insertBefore(_historyFrameObj,document.body.firstChild);
			// get reference to the frame from frames array (needed for document.open)
			// :NOTE: there might be an issue with this according to quirksmode.org
			// http://www.quirksmode.org/js/iframe.html
			_historyFrameRef = frames[$historyFrameName];
			
			// add base history entry
			_createHistoryHTML(_currentHash, true);
		}
		
		/*
		method: _createHistoryHTML
			This is an alternative to <_setHistoryHTML> that is used by IE (and others if I can get it to work).
			This method will create the history page completely in memory, with no need to download a new file
			from the server.
		*/
		function _createHistoryHTML($newHash) {
			with (_historyFrameRef.document) {
				open("text/html");
				write("<html><head></head><body onl",
					'oad="parent.unFocus.History._updateFromHistory(\''+$newHash+'\');">',
					$newHash+"</body></html>");
				close();
			}
		}
		
		/*
		method: _updateFromHistory
			A private method that is meant to be called only from HistoryFrame.html.
			It is not meant to be used by an end user even though it is accessable as public.
		*/
			// hides the first call to the method, and sets up the real method for the rest of the calls
		function updateFromHistory($hash) {
			_currentHash = $hash;
			_this.notifyListeners("historyChange", $hash);
		}
		_this._updateFromHistory = function() {
			_this._updateFromHistory = updateFromHistory;
		};

		function addHistoryIE($newHash) { // adds history and bookmark hash
			if (_currentHash != $newHash) {
				// :NOTE: IE will create an entry if there is an achor on the page, but it
				// does not allow you to detect the state change.
				_currentHash = $newHash;
				// sets hash and notifies listeners
				_createHistoryHTML($newHash);
			}
			return true;
		};
		_this.addHistory = function($newHash) {
			// do initialization stuff on first call
			_createHistoryFrame();
			
			// replace this function with a slimmer one on first call
			_this.addHistory = addHistoryIE;
			// call the first call
			return _this.addHistory($newHash);
		};
		// anonymous method - subscribe to self to update the hash when the history is updated
		_this.addEventListener("historyChange", function($hash) { _setHash($hash) });
		
	}
}
Keeper.prototype = new unFocus.EventManager("historyChange");

return new Keeper();

})();


/*
Class: SwfHTML
	A class for assembling and outputting html for a Swf file.
	
References:
	<http://www.adobe.com/go/tn_12701>
	<http://www.adobe.com/go/tn_16588>
*/
unFocus.SwfHTML = function() {
	this._properties = {};
	this._params = {};
	this._flashvars = "";
	this._flashvarPairs = {};
	this._version = 0;
	this._majorRevision = 0;
	this._minorRevision = 0;
	this._betaVersion = 0;
	this._src = "";
};
// setters check against valid values http://www.adobe.com/go/tn_12701
unFocus.SwfHTML.prototype = {
	// Method: setSrc
	//	Sets the Src of the swf file.
	setSrc: function($src) {
		this._src = $src;
	},
	// Method: setWidth
	//	Sets the Width of the swf file.
	setWidth: function($width) {
		this._properties.width = $width;
	},
	setHeight: function($height) {
		this._properties.height = $height;
	},
	setId: function($id) {
		this._properties.id = $id;
	},
	getId: function() {
		return this._properties.id;
	},
	setName: function($name) {
		this._properties.name = $name;
	},
	
	setMovie: function($src) {
		this.setSrc($src);
	},
	setSwliveconnect: function($swliveconnect) {
		if (typeof $swliveconnect == "boolean")
			this._params.swliveconnect = $swliveconnect;
		else
			throw "SwfHTML.setSwliveconnect Error: Valid Values for swliveconnect: true, false";
	},
	setPlay: function($play) {
		if (typeof $play == "boolean")
			this._params.play= $play;
		else
			throw "SwfHTML.setPlay Error: Valid Values for play: true, false";
	},
	setLoop: function($loop) {
		if (typeof $loop == "boolean")
			this._params.loop= $loop;
		else
			throw "SwfHTML.setLoop Error: Valid Values for loop: true, false";
	},
	setMenu: function($menu) {
		if (typeof $menu == "boolean")
			this._params.menu= $menu;
		else
			throw "SwfHTML.setMenu Error: Valid Values for menu: true, false";
	},
	setQuality: function($quality) {
		switch ($quality.toLowerCase()) {
			case "low":
			case "medium":
			case "high":
			case "autolow":
			case "autohigh":
			case "best":
				this._params.quality = $quality; /* low, medium, high, autolow, autohigh, best */
				break;
			default:
				throw "SwfHTML.setQuality Error: Valid Values for quality: low, medium, high, autolow, autohigh, best";
		}
	},
	setScale: function($scale) {
		switch ($scale.toLowerCase()) {
			case "showall":
			case "noborder":
			case "exactfit":
			case "noscale":
				this._params.scale = $scale; /* showall, noborder, exactfit, noscale (missing from the documentation) */
				break;
			default:
				throw "SwfHTML.setScale Error: Valid Values for scale: showall, noborder, exactfit, noscale";
		}
	},
	setAlign: function($align) { // :NOTE: There is a conflict here - you can set align on the html element, as well as for the movie. Hhow does this sort out for embed?
		switch ($align.toLowerCase()) {
			case "l":
			case "t":
			case "r":
			case "b":
				this._params.align = $align; /* l, t, r, b (defaults to center, which isn't in the list) */
				break;
			default:
				throw "SwfHTML.setAlign Error: Valid Values for align: l, t, r, b";
		}
	},
	setSAlign: function($salign) {
		switch ($salign.toLowerCase()) {
			case "l":
			case "t":
			case "r":
			case "b":
			case "tl":
			case "tr":
			case "bl":
			case "br":
				this._params.salign = $salign;
				break;
			default:
				throw "SwfHTML.setSAlign Error: Valid Values for salign: l, t, r, b, tl, tr, bl, br";
		}
	},
	setWMode: function($wmode) {
		switch($wmode.toLowerCase()) {
			case "window":
			case "opaque":
			case "transparent":
			case "direct":
			case "gpu":
				this._params.wmode = $wmode;
				break;
			default:
				throw "SwfHTML.setWMode Error: Valid Values for wmode: window, opaque, transparent";
		}
	},
	setBGColor: function($bgcolor) {
		if (/^#[\dA-F]{6}$/i.test($bgcolor))
			this._params.bgcolor = $bgcolor.toUpperCase(); /* #RRGGBB, hexadecimal RGB value */
		else
			throw "SwfHTML.setBGColor Error: Valid Values for bgcolor: a valid html color hex value (#0099FF)";
	},
	setBase: function($base) {
		this._params.base = $base;
	},
	setFlashvars: function($flashvars) {
		this._flashvars = $flashvars;
	},
	addFlashvar: function($name, $value) {
		if ($value)
			this.setFlashvars($name + "=" + escape($value) + "&" + this._flashvars);
	},
	
	// http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_16494
	setAllowscriptaccess: function($allowscriptaccess) {
		switch ($allowscriptaccess.toLowerCase()) {
			case "never":
			case "always":
				this._params.allowscriptaccess = $allowscriptaccess;
				break;
			default:
				throw "SwfHTML.setAllowscriptaccess Error: Valid Values for allowscriptaccess: never, always";
		}
	},
	
	// for version stuffs
	setVersion: function($version) {
		this._version = $version;
	},
	setMajorRevision: function($majorRevision) {
		this._majorRevision = $majorRevision;
	},
	setMinorRevision: function($minorRevision) {
		this._mainorRevision = $minorRevision;
	},
	setBetaVersion: function($betaVersion) {
		this._betaVersion = $betaVersion;
	},
	
	// misc
	setAdditionalParam: function($name, $value) {
		this._params[$name] = $value;
	},
	setAdditionalProperty: function($name, $value) {
		this._properties[$name] = $value;
	},
	
	// new allowFullScreen prop
	setAllowFullScreen: function($allowFullScreen) {
		if (typeof $allowFullScreen == "boolean")
			this._params.allowFullScreen= $allowFullScreen;
		else
			throw "SwfHTML.setAllowFullScreen Error: Valid Values for allowFullScreen: true, false";
	},
	
	/**
	 * Generates the platform specific HTML for the flash movie
	 *
	 * @return String containing the platform specific HTML for the flash movie
	 */
	getHTML: function() {
		// initialize local variables
		var $key, $html, $ActiveX = window.ActiveXObject && window.print && !window.opera;
		
		if (this._src) {
			if ($ActiveX)
				this._params.movie = this._src;
			else
				this._properties.src = this._src;
		}
		
		if ($ActiveX) {
			$html = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="';
			// solve https popup issue http://www.adobe.com/go/tn_16588
			$html += /^https/.test(window.location)?"https":"http";
			$html += '://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version='+this._version+","+this._majorRevision+","+this._minorRevision+","+this._betaVersion+'"';
		} else
			$html = "<embed";
		
		// output  properties
		for ($key in this._properties)
			$html += ' ' + $key + '="' + this._properties[$key]+'"';
	
		if ($ActiveX) {
			$html += ">";
			for ($key in this._params)
				$html += '<param name="' + $key + '" value="' + this._params[$key] + '"/>';
			if (this._flashvars)
				$html += '<param name="flashvars" value="' + this._flashvars + '"/>';
		} else {
			for ($key in this._params)
				$html += " " + $key + '="' + this._params[$key]+'"';
			if (this._flashvars)
				$html += ' flashvars="' + this._flashvars + '"';
		}
		
		// outputs the rest of the platform specific stuff
		if ($ActiveX) {
			$html += '</object>';
		}
		else
			$html += ' type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>';
		return $html;
	}
};

unFocus.SwfShim = function(shimSwfUrl) {
	/*if (!shimSwfUrl && !unFocus.SwfShim.shimSwfUrl)
		throw new Error (
			"Argument Error. You must pass the URL of the SwfShim.swf to the constructor, or set the static property - unFocus.SwfShim.shimSwfUrl."
		);*/
	unFocus.SwfHTML.call(this);
	this._shimSwfUrl = shimSwfUrl || unFocus.SwfShim.shimSwfUrl;
};
// static properties and methods
with (unFocus) {
	// :NOTE: this is relative to the document, not this js source file
	SwfShim.shimSwfUrl = "SwfShim.swf";
	SwfShim.prototype = new SwfHTML;
}
with (unFocus.SwfShim) {
	// new methods and overrides
	prototype._realSrc = "";
	prototype._MMdocumentTitle = escape(document.title);
	prototype._MMredirectURL = escape(window.location);
	// :NOTE: This should be overridden by the user.
	prototype.eiCallbackName = false;
	prototype.expressInstall = true;
	prototype.shimMode = false;
	
	prototype.setSrc = function(src) {
		this._realSrc = src;
	};
	prototype.setMMdocumentTitle = function(title) {
		this._MMdocumentTitle = title;
	};
	prototype.setMMredirectURL = function(url) {
		this._MMredirectURL = url;
	};
	prototype.setExpressInstallCallback = function(methodName) {
		this.eiCallbackName = methodName;
	};
	prototype.useExpressInstall = function(useEI) {
		this.expressInstall = useEI;	
	};
	prototype.useShimMode = function(m) {
		this.shimMode = m;	
	};
}
unFocus.SwfShim.prototype.getHTML = function() {
	var theHTML, useEI;
	
	if (this.shimMode)
		this.addFlashvar("movieSrc", this._realSrc);
	else
		unFocus.SwfHTML.prototype.setSrc.call(this,this._realSrc);
	
	if (this.expressInstall) {
		// :NOTE: Uses JS based detection. To use ExpressInstall, without shimMode
		// you need to include unFocus.FlashPlayerInfo. Not needed otherwise.
		with (unFocus.FlashPlayerInfo) {
			var majorRevision = getMajorRevision();
			var version = getVersion() + '.' + majorRevision;
			var minorRevision = getMinorRevision();
		}
		
		var reqVersion = this._version;
		if (this._majorVersion)
			reqVersion = reqVersion + '.' + this._majorVersion;
		
		var reqMinorRevision = this._minorRevision;
		
		if (version < reqVersion || (
				reqMinorRevision && 
				version == reqVersion && 
				minorRevision < reqMinorRevision
			)
		) useEI = true;
	}
	
	if (useEI || this.shimMode) {
		unFocus.SwfHTML.prototype.setSrc.call(this,this._shimSwfUrl);
		
		this.addFlashvar("useExpressInstall", "true");
		this.addFlashvar("reqVersion", this._version);
		this.addFlashvar("reqMajorRevision", this._majorRevision);
		this.addFlashvar("reqMinorRevision", this._minorRevision);
		
		var version = this._version,
			minorRev = this._minorRevision;
		
		this.setVersion(6);
		this.setMinorRevision(65);
		
		this.addFlashvar("MMdocumentTitle", this._MMdocumentTitle);
		this.addFlashvar("MMredirectURL", this._MMredirectURL);
		
		if (this.eiCallbackName)
			this.addFlashvar("eiCallbackName", this.eiCallbackName);
		
		if (/*@cc_on!@*/0)
			this.addFlashvar("MMplayerType", "ActiveX");
		else
			this.addFlashvar("MMplayerType", "PlugIn");
		
		theHTML = unFocus.SwfHTML.prototype.getHTML.apply(this);
		
		this.setVersion(version);
		this.setMinorRevision(minorRev);
	}
	else
		theHTML = unFocus.SwfHTML.prototype.getHTML.apply(this);
	
	return theHTML;
};

if (!unFocus.SwfUtilities) unFocus.SwfUtilities = {
	getSwfReference: function(swfId) {
		var $movieObj;
		if (document.embeds && document.embeds[swfId])
			$movieObj = document.embeds[swfId];
		 else if (document[swfId])
			$movieObj = document[swfId];
		 /*else if (window[$swfId])
			$movieObj = $window[$swfId];
		else if (document.getElementById)
			$movieObj = document.getElementById($swfId);*/
		return $movieObj;
	}
};

unFocus.FlashPlayerInfo = (function() {
	// private vars
	var _installed = false,
		_beta = false,
		_version = 0,
		_majorRevision = 0,
		_minorRevision = 0,
		_betaVersion = 0,
		_versionRaw = "",
		_playerType = "",
		_releaseCode = "";
	
	// detection work
	if (navigator.plugins && navigator.plugins.length > 0) {
		_versionRaw = navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"];
		if (_versionRaw) {
			_versionRaw = _versionRaw.description;
			_installed = true;
			_playerType = "PlugIn";
			if (/Shockwave Flash/.test(_versionRaw)) {
				_version = _versionRaw.match(/Shockwave Flash (\d+)\.(\d+)/);
				_majorRevision = _version[2];
				if (/r\d+/.test(_versionRaw)) {
					_releaseCode = "r";
					_minorRevision = _versionRaw.match(/r(\d+)/)[1];
				}
				_version = _version[1];
				if (/[abd]\d+/.test(_versionRaw)) { // I'm not sure what other letters would be here, but I've encountered b, d and a (alpha) so far
					_betaVersion = _versionRaw.match(/([abd])(\d+)/);
					_releaseCode = _betaVersion[1];
					_beta = true;
					_betaVersion = _betaVersion[2];
				}
			} else _version = 1;
		}
	} else if (window.ActiveXObject) {
		// src: Player.vbs 
		var _ax;
		function _getActiveXObject($objectString) {
			try {
				_ax = new ActiveXObject($objectString);
				return true;
			} catch (e){
				return false;
			}
		}
		var _versionTemp;
		
		function _parseVersion() {
			var _versionTemp = _ax.GetVariable("$version");
			_versionRaw = _versionTemp;
			_versionTemp = _versionTemp.split(",");
			_version = _versionTemp[0].match(/\d+/);
			_majorRevision = _versionTemp[1];
			_minorRevision = _versionTemp[2];
			_betaVersion = _versionTemp[3];
			if (_versionTemp[3]>0) _beta = true;
			// if the last number is 0, assume this is a release version
			else _releaseCode = "r";
		}
		
		// we have to detect around Flash 6, since it can crash some versions of IE
		if (_getActiveXObject("ShockwaveFlash.ShockwaveFlash.7"))
			_parseVersion();
		else if (_getActiveXObject("ShockwaveFlash.ShockwaveFlash.6")) {
			// tread lightly
			try {
				// will throw error if < 6.0.47 (info glombed from Adobe's Detection Kit - thanks!)
				_ax.AllowScriptAccess = "always";
				// now safe to call GetVariable
				_parseVersion();
			} catch (e) {
				_version = 6;
				_minorRevision = 0; // cannot be safely detected
			}
		} else if (_getActiveXObject("ShockwaveFlash.ShockwaveFlash.5"))
			_parseVersion();
		else if (_getActiveXObject("ShockwaveFlash.ShockwaveFlash.4"))
			_version = 4;
		else if (_getActiveXObject("ShockwaveFlash.ShockwaveFlash.3"))
			_version = 3;
		else if (_getActiveXObject("ShockwaveFlash.ShockwaveFlash"))
			// Tested on Windows 95 with flash player 2 - using the ".2" at the end doesn't work, but this does ;-)
			// :BUG: This doesn't seem to work when FP2 is installed in WinXP
			_version = 2;
		if (_version) {
			_installed = true;
			_playerType = "ActiveX";
		}
	} else if (/WebTV/.test(navigator.userAgent)) { // WebTV
		_playerType = "WebTV";
		_versionRaw = navigator.userAgent.match(/WebTV\/(\d\.\d)/)[1];
		if (_versionRaw > 2.5) _version = 4;
		else if (_versionRaw == 2.5) _version = 3;
		else _version = 2;
	}
	
	// public/priveleged Getters
	var FlashPlayerInfo = {
		isInstalled: function() {
			return _installed;
		},
		isBeta: function() {
			return _beta;
		},
		getVersion: function() {
			return _version;
		},
		getMajorRevision: function() {
			return _majorRevision;
		},
		getMinorRevision: function() {
			return _minorRevision;
		},
		getBetaVersion: function() {
			return _betaVersion;
		},
		getVersionRaw: function() {
			return _versionRaw;
		},
		// for backward compat - deprecated, will be removed in next version
		getPluginType: function() {
			return this.getPlayerType();
		},
		getPlayerType: function() {
			return _playerType;
		},
		getReleaseCode: function() {
			return _releaseCode;
		}
	};
	return FlashPlayerInfo;
})();



unFocus.AS3Communicator = {
	createFSCommand: function(id) {
		if (/*@cc_on!@*/0) {
			var script = window.document.createElement('<script event="FSCommand(cmd,args)" for="' +id+ '">');
				script.text = "(args)?(window[cmd])?window[cmd](args):eval(cmd)(args):eval(cmd);";
			window.document.getElementsByTagName("head").item(0).appendChild(script);
		} else
			var funcName = id + "_DoFSCommand";
			if (!window[funcName])
				window[funcName] = function(cmd,args) {
					(args)?(window[cmd])?window[cmd](args):eval(cmd)(args):eval(cmd);
				};
	}
};


// :NOTE: These can't be compressed within an eval, if they are it triggers the IE patent thingy
unFocus.SwfHTML.prototype.writeToDocument = function($document) {
	$document.write(this.getHTML());
};
unFocus.SwfHTML.prototype.outputToInnerHTML = function($element) {
	$element.innerHTML = this.getHTML();
};
unFocus.SwfHTML.prototype.outputToOuterHTML = function($element) {
	$element.outerHTML = this.getHTML();
};

