//  DEVELOPER NOTES TO SELF:

// SIFR STUFF
//	- add scoping back in
//	- add in hover styles.
//	- z-indexing for event capture images and swf fonts.
//	- inline/block styling differential for fancy multipart headlines
//	- permit assertion of leading via CSS.
//	- permit assertion of word-spacing via css.
//	- permit assertion of letter-spacing via css.

// CSS STUFF - MANAGE IMPORTANCE
//	 - make sure that the selector strength comparisons for the hover and sublink/sublink+hover styles are being performed correctly.

// PLUGIN ARCHITECTURE!!!!
//	- set up SIFR and DOM movies as the first plugins!
//	- this will create lots of dev interest.
//	- encourages the concept of flash as an advanced image format.

// altcont issue - if a swfhandler div has no *significant* innerhtml, then we should set display:none if flash support is inadequate

// release notes, legal, documentation.

	//// BEGIN HEADER ////////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////////////////////////
	////                                                                                          ////
	////    SWFHANDLER OBJECT CREATOR. V3.0                                                       ////
	////                                                                                          ////
	////    Copyright 2008, Jose Cao-Garcia                                                       ////
	////                                                                                          ////
	////    This software is licensed under the Creative Commons                                  ////
	////    Attribution-ShareAlike 2.5 License:                                                   ////
	////    <http://creativecommons.org/licenses/by-sa/2.5/legalcode>                             ////
	////                                                                                          ////
	////    HELP/INFO/DEVELOPER CONTACT: jose@jcao.com, http://jcao.com                           ////
	////                                                                                          ////
	//////////////////////////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////////////////////////
	////                                                                                          ////
	////    SWFHANDLER is a simple, powerful and lightweight object creator that provides         ////
	////    support for flash deployment across all major/modern browsers (as well as Internet    ////
	////    Explorer) via W3C DOM and JavaScript. SWFHANDLER detects for the availability and     ////
	////    version of the shockwave flash plugin, It generates a pure-dom swf object that can    ////
	////    be inserted and manipulated via standard W3C DOM methods. In addition to detecting    ////
	////    the flash plugin and generating SWF objects, this script also provides object-level   ////
	////    support for javascript/flash interaction, via the Flash 'ExternalInterface' and       ////
	////    'liveconnect' methods provided by the shockwave flash browser plugin. Finally,        ////
	////    this script provides a flexible mechanism for serving alternate content to browsers   ////
	////    with missing or inadequate flash support.                                             ////
	////                                                                                          ////
	////    FOR MORE INFO VISIT: http://jcao.com/scripts/swfHandler/                              ////
	////                                                                                          ////
	//////////////////////////////////////////////////////////////////////////////////////////////////
	//// END HEADER //////////////////////////////////////////////////////////////////////////////////


	//// these CSS rules complement the built-in sifr support.
		document.writeln(' <style type="text/css">                                                                         ');
		document.writeln('     @media screen {                                                                             ');
		document.writeln('         .swf-movie,                                                                             ');
		document.writeln('         .swf-altCont         { visibility: hidden; }                                            ');
		document.writeln('         .swf-noFont          { visibility: visible ! important; }                               ');
		document.writeln('         img.swf-clickImg     { display: block; position: relative; margin: 0px; padding: 0px; } ');
		document.writeln('         span.swf-font        { visibility: hidden;  display: none;                            } ');
		document.writeln('         object.swf-font,                                                                        ');
		document.writeln('         embed.swf-font       { margin: 0px; padding: 0px; }                                     ');
		document.writeln('     }                                                                                           ');
		document.writeln('     @media print  {                                                                             ');
		document.writeln('         span.swf-font  { visibility: visible; display: inline; }                                ');
		document.writeln('         object.swf-font,                                                                        ');
		document.writeln('         embed.swf-font { visibility: hidden;  display: none;   }                                ');
		document.writeln('     }                                                                                           ');
		document.writeln('    div#swfHandler-scaleTestingDiv { font-size: 10px ! important; height: 60em ! important; width: 60em ! important; background: red ! important; margin: 0px ! important; padding: 0px ! important; visibility: hidden ! important; position: absolute ! important; top: -1200px; left: -1200px; } ');
		document.writeln(' </style>                                                                                        ');


	//// OBJECT CREATOR FOR WORKING WITH SHOCKWAVE FLASH FILES
		function swfHandler(defaults, scope) {
		// error handling for defaults
			if (defaults && typeof(defaults) != 'object')  { throw('new swfHandler(defaults): default options for swf movies must be an object'); }
		// root for scope, and default swf attributes
			var root             = this;
				root.scope       = scope    || document.body;
				root.defaults    = {
					allowScriptAccess : 'sameDomain',
					quality           : 'high',
					type              : 'application/x-shockwave-flash',
					classid           : 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
					revreq            :  8,
					width             : '100%',
					height            : '100%'
				};
			// ovverride defaults with any supplied values.
				for (var i in defaults) { root.defaults[i] = defaults[i]; }
			// remove classid for standards-based browsers
				if  (typeof(ActiveXObject) == 'undefined') { delete root.defaults.classid; }
			// this object will store font styles for use with SIFR type text replacement.
				root.fonts       = [];
				root.storedAltConts   = new Object();
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// DICTIONARY OF RULES FOR APPLYING/VALIDATING SWF OBJECT PROPERTIES                       ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.propDict = {
			// These properties describe application rules for html object/embed/param attributes,
			// altering them will alter the flash object markup this script produces. Be careful
			// messing around here. Make damn sure you know what you are doing before you edit this
			// object--because it is extremely probable that you will break something if you don't.
				markupProps : {
					align             : { applyTo:{ OBJECT: true,  PARAM: true,  EMBED: false }, valueType:'string', values:['left', 'top', 'right', 'bottom', 'middle'] },   // <-- (attribute for Object) - Possible values: l, t, r, b.
					allowScriptAccess : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'string', values:['always', 'never', 'sameDomain'] },              // <-- Sets permissions for scripting acess across domains.
					allowFullScreen   : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'boolean' },                                                       // <-- permit movie to be displayed full screen?
					base              : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'string:url' },                                                    // <-- Specifies the base directory or URL used to resolve all relative path statements in the Flash Player movie.
					bgcolor           : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'string:hexadecimal' },                                            // <-- Specifies the background color of the movie/player.
					classid           : { applyTo:{ OBJECT: true,  PARAM: false, EMBED: false }, valueType:'string' },                                                        // <-- identifies the ActiveX control for the browser.
					codebase          : { applyTo:{ OBJECT: true,  PARAM: false, EMBED: false }, valueType:'string:url' },                                                    // <-- url of the Flash Player ActiveX control for automatic installation on windows.
					data              : { applyTo:{ OBJECT: true,  PARAM: false, EMBED: false }, valueType:'string:url' },                                                    // <-- Specifies the location (URL) of the movie to be loaded.
					flashvars         : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'string' },                                                        // <-- name-value pairs to pass into the flash movie.
					height            : { applyTo:{ OBJECT: true,  PARAM: false, EMBED: false }, valueType:'number' },                                                        // <-- specifies hidth in pixels.
					id                : { applyTo:{ OBJECT: true,  PARAM: false, EMBED: false }, valueType:'string' },                                                        // <-- (attribute for object, object only) - Movie Identifier. Identifies the Flash movie to the host environment (a web browser, for example) so that it can be referenced using a scripting language.
					loop              : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'boolean' },                                                       // <-- Should the movie repeat indefinitely? Default value is true if omitted.
					menu              : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'boolean' },                                                       // <-- ?? I have no idea what the heck this is supposed to do.
					movie             : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'string:url' },                                                    // <-- Specifies the location (URL) of the movie to be loaded.
					name              : { applyTo:{ OBJECT: false, PARAM: false, EMBED: false }, valueType:'string' },                                                        // <-- Identifies the Flash movie to the host environment so that it can be referenced using JavaScript.
					play              : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'boolean' },                                                       // <-- Should the movie begins playing immediately on loading in the browser? Default is true if omitted.
					pluginspage       : { applyTo:{ OBJECT: true,  PARAM: true,  EMBED: false }, valueType:'string' },                                                        // <-- url of the Flash Player ActiveX control for automatic installation on windows Identifies the location of the Flash Player plug-in so that the user can download it if it is not already installed. EMBED only. (See example code in TechNote tn_4150 for the correct value.)
					quality           : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'string', values:['low', 'high', 'autolow', 'autohigh', 'best'] }, // <-- Sets playback quality..
					salign            : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'string', values:['l', 't', 'r', 'b', 'tl', 'tr', 'bl', 'br'] },   // <-- sets movie alignment within flash player.
					scale             : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'string', values:['showall', 'noborder', 'exactfit', 'noScale'] }, // <-- determine how movie should scale.
					swliveconnect     : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'boolean' },                                                       // <-- Should the browser start Java when loading the Flash Player? Default is false if omitted. If you use JavaScript and Flash on the same page. Java must be running for the FSCommand to work.
					src               : { applyTo:{ OBJECT: false, PARAM: false, EMBED: false }, valueType:'string:url' },                                                    // <-- Specifies the location (URL) of the movie to be loaded.
					type              : { applyTo:{ OBJECT: true,  PARAM: true,  EMBED: false }, valueType:'string', values:['application/x-shockwave-flash'] },              // <-- sets type for embed object.
					width             : { applyTo:{ OBJECT: true,  PARAM: false, EMBED: false }, valueType:'number' },                                                        // <-- specifies width in pixels.
					wmode             : { applyTo:{ OBJECT: false, PARAM: true,  EMBED: false }, valueType:'string', values:['window', 'opaque', 'transparent'] }             // <-- sets the Window Mode property of the Flash movie for transparency, layering, and positioning in the browser.
				},
			// these properties are used by root.movie, for movie creation, but are not passed on
			// into the markup, they indicate how the swf should be treated by the movie creation script.
				objectProps : {
					revreq            : { valueType:'number'     },                                                                                                           // <-- specifies the minimum required flash player version to display movie
					altcont           : { valueType:'string'     },                                                                                                           // <-- specifies alternate content, in the event that flash support is inadequate
					swfhandler        : { valueType:'string', values:['swfcont', 'altcont', 'font:']},                                                                        // <-- used in markup-based insertion, indicates how to handle the flash movie.
					isFont            : { valueType:'boolean'    },                                                                                                           // <-- used to determine if a swf movie is a sifr font
					objref            : { valueType:'string'     },                                                                                                           // <-- used to create a window level variable, object reference for a movie.
					procobj           : { valueType:'function'   },
					url               : { valueType:'string:url' },                                                                                                           // <-- the url of your movie, so you don't have to include it twice.
					copyquery         : { valueType:'boolean'    }                                                                                                            // <-- boolean: if true, we carry over page request querystring to flashvars
				}
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// DICTIONARY OF ERRORS THAT CAN BE CALLED BY VARIOUS METHODS WITHIN THE SWFHANDLER.       ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.error = {
				beyondScope  : 'Scope Error.',
				badType      : 'Type Error (Major).',
				badSubType   : 'Minor Type (Minor).',
				badValue     : 'Illegal Value Error.',
				badProp      : 'Unknown Property Error.',
				noRevreq     : 'No Version Check Error.',
				noUrl        : 'No Url Error.',
				altTarget    : 'No Alt Target Error.'
			};
		// tries to warn developers in a useful way when there are problems with a swfOpts object.
			root.devWarn = function(err, swfOpts, badProp, customError) {
				var errorStr  = ['swfHandler error: ' + root.error[err] + '.\n\t\tSee documentation at http://jcao.com/scripts/swfHandler/ for debugging info.'].join('');
				if (swfOpts) {
					var swfOptsStr  = '\n\t\tswfOpts:{';
					for (var i in swfOpts) {
						swfOptsStr += '\n\t\t\t' + i + ':' + swfOpts[i] + ', ';
						if (badProp && i == badProp) { swfOptsStr += '\/\/<---' + (customError||root.error[err]); }
					}
					swfOptsStr  = swfOptsStr.split(', }').join('\n\t\t};');
					errorStr   += swfOptsStr;
				}
				try { console.warn(errorStr); } catch(e) {}
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// ADDS FONT-STYLES FOR USE WITH sIFR TEXT REPLACEMENT                                     ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.newFont = function(fontName, fontUrl) {
				if (!fontName || !fontUrl) {
					throw('swf.fontStyles: you must specify a styleName, and styleValues');
				} else {
				// set or accept defaults
					root.fonts[fontName] = fontUrl;
				}
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// METHOD CREATES A BASIC SWF OBJECT, AND RETURNS A REFERENCE FOR IT                       ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.movie = function(swfOpts, target, forceAlt) {
			// permit target to be an object reference, or an id string if supplied
				target  = (target) ? ((typeof(target) == 'string') ? document.getElementById(target) : target) : null;
			// validate/process swfOpts?
				swfOpts = root.swfOptsProc(swfOpts, target);
				swfOpts = root.validateSwfOpts(swfOpts);
			// return swf content or alternate content
				var returnType  = ((swf.rev >= swfOpts.revreq) && !forceAlt) ? 'swfCont' : 'altcont';
			// insert flash or alternate content, set return value to movie reference, or boolean false
				switch(returnType) {
				// return swfContent
					case 'swfCont':
						if (target) {
							target.style.display = '';
						}
					// default markup for movies
						var swfMarkup = {
							OBJECT : '<object<!--ins-->><!-- children --></object>\n',
							PARAM  : '<!--ins-->',
							EMBED  : '\t<embed<!--ins--> />\n'
						};
						// set all unignored properties
						for (var propName in swfOpts) { if (root.propDict.markupProps[propName]) { swfMarkup = root.setSwfOpt(swfMarkup, propName, swfOpts[propName]); } }
					// process markup ...
						swfMarkup.EMBED = (swfMarkup.EMBED == '\t<embed<!--ins--> />\n') ? '' : swfMarkup.EMBED.split('<!--ins-->').join('');
						swfMarkup = swfMarkup.OBJECT.split('<!-- children -->').join(swfMarkup.PARAM + swfMarkup.EMBED);
						swfMarkup = swfMarkup.split('<!--ins-->').join('');
					// insert in page, and return reference, or return a pure dom element
						if (target) {
						// hide div insert markup and normalize
							target.style.visibility = 'hidden';
							target.innerHTML  = swfMarkup;
							target.normalize();
						// handle return values
							if (!swfOpts.isFont) {
								var returnValue   = (typeof(ActiveXObject) != 'undefined' && document.embeds) ? window[swfOpts.name] : document[swfOpts.id];
							} else {
								var returnValue = true;
							}
						// show content after slight delay (keeps things clean).
							setTimeout(function(){target.style.visibility = 'visible';}, 40);
						} else {
							target            = document.createElement('div');
							target.innerHTML  = swfMarkup; target.normalize();
							var returnValue   = target.removeChild(target.firstChild);
						}
						if (!swfOpts.isFont && returnValue) {
						// set liveconnect methods
							returnValue.lC_getVar  = root.lC_getVar;
							returnValue.lC_setVar  = root.lC_setVar;
							returnValue.lC_goFrame = root.lC_goFrame;
							returnValue.lC_pause   = root.lC_pause;
							returnValue.lC_play    = root.lC_play;
							returnValue.lC_rewind  = root.lC_rewind;
							returnValue.lC_loadMov = root.lC_loadMov;
						}
					break;
				// return alternate content
					case 'altcont':
						if (swfOpts.altcont) {
						// determine type of alternate content
							var isImg  = (/\.png$|\.jpg$|\.jpeg$|\.gif$/.test(swfOpts.altcont));
							var isUrl  = ((/\.html$|\.htm$|\.shtml$|\.asp$|\.aspx$|\.php$|^http|^https/.test(swfOpts.altcont)));
							var isHTML = (!isImg && !isUrl);
						// insert/forward to alternate content
							if (isImg)  { if (target) { target.innerHTML  = '<img src="' + swfOpts.altcont + '" width="' + swfOpts.width + '" height="' + swfOpts.height + '" />'; } else {  root.devWarn('altTarget', swfOpts, 'altcont', 'you must specify a target element when setting alternate content as an image URL'); } }
							if (isHTML) { if (target) { target.innerHTML  = swfOpts.altcont; } else {  root.devWarn('altTarget', swfOpts, 'altcont', 'you must specify a target element when setting alternate content as HTML text'); } }
							if (isUrl)  { location.replace(swfOpts.altcont); }
							var returnValue   = null;
						} else {
							target.style.display = 'none';
						}
					break;
				}
			return returnValue;
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// METHOD ADDS PARAMS/ATTRIBUTES TO A SWF OBJECT.                                          ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.setSwfOpt = function(swfMarkup, propName, propValue) {
			// get rules
				var applicationRules = root.propDict.markupProps[propName].applyTo;
				var splitStr         = '<!--ins-->';
			// apply attributes
				if (applicationRules.OBJECT)  {
					swfMarkup.OBJECT = swfMarkup.OBJECT.split(splitStr).join(' '+ propName + '="' + propValue + '"' + splitStr);
				}
				if (applicationRules.EMBED)   {
					swfMarkup.EMBED = swfMarkup.EMBED.split(splitStr).join(' '+ propName + '="' + propValue + '"' + splitStr);
				}
				if (applicationRules.PARAM)   {
					swfMarkup.PARAM = swfMarkup.PARAM.split(splitStr).join('\t<param name="' + propName + '" value="' + propValue + '" />\n' + splitStr);
				}
			// send it back
				return swfMarkup;
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// METHOD VALIDATES/PROCESSES SWF PARAMS/ATTRIBUTES AGAINST DICTIONARY OBJECT RULES.       ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.validateSwfOpts = function(swfOpts) {
			// convert url to movie/src property
				if (!swfOpts.url)    { swfOpts.url    = 'undefined or null'; root.devWarn('noUrl', swfOpts, 'url', 'MISSING OR UNDEFINED URL PROPERTY. Multiple "(Major) Type" errors for "data", "src", and "movie" can be resolved as well by setting the url property.'); }
				if (!swfOpts.revreq) { swfOpts.revreq = 'undefined or null'; root.devWarn('noRevreq', swfOpts, 'revreq'); }
			// check the final properties
				for (var i in swfOpts) {
				// get name/value validity
					var propName    = i;
					var propValue   = swfOpts[i];
					var isValid     = (root.propDict.markupProps[propName] || root.propDict.objectProps[propName]);
				// return error if property is unknown
					if (!isValid) {
						root.devWarn('badProp', swfOpts, i);
					} else {
						var rules       = root.propDict.markupProps[propName] || root.propDict.objectProps[propName];
						var majType     = rules.valueType.split(':')[0];
						var minType     = (/\w\:/.test(rules.valueType)) ? rules.valueType.split(':')[1] : null;
						var legalValues = rules.values || null;
					// make sure numbers expressed as strings, are stored as numbers, but don't strip percentages for width and height.
						if (majType == 'number') {
							var isValidNumber  = (parseInt(propValue).toString() != 'NaN');
							var isPercentValue = (/\%$/.test(propValue));
							propValue = swfOpts[i] = (isValidNumber) ? parseInt(propValue) : propValue;
						// return percentage value back into swfOpts (turning it back into a string) but not propValue, because it must validate as number type.
							if (isPercentValue) { swfOpts[i] += '%'; }
						}
						if (majType == 'function' && typeof(propValue) == 'string') {
							if (typeof(window[propValue]) != 'undefined') { propValue = window[propValue]; }
						}
					// begin typing tests
						if (typeof(propValue) != majType) {
						// invalid type error
							root.devWarn('badType', swfOpts, i);
						} else {
							if (legalValues && legalValues.join().indexOf(propValue) == -1) {
							// invalid value error (no match)
								root.devWarn('badValue', swfOpts, i);
							}
						}
					}
				}
				return swfOpts;
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// METHOD PRE-PROCESSES swfOpts OBJECTS BEFORE THEY ARE TURNED INTO MOVIES.                ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.swfOptsProc = function(swfOpts, target) {
			// if a target is specified, store its innnerHTML as altCont if it hasn't been converted to a .swf allready
				if (target) {
					var objTag = target.getElementsByTagName('object');
					var embTag = target.getElementsByTagName('embed');
					if (objTag.length || embTag.length) {
						// point to old innerHTML if it has been converted allready
						var movieId = (objTag.length) ? objTag[0].id : embTag[0].name;
						if (movieId) {
							swfOpts.id      = swfOpts.name = movieId;
							swfOpts.altcont = root.storedAltConts[swfOpts.id];
						}
					} else {
						// store innerHTML for the first time otherwise
						swfOpts.altcont     = target.innerHTML;
					}
				}
			// if the movie is being built from a div with custom attributes, let the objRef define id/name if undefined.
				if (swfOpts.objref && typeof(swfOpts.id) == 'undefined' && typeof(swfOpts.name) == 'undefined') {
					swfOpts.id = swfOpts.objref;
				}
			// make sure name and ID match, with id trumping Name. if there is no name or id, generate a random one.
				if (swfOpts.id || swfOpts.name) {
					if (swfOpts.id && !swfOpts.name) { swfOpts.name = swfOpts.id;   }
					if (swfOpts.name && !swfOpts.id) { swfOpts.id   = swfOpts.name; }
				} else {
					var rndChars  = function(num) {
						var allChars = '0123456789abcdefghijklmnopqrstuvwxyz';
						var str      = '';
						while (str.length < num) { str += allChars.charAt(Math.round(Math.random() * (allChars.length-1))); };
						return str;
					};
				// keep generating random ids until we hit an unused one.
					while(!swfOpts.id || document.getElementById(swfOpts.id)) { swfOpts.id = swfOpts.name = 'swfHandlerGenerated_' + rndChars(8); }
				}
			// now that all ID and altCont issues have been sorted out, re-store the altCont referenced by ID.
					root.storedAltConts[swfOpts.id] = swfOpts.altcont;
			// splice in default values for undeclared
				for (var loop in root.defaults) { if (typeof(swfOpts[loop]) == 'undefined') { swfOpts[loop] = root.defaults[loop]; } }
			// if an options processing function has been specified, use it first
				var procFunc = target.getAttribute('procobj') || swfOpts.procobj || null;
				if (procFunc) { swfOpts = procFunc(swfOpts); }
			// carry over querystring to flashvars if requested
				if (swfOpts.copyquery) { swfOpts.flashvars = document.location.search.substring(1); }
			// convert url attribute so that the movie method can do something with it
				swfOpts.movie = swfOpts.src = swfOpts.data = swfOpts.url;
			// return processed options
				return swfOpts;
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// CONVERTS AN HTML DIV WITH SWFHANDLER ATTRIBUTES INTO FLASH/ALTERNATE CONTENT            ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.setOne = function(thisObj, forceAlt) {
				var thisType = thisObj.getAttribute('swfHandler').toLowerCase();
			// builds swfOpts objects from element attribute lists
				var objBuilder  = function(thisObj) {
				// construct anonymous obj
					var options = {};
				// get attributes and convert to object properties
					var attbrs  = thisObj.attributes;
					for (var ii = 0; ii < attbrs.length; ii++) { 
						var name  = attbrs[ii].name;
						var value = attbrs[ii].value;
					// skip standard html attribute names
						if (name == 'id' || name == 'name' || (!root.propDict.objectProps[name] && !root.propDict.markupProps[name])) { continue; }
					// set object property for attribute names
						options[name] = value;
					}
					return options;
				};
			// create swfOpts obj from attributes
				var swfOpts = objBuilder(thisObj);
				switch (thisType) {
					case 'swfcont':
					// create movie and add to dom.
						if (swfOpts.objref) {
							window[swfOpts.objref] = root.movie(swfOpts, thisObj, forceAlt);
						} else {
							root.movie(swfOpts, thisObj, forceAlt);
						}
					break;
					case 'altcont':
						var showAlt  = (forceAlt || !swf.rev || (swf.rev <= swfOpts.revreq));
						thisObj.style.display = (showAlt) ? 'block' : 'none';
					break;
				}
			// make sure object is visible
				setTimeout(function(){thisObj.style.visibility = 'visible';}, 250);
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// CONVERTS AN HTML DIV WITH SWFHANDLER ATTRIBUTES INTO FLASH/ALTERNATE CONTENT            ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.setOneFont = function(thisObj, fontStyle, forceAlt) {
			// get html content strings
				var textStr     = thisObj.getAttribute('textStr') || escape(thisObj.innerHTML);
			// store text content if not allready saved.
				if (!thisObj.getAttribute('textStr')) { thisObj.setAttribute('textStr', textStr); }
				// create and show the type, otherwise if:
				//     - flash plugin version >= 6
				//     - we are not forcing alternate content
				//     - element is not currently hidden.
					if ((swf.rev >= 6) && !forceAlt && thisObj.offsetHeight > 0 && thisObj.offsetWidth > 0) {
					// prepare for measurement by relasing dimensional styling and restoring / hiding content.
						thisObj.style.fontSize   = '';
						thisObj.style.width      = '';
						thisObj.style.height     = '';
						thisObj.style.fontFamily = 'arial';
						thisObj.innerHTML        = unescape(textStr);
						thisObj.style.display    = 'block';
						thisObj.style.visibility = 'hidden';
						thisObj.normalize();
					// construct flashVars string.
						var flashvars  = 'txt='              + textStr;
							flashvars += '&textalign='       + escape(fontStyle.textalign);
							flashvars += '&offsetTop='       + escape(fontStyle.offsetTop);

							flashvars += '&textcolor='       + escape(fontStyle.textcolor);
							flashvars += '&texthovercolor='  + escape(fontStyle.texthovercolor);

							flashvars += '&linkcolor='       + escape(fontStyle.linkcolor);
							flashvars += '&linkhovercolor='  + escape(fontStyle.linkhovercolor);
							flashvars += '&sifr_url_0='      + escape(fontStyle.sifr_url_0); //<! -- find out WTF this is for ... 


						// log colours
							console.log('fontStyle.textcolor: '      + fontStyle.textcolor);
							console.log('fontStyle.texthovercolor: ' + fontStyle.texthovercolor);
							console.log('fontStyle.linkcolor: '      + fontStyle.linkcolor);
							console.log('fontStyle.linkhovercolor: ' + fontStyle.linkhovercolor);
							console.log('===========================================================================================================');


					// construct swfOpts object
						var swfOpts = {
							url       : fontStyle.face,
							flashvars : flashvars,
							quality   : 'best',
							wmode     : 'transparent',
							scale     : 'noScale',
							revreq    : 6,
							isFont    : true
						};
					// measure dimensions
						var measuredWidth      = thisObj.offsetWidth;
						var measuredHeight     = thisObj.offsetHeight;
					// Re-Style target Element to support Scaling
						thisObj.style.fontSize = '10px';
						var emScale            = (1/root.getScalingFactor());
						thisObj.style.width    =  (measuredWidth/10)*emScale+'em';
						thisObj.style.height   =  (measuredHeight/10)*emScale+'em';
					// write in sifr and show element contents
						var thisMovie          = root.movie(swfOpts, thisObj);
					// add classes in for print styling
						var objTags = thisObj.getElementsByTagName('object');
						var embTags = thisObj.getElementsByTagName('embed');
						if (objTags.length) { objTags[0].className = 'swf-font'; }
						if (embTags.length) { embTags[0].className = 'swf-font'; }
					// add in backup content for printing.
						var printObj = thisObj.appendChild(document.createElement('span'));
							printObj.className = 'swf-font';
							printObj.innerHTML = unescape(textStr);
					// does the parent element have mouse events that need capturing?
						var hasEvents = (
							typeof(thisObj.onclick)     == 'function' ||
							typeof(thisObj.onmousedown) == 'function' ||
							typeof(thisObj.onmouseup)   == 'function' ||
							typeof(thisObj.onmouseover) == 'function' ||
							typeof(thisObj.onmouseout)  == 'function'
						);
					// provide an element to absorb mouse events for elements that have them
						if (hasEvents) {
							var clickImg                   = document.createElement('div');
								clickImg.innerHTML         = '&nbsp';
								clickImg.className         = 'swfhandler-clickImg';
								clickImg.style.fontSize    = '10px';
								clickImg.style.cursor      = 'pointer';
								clickImg.style.width       = thisObj.style.width;
								clickImg.style.height      = thisObj.style.height;
								clickImg.style.position    = 'absolute';
								clickImg.style.zIndex      = '50';
							if (typeof(ActiveXObject) == 'undefined') {
							// special styling for standards-challenged IE
								clickImg.style.marginTop   = '-' + clickImg.style.height;
							} else {
							// styling for standards-based browsers
								clickImg.style.background  = 'black';
								clickImg.style.marginLeft  = '-' + clickImg.style.width;
								clickImg.style.filter      = 'alpha(opacity=0)';
							}
							clickImg                       = thisObj.appendChild(clickImg);
						}
					} else {
					// show standard HTML version.
						var textStr = thisObj.getAttribute('textStr');
						if (textStr) { thisObj.innerHTML = unescape(textStr); }
						thisObj.className = (thisObj.className && /\w/.test(thisObj.className)) ? thisObj.className + ' swf-noFont' : 'swf-noFont';
					}
				// enforce original measured container dimensions, and show.
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// HANDLES AUTOMATED CSS/DOM-BASED FLASH/ALTERNATE CONTENT INSERTION AND  DISPLAY          ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			// creates movies based on DOM element attributes
			root.setMovies = function(subScope, forceAlt) {
			// get all divs
				var allSwfDivs = root.getAll();
			// send each div to processor method, or sifr processing method
				for (var i in allSwfDivs) { root.setOne(allSwfDivs[i], forceAlt); }
			};
			// creates movies based on DOM element attributes
			root.setAll    = function(subScope, forceAlt) {
				setTimeout(root.setMovies, 10);  // do main movies first since there will be fewer of them
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// RETURNS AN ARRAY CONTAINING ALL OF THE SWFHANDLER DIVS IN THE DOM                       ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.getAll = function(subScope) {
			// empty array will hold swfHandler elements
				var allSwfDivs = [];
			// set subscope to default if unspecified
				subScope   = subScope || document.getElementsByTagName('HTML')[0];
			// test to make sure subscope is within scope, throw error if not
				var parent = subScope;
				while (parent != document.body) {
					if (parent == root.scope)    { break; }
					parent = parent.parentNode;
					if (parent == document.body) { root.devWarn('beyondScope'); }
				}
			// get all page elements within scope
				var allElements = subScope.getElementsByTagName('*');
			// save elements that contain the swfHandler into the array
				for (var i = 0; i < allElements.length; i++) {
					var thisObj = allElements[i];
					var thisOpt = thisObj.getAttribute('swfhandler');
					if (thisOpt) { allSwfDivs.push(thisObj); }
				}
				return allSwfDivs;
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// METHOD TESTS FOR FLASH PLUGIN CONSERVATIVELY (RETURNS FALSE IF VERSION INDETERMINATE)   ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.testPlugin = function() {
				var swfStr     = false;
				var swfValue   = false;
			// for standards-challenged browsers:
				if (typeof(ActiveXObject) != 'undefined') {
					for (var loop = 0; loop < 50; loop++){
						try {
							var swfAxObj = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.' + loop);
							swfValue = loop;
						} catch(e) {  }
					}
			// for standards-capable browsers:
				} else {
				    if (navigator.plugins && navigator.plugins.length > 0) {
						if (navigator.plugins['Shockwave Flash 2.0'])  { swfValue = 2; }
						if (navigator.plugins['Shockwave Flash'])      {
							swfStr = navigator.plugins['Shockwave Flash'].description;
							swfValue = swfStr.split('.')[0].substring(swfStr.split('.')[0].lastIndexOf(' '));
						}
					}
				}
			// set the revision value
				root.rev = swfValue;
			// include an override mechanism to force display of alternate content
				if (document.location.href.indexOf('flash=false') != -1) { root.rev = false; }
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// METHODS PROVIDE WAYS TO INTERACT SWF MOVIES VIA LIVECONNECT. ANTIQUATED.                ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			// get value of a variable in a flash movie
			root.lC_getVar = function(varName) {
				try {
					return this.GetVariable(varName);
				} catch (e) { return 'undefined'; }
			};
			// set value of a variable in a flash movie
			root.lC_setVar = function(varName, varValue) {
				try {
					this.SetVariable(varName, varValue);
				} catch (e) {  }
			};
			// go to a frame number (or label) in a flash movie
			root.lC_goFrame = function(swfFrame, swfLayer) {
				try {
					var movieLayer = (swfLayer) ? swfLayer : '_level0/';
					if (parseInt(swfFrame) == NaN) {
						this.TGotoLabel(movieLayer, swfFrame);
					} else {
						this.TGotoFrame(movieLayer, swfFrame);
					}
				} catch (e) {  }
			};
			// pause playback of a flash movie
			root.lC_pause = function(swfLayer) {
				try {
					var movieLayer = (swfLayer) ? swfLayer : '_level0/';
					this.TStopPlay(movieLayer);
				} catch (e) {  }
			};
			// resume playback of a flash movie
			root.lC_play = function(swfLayer) {
				try {
					var movieLayer = (swfLayer) ? swfLayer : '_level0/';
					this.TPlay(movieLayer);
				} catch (e) {  }
			};
			// rewind movie, reset variables
			root.lC_rewind = function() {
				try {
					this.Rewind();
				} catch (e) {  }
			};
			// load a separate flash movie into a layer of an existing movie
			// set 'newSwf' to false to unload a movie from a particular layer
			root.lC_loadMov = function(layer, newSwf) {
				try {
					this.LoadMovie(layer, newSwf);
				} catch (e) {  }
			};
		/////////////////////////////////////////////////////////////////////////////////////////////////
		//// INITIALIZE THE OBJECT BY TESTING FLASH SUPPORT AND PROCESSING HTML (STAGGERED BY TYPE)  ////
		/////////////////////////////////////////////////////////////////////////////////////////////////
			root.testPlugin();                // test flash support.
		};


