/* Photofont WebReady Components
Copyright (c) 2008 by Fontlab Ltd.
Portions copyright 2004 - 2006 Mike Davidson, Shaun Inman, Tomas Jogin and Mark Wubben

This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
*/

/*
   PFWR_Interpreter allows to calculate the size of the flash text using
   the mapping above
*/
var PFWR_CHAR = new Array();
var PFWR_CHAR_WIDTH = new Array();
var PFWR_CHAR_DESC = new Array();
var PFWR_CHAR_ASC = new Array();
var PFWR_KERNING = new Array();
var PFWR_WIDTH_RESERVE = new Array();
var PFWR_Interpreter = function(tag, width, scale, sFlashFile) {

    var words = new Array();
	var delimiters = new Array();
    var widths = new Array();
    var lines = 1;
	for (font = 0; font<PFWR_CHAR.length; font++) {
		if (PFWR_CHAR[font][0] == sFlashFile) {
			break;
		}
	}
	width -= (4 + PFWR_WIDTH_RESERVE[font][1]);
    newTag = tag.replace(/[\s][\s]*/g," ");
    newTag = newTag.replace(/<BR[\/]*>/gi,"\n");			// replace BR tag with new line symbol
    newTag = newTag.replace(/<[a-z\/][a-z0-9=" \/%^'(),.:;!?_@#+\-*&]*>[\s]*/gi, ""); // remove all tags 
    newTag = newTag.replace(/&lt;/g,"<");
    newTag = newTag.replace(/&rt;/g,">");
    newTag = newTag.replace(/&nbsp;/g," ");
	j=0;
	words[0] = ""
	for (i=0; i<newTag.length; i++) {
		if ((newTag.charAt(i) != " ") && (newTag.charAt(i) != ".") && (newTag.charAt(i) != ";") && (newTag.charAt(i) != ":") && (newTag.charAt(i) != ",") && (newTag.charAt(i) != "\\") && (newTag.charAt(i) != "\/") && (newTag.charAt(i) != "\n")) {
			words[j] += newTag.charAt(i);
		} else {
			delimiters[j] = newTag.charAt(i);
			j++;
			words[j] = "";
		}
	}
    if (words==null || words.length==null) return 0;
    currWidth = 0;
    newStr = "";
    for(i=0; i<words.length; i++) {         // for each word we calculate
		if (words[i] == "") {
			if ((i < delimiters.length) && ((currWidth != 0) || (delimiters[i] != " "))) {
				if (delimiters[i] == "\n") {					
					newStr += "\n";
    		        currWidth = 0;				// increment the number of lines
   	    		    lines++;
				} else if (currWidth + getCharWidth(delimiters[i].charCodeAt(0), scale) > width) {
					newStr += "\n";
    		        currWidth = 0;				// increment the number of lines
   	    		    lines++;
					if (delimiters[i] != " ") {
						newStr += delimiters[i];
						currWidth += getCharWidth(delimiters[i].charCodeAt(0), scale);
					}
				} else {
					newStr += delimiters[i];
					currWidth += getCharWidth(delimiters[i].charCodeAt(0), scale);
				}
			}
			continue;	
		}
        thisWidth = getWordWidth(words[i], scale); // the size
		if ((i < delimiters.length) && (delimiters[i] != " ")) {
			thisWidth += getCharWidth(delimiters[i].charCodeAt(0), scale)
		}
        currWidth += thisWidth;
        if (currWidth>width) {              // if the line exceeds our width
			if (currWidth == thisWidth) {
				currWidth = 0;
		        for(ii=0; ii<words[i].length; ii++) {
    		        currWidth += getCharWidth(words[i].charCodeAt(ii), scale);
					if (ii<words[i].length-1) {
	        		    word_width += getCharKerning(words[i].charCodeAt(ii), words[i].charCodeAt(ii+1), scale);
					}
					if (currWidth>width) {
						newStr += "\n";
    			        currWidth = getCharWidth(words[i].charCodeAt(ii), scale);					// increment the number of lines
        	    		lines++;
					}
					newStr += words[i].charAt(ii);
	    	    }
				if (i < delimiters.length) {
					if (delimiters[i] == "\n") {					
						newStr += "\n";
    			        currWidth = 0;				// increment the number of lines
   	    			    lines++;
					} else if (currWidth + getCharWidth(delimiters[i].charCodeAt(0), scale) > width) {
						newStr += "\n";
	    		        currWidth = 0;				// increment the number of lines
    	    		    lines++;
						if (delimiters[i] != " ") {
							newStr += delimiters[i];
							currWidth += getCharWidth(delimiters[i].charCodeAt(0), scale);
						}
					} else {
						newStr += delimiters[i];
						currWidth += getCharWidth(delimiters[i].charCodeAt(0), scale);
					}
				}
			} else {
				if (newStr[newStr.length - 1] == " ") {
					newStr = newStr.slice(0, newStr.length - 1);
				}
				newStr += "\n";
    	        currWidth = 0;					// increment the number of lines
        	    lines++;
				i--;
			}
			continue;
        }
        newStr += words[i];
		if (i < delimiters.length) {
			if (delimiters[i] == "\n") {					
				newStr += "\n";
    	        currWidth = 0;				// increment the number of lines
   	    	    lines++;
			} else if (delimiters[i] != " ") {
				newStr += delimiters[i];
			} else {
				if (currWidth + getCharWidth(delimiters[i].charCodeAt(0), scale) > width) {
					newStr += "\n";
   			        currWidth = 0;				// increment the number of lines
    			    lines++;
				} else {
					newStr += delimiters[i];
					currWidth += getCharWidth(delimiters[i].charCodeAt(0), scale);
				}
			}
		}
    }
	for (i = newStr.length; i >= 0; i--) {
		while (newStr[i] == " ") {
			newStr = newStr.slice(0, i) + newStr.slice(i + 1);
		}
		while ((i >= 0) && (newStr[i])) {
			i--;
		}
	}
    lines = parseInt(lines * PFWR_CHAR[font][1] + getDescender(newStr) + getAscender(newStr) + 6) * scale / 100;
    return {"lines" : lines, "string" : newStr, "oldString": tag};

    function getWordWidth(word, scale) {           // returns the width of the word in px
        word_width = 0;
        if (word_width==null || word.length==null) return 0;
        for(ii=0; ii<word.length; ii++) {
            word_width += getCharWidth(word.charCodeAt(ii), scale);
			if (ii<word.length-1) {
	            word_width += getCharKerning(word.charCodeAt(ii), word.charCodeAt(ii+1), scale);
			}
        }
        return word_width;
    }

    function getCharWidth(char1, scale) {			// returns the width of individual character in px
        if (char1==null) return 0;			// from the mapping
        for(iii=3; iii<PFWR_CHAR[font].length;iii++) {
            if (PFWR_CHAR[font][iii]==char1) {
                return PFWR_CHAR_WIDTH[font][iii-1] * scale / 100;
            }
        }
        return PFWR_CHAR_WIDTH[font][1];
    };

    function getCharKerning(char1, char2, scale) {	// returns the width of individual character in px
        for(iii=1; iii<PFWR_KERNING[font].length;iii+=3) {
            if (PFWR_KERNING[font][iii]==char1 && PFWR_KERNING[font][iii+1]==char2) {
                return PFWR_KERNING[font][iii+2] * scale / 100;
            }
        }
        return 0;
    };
	
	function getDescender(word) {
		descender = 0;
		for (k=word.length-1; k>=0; k--) {
			if (word[k] == "\n")
				break;
	        for(iii=3; iii<PFWR_CHAR[font].length;iii++) {
    	        if (PFWR_CHAR[font][iii]==word.charCodeAt(k)) {
					if (PFWR_CHAR_DESC[font][iii-1] > descender)
						descender = PFWR_CHAR_DESC[font][iii-1];
					break;
            	}
	        }
		}
		return descender;
	}

	function getAscender(word) {
		ascender = 0;
		for (k=0; k<word.length; k++) {
			if (word[k] == "\n")
				break;
	        for(iii=3; iii<PFWR_CHAR[font].length;iii++) {
    	        if (PFWR_CHAR[font][iii]==word.charCodeAt(k)) {
					if (PFWR_CHAR_ASC[font][iii-1] > ascender)
						ascender = PFWR_CHAR_ASC[font][iii-1];
					break;
            	}
	        }
		}
		return ascender;
	}
};

/* end of mapping */

var hasFlash = function(){
	var nRequiredVersion = 6;

	if(navigator.appVersion.indexOf("MSIE") != -1 && navigator.appVersion.indexOf("Windows") > -1){
		document.write('<script language="VBScript"\> \non error resume next \nhasFlash = (IsObject(CreateObject("ShockwaveFlash.ShockwaveFlash." & ' + nRequiredVersion + '))) \n</script\> \n');
		/*	If executed, the VBScript above checks for Flash and sets the hasFlash variable.
			If VBScript is not supported it's value will still be undefined, so we'll run it though another test
			This will make sure even Opera identified as IE will be tested */
		if(window.hasFlash != null){
			return window.hasFlash;
		};
	};

	if(navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"] && navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin){
		var flashDescription = (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description;
		return parseInt(flashDescription.substr(flashDescription.indexOf(".") - 2,2),10) >= nRequiredVersion;
	};

	return false;
}();

String.prototype.normalize = function(){
	return this.replace(/\s+/g, " ");
};

/* IE 5.0 does not support the push method, so here goes */
if(Array.prototype.push == null){
	Array.prototype.push = function(){
		var i = 0, index = this.length, limit = arguments.length;
		while(i < limit){
			this[index++] = arguments[i++];
		};
		return this.length;
	};
};

/*	Implement function.apply for browsers which don't support it natively
	Courtesy of Aaron Boodman - http://youngpup.net */
if (!Function.prototype.apply){
	Function.prototype.apply = function(oScope, args) {
		var sarg = [];
		var rtrn, call;

		if (!oScope) oScope = window;
		if (!args) args = [];

		for (var i = 0; i < args.length; i++) {
			sarg[i] = "args["+i+"]";
		};

		call = "oScope.__applyTemp__(" + sarg.join(",") + ");";

		oScope.__applyTemp__ = this;
		rtrn = eval(call);
		oScope.__applyTemp__ = null;
		return rtrn;
	};
};

/*	The following code parses CSS selectors.
	This script however is not the right place to explain it,
	please visit the documentation for more information. */
var parseSelector = function(){
	var reParseSelector = /^([^#.>`]*)(#|\.|\>|\`)(.+)$/;
	function parseSelector(sSelector, oParentNode){
		var listSelectors = sSelector.split(/\s*\,\s*/);
		var listReturn = [];
		for(var i = 0; i < listSelectors.length; i++){
			listReturn = listReturn.concat(doParse(listSelectors[i], oParentNode));
		};

		return listReturn;
	};

	function doParse(sSelector, oParentNode, sMode){
		sSelector = sSelector.replace(" ", "`");
		var selector = sSelector.match(reParseSelector);
		var node, listNodes, listSubNodes, subselector, i, limit;
		var listReturn = [];

		if(selector == null){ selector = [sSelector, sSelector] };
		if(selector[1] == ""){ selector[1] = "*" };
		if(sMode == null){ sMode = "`" };
		if(oParentNode == null){
			oParentNode = document;
		};

		switch(selector[2]){
			case "#":
				subselector = selector[3].match(reParseSelector);
				if(subselector == null){ subselector = [null, selector[3]] };
				node = 	document.getElementById(subselector[1]);
				if(node == null || (selector[1] != "*" && !matchNodeNames(node, selector[1]))){
					return listReturn;
				};
				if(subselector.length == 2){
					listReturn.push(node);
					return listReturn;
				};
				return doParse(subselector[3], node, subselector[2]);
			case ".":
				if(sMode != ">"){
					listNodes = getElementsByTagName(oParentNode, selector[1]);
				} else {
					listNodes = oParentNode.childNodes;
				};

				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					if(node.nodeType != 1){
						continue;
					};
					subselector = selector[3].match(reParseSelector);
					if(subselector != null){
						if(node.className == null || node.className.match("(\\s|^)" + subselector[1] + "(\\s|$)") == null){
							continue;
						};
						listSubNodes = doParse(subselector[3], node, subselector[2]);
						listReturn = listReturn.concat(listSubNodes);
					} else if(node.className != null && node.className.match("(\\s|^)" + selector[3] + "(\\s|$)") != null){
						listReturn.push(node);
					};
				};
				return listReturn;
			case ">":
				if(sMode != ">"){
					listNodes = getElementsByTagName(oParentNode, selector[1]);
				} else {
					listNodes = oParentNode.childNodes;
				};

				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];

					if(node.nodeType != 1){
						continue;
					};

					if(!matchNodeNames(node, selector[1])){
						continue;
					};
					listSubNodes = doParse(selector[3], node, ">");
					listReturn = listReturn.concat(listSubNodes);
				};
				return listReturn;
			case "`":
				listNodes = getElementsByTagName(oParentNode, selector[1]);
				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					listSubNodes = doParse(selector[3], node, "`");
					listReturn = listReturn.concat(listSubNodes);
				};
				return listReturn;
			default:
				if(sMode != ">"){
					listNodes = getElementsByTagName(oParentNode, selector[1]);
				} else {
					listNodes = oParentNode.childNodes;
				};

				for(i = 0, limit = listNodes.length; i < limit; i++){
					node = listNodes[i];
					if(node.nodeType != 1){
						continue;
					};
					if(!matchNodeNames(node, selector[1])){
						continue;
					};
					listReturn.push(node);
				};
				return listReturn;
		};
	};

	function getElementsByTagName(oParentNode, sTagName){
		/*	IE5.x does not support document.getElementsByTagName("*")
			therefore we're falling back to element.all */
		if(sTagName == "*" && oParentNode.all != null){
			return oParentNode.all;
		};
		return oParentNode.getElementsByTagName(sTagName);
	};

	function matchNodeNames(node, sMatch){
		if(sMatch == "*"){
			return true;
		};
		return node.nodeName.toLowerCase().replace("html:", "") == sMatch.toLowerCase();
	};

	return parseSelector;
}();

/*	Adds named arguments support to JavaScript. */
function named(oArgs){
	return new named.Arguments(oArgs);
};

named.Arguments = function(oArgs){
	this.oArgs = oArgs;
};

named.Arguments.prototype.constructor = named.Arguments;

named.extract = function(listPassedArgs, oMapping){
	var oNamedArgs, passedArg;

	var i = listPassedArgs.length;
	while(i--){
		passedArg = listPassedArgs[i];
		if(passedArg != null && passedArg.constructor != null && passedArg.constructor == named.Arguments){
			oNamedArgs = listPassedArgs[i].oArgs; /* oNamedArgs isn't the named.Arguments class! */
			break;
		};
	};

	if(oNamedArgs == null){ return };

	for(sName in oNamedArgs){
		if(oMapping[sName] != null){
			oMapping[sName](oNamedArgs[sName]);
		};
	};

	return;
};

/**
 Function to redraw the elements on onResize event
**/

var doPFWRResize = function() {

    if (needResize==0) {
    	return;
    }
    // this recalculates the size of flash containers onResize event
    bodyObj = document.getElementsByTagName("body")[0]
    var PFWRSize = bodyObj.getAttribute("PFWR_SIZE");
    var winWOld = bodyObj.getAttribute("INIT_SCREEN_W");
    var winHOld = bodyObj.getAttribute("INIT_SCREEN_H");
    // all of these parameters are the initial size of the window
    var win = getWindowSize();
    if (PFWRSize>0) {
        // PFWR size is the count of the replaced tags (it is used to
        // get elements by id since they are given id as floowing PFWR_OBJ_ID_XXX
        // were XXX is a digit from 0 to PFWR_SIZE)
        var ratio = win.winW / winWOld;

        for (objI=1; objI<=PFWRSize; objI++) {
            // for each element we get the corresponding flash container
            var resizeObj = document.getElementById("PFWR_OBJ_ID_" + objI);

            // get its initial width attributes togeter with the attribute
            // of word lengths
            var initWidth = resizeObj.getAttribute("initWidth");
			var oldString = unescape(resizeObj.getAttribute("oldString"));
			var nScale = resizeObj.getAttribute("flashScale");

            var oldWidth = resizeObj.getAttribute("width");
            var newWidth = initWidth * ratio;
			var src = resizeObj.getAttribute("src");
			src = src.slice(0, src.length-4);
			if (oldWidth == newWidth) {
				continue;
			}
            // we calculate the new dimensions of the container
            // in respect to the changed size ratio
            interpreted = PFWR_Interpreter(oldString, newWidth, nScale, src);

            iFV = resizeObj.getAttribute("flashvars");

            // before we continue replace the FlashVars parameters with new
            // width and height params so that the flash redraws itself properly

            iFVarr = iFV.split("txt=");
			iFV = iFVarr[0];
            iFVarr = iFVarr[1].split("&");
            iFVarr[0] ="";
			if (navigator.userAgent.toLowerCase().indexOf("msie") > -1) {
				iFV += "txt=" + interpreted.string.replace(new RegExp("%\d{0}", "g"), "%25").replace(/\+/g, "%2B").replace(/&/g, "%26").replace(/\"/g, "%22") + iFVarr.join("&");
			} else {
				iFV += "txt=" + interpreted.string.replace(new RegExp("%(?!\d)", "g"), "%25").replace(/\+/g, "%2B").replace(/&/g, "%26").replace(/\"/g, "%22") + iFVarr.join("&");
			}

            iFVarr = iFV.split("h=");
            iFV = iFVarr[0];
            iFVarr = iFVarr[1].split("&");
            iFVarr[0] ="";
            iFV += "h=" + parseInt(interpreted.lines) + iFVarr.join("&");

            iFVarr = iFV.split("w=");
            iFV = iFVarr[0];
            iFVarr = iFVarr[1].split("&");
            iFVarr[0] = "";
            iFV += "w=" + parseInt(newWidth) + iFVarr.join("&");

            resizeObj.setAttribute("flashvars", iFV);
            resizeObj.setAttribute("width", newWidth);
            resizeObj.setAttribute("height", interpreted.lines);

            var containerObj = document.getElementById(replaced_ID[objI - 1]);
            // initiate the redrawing
            containerObj.innerHTML +="";

        }
    }
};


function getWindowSize() {
    // this function captures the window size
    // the values are then used to calculate resize ratio
    // for resizing function
    var winW=0, winH=0;

    if( typeof( window.innerWidth ) == 'number' ) {
        //Non-IE
        var thisWin = window;
        winW = thisWin.innerWidth;
        winH = thisWin.innerHeight;

    } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
        //IE 6+ in 'standards compliant mode'
        var thisWin = document;
        winW = thisWin.documentElement.clientWidth;
        winH = thisWin.documentElement.clientHeight;

    } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
        //IE 4 compatible
        var thisWin = document;
        winW = thisWin.body.clientWidth-35;
        winH = thisWin.body.clientHeight-35;
    }
    return {"winW" : winW, "winH" : winH};
}


/*	Executes an anonymous function which returns the function PFWR (defined inside the function).
	You can replace elements using PFWR.replaceElements()
	All other variables and methods you see are private. If you want to understand how this works you should
	learn more about the variable-scope in JavaScript. */
var PFWR = function(){
	/* Opera and Mozilla require a namespace when creating elements in an XML page */

    // DO NOT CHANGE THESE VAR - THEY MUST REMAIN A CONSTANT
    var objPrefix = "PFWR_OBJ_ID_"; // this will form the id's of flash objects
    var conPrefix = "PFWR_CON_ID_"; // this will form the id's of the div containers for flash + alt text
    var spanPrefix = "PFWR_SPAN_ID_"; // this will form the id's of the div containers for flash + alt text
    var conClass = "pfwr"; // this is the class name for DIV container
    var objClass = "pfwr-flash";    // this is the class name for flash objects
    var altClass = "pfwr-alternate"; // this is the class for alternative text

    var bodyAttr = "PFWR_SIZE"; // size of replaced
    var bodyScreenWAttr = "INIT_SCREEN_W";
    var bodyScreenHAttr = "INIT_SCREEN_H";

    var initWidthAttr = "initWidth"; // attribute to remember the initial width
    var oldStringAttr = "oldString"; // attribute to remember start string
    var scaleAttr = "flashScale"; // attribute to remember scale

    // Dynamic VARS
    var sizeOfReplaced = 0;   // counter of the changed elements (Prefix + this == id of the element)

    var needIEonResizePatch = false;    // patch for onResize event

	var sNameSpaceURI = "http://www.w3.org/1999/xhtml";
	var bIsInitialized = false;
    var bIsPrintCSSUpdated = false;
	var bIsSetUp = false;
	var bInnerHTMLTested = false;
	var sDocumentTitle;
	var stackReplaceElementArguments = [];
	var UA = function(){
		var sUA = navigator.userAgent.toLowerCase();
		var oReturn =  {
			bIsWebKit : sUA.indexOf("applewebkit") > -1,
			bIsSafari : sUA.indexOf("safari") > -1,
			bIsKonq: navigator.product != null && navigator.product.toLowerCase().indexOf("konqueror") > -1,
			bIsOpera : sUA.indexOf("opera") > -1,
			bIsXML : document.contentType != null && document.contentType.indexOf("xml") > -1,
			bHasTransparencySupport : true,
			bUseDOM : true,
			nFlashVersion : null,
			nOperaVersion : null,
			nGeckoBuildDate : null,
			nWebKitVersion : null
		};

		oReturn.bIsKHTML = oReturn.bIsWebKit || oReturn.bIsKonq;
		oReturn.bIsGecko = !oReturn.bIsWebKit && navigator.product != null && navigator.product.toLowerCase() == "gecko";
		if(oReturn.bIsGecko && sUA.match(/.*gecko\/(\d{8}).*/)){ oReturn.nGeckoBuildDate = new Number(sUA.match(/.*gecko\/(\d{8}).*/)[1]) };
    if(oReturn.bIsOpera && sUA.match(/.*opera(\s|\/)(\d+\.\d+)/)){ oReturn.nOperaVersion = new Number(sUA.match(/.*opera(\s|\/)(\d+\.\d+)/)[2]) };
		oReturn.bIsIE = sUA.indexOf("msie") > -1 && !oReturn.bIsOpera && !oReturn.bIsKHTML && !oReturn.bIsGecko;
		oReturn.bIsIEMac = oReturn.bIsIE && sUA.match(/.*mac.*/) != null;
		if(oReturn.bIsIE || (oReturn.bIsOpera && oReturn.nOperaVersion < 7.6)){ oReturn.bUseDOM = false };
		if(oReturn.bIsWebKit && sUA.match(/.*applewebkit\/(\d+).*/)){ oReturn.nWebKitVersion = new Number(sUA.match(/.*applewebkit\/(\d+).*/)[1]) };
		if(window.hasFlash && (!oReturn.bIsIE || oReturn.bIsIEMac)){
			var flashDescription = (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]).description;
			oReturn.nFlashVersion = parseInt(flashDescription.charAt(flashDescription.indexOf(".") - 1));
		};
		if(sUA.match(/.*(windows|mac).*/) == null ||
		oReturn.bIsIEMac || oReturn.bIsKonq ||
		(oReturn.bIsOpera && oReturn.nOperaVersion < 7.6) ||
		(oReturn.bIsSafari && oReturn.nFlashVersion < 7) ||
		(!oReturn.bIsSafari && oReturn.bIsWebKit && oReturn.nWebKitVersion < 312) ||
		(oReturn.bIsGecko && oReturn.nGeckoBuildDate < 20020523)){
			oReturn.bHasTransparencySupport = false;
		};

		if(!oReturn.bIsIEMac && !oReturn.bIsGecko && document.createElementNS){
			try {
				document.createElementNS(sNameSpaceURI, "i").innerHTML = "";
			} catch(e){
				oReturn.bIsXML = true;
			};
		};

		oReturn.bUseInnerHTMLHack = oReturn.bIsKonq || (oReturn.bIsWebKit && oReturn.nWebKitVersion < 312);

		return oReturn;
	}();

	/*	Disable PFWR for non-Flash or old browsers
		Also disable it for IE and KHTML browsers in XML mode, since we are using innerHTML for those browsers */
	if(window.hasFlash == false || !document.createElement || !document.getElementById || (UA.bIsXML && (UA.bUseInnerHTMLHack || UA.bIsIE))){
		return {UA:UA};
	};

	function PFWR(e){
		if((!self.bAutoInit && (window.event || e) != null) || !mayReplace(e)){
			return;
		};
		bIsInitialized = true;

		for(var i = 0, limit = stackReplaceElementArguments.length; i < limit; i++){
			replaceElements.apply(null, stackReplaceElementArguments[i]);
		};
		stackReplaceElementArguments = [];
	};

	var self = PFWR;

	function mayReplace(e){
		if(bIsSetUp == false || self.bIsDisabled == true || ((UA.bIsXML && UA.bIsGecko || UA.bIsKHTML) && e == null && bIsInitialized == false) || (document.body == null || document.getElementsByTagName("body").length == 0)){
			return false;
		};
		return true;
	};

	function escapeHex(sHex){
		if(UA.bIsIE){ /* The RegExp for IE breaks old Gecko's, the RegExp for non-IE breaks IE 5.01 */
			return sHex.replace(new RegExp("%\d{0}", "g"), "%25");
		}
		return sHex.replace(new RegExp("%(?!\d)", "g"), "%25");
	};

	function matchNodeNames(node, sMatch){
		if(sMatch == "*"){
			return true;
		};
		return node.nodeName.toLowerCase().replace("html:", "") == sMatch.toLowerCase();
	};

	function fetchContent(node, nodeNew, sCase, nLinkCount, sLinkVars){
		var sContent = "";
		var oSearch = node.firstChild;
		var oRemove, nodeRemoved, oResult, sValue;

		if(nLinkCount == null){ nLinkCount = 0 };
		if(sLinkVars == null){ sLinkVars = "" };

		while(oSearch){
			if(oSearch.nodeType == 3){
				sValue = oSearch.nodeValue.replace("<", "&lt;");
				switch(sCase){
					case "lower":
						sContent += sValue.toLowerCase();
						break;
					case "upper":
						sContent += sValue.toUpperCase();
						break;
					default:
						sContent += sValue;
				};
			} else if(oSearch.nodeType == 1){
				if(matchNodeNames(oSearch, "a") && !oSearch.getAttribute("href") == false){
					if(oSearch.getAttribute("target")){
						sLinkVars += "&sifr_url_" + nLinkCount + "_target=" + oSearch.getAttribute("target");
					};
					sLinkVars += "&sifr_url_" + nLinkCount + "=" + escapeHex(oSearch.getAttribute("href")).replace(/&/g, "%26");
					sContent += '<a href="asfunction:_root.launchURL,' + nLinkCount + '">';
					nLinkCount++;
				} else if(matchNodeNames(oSearch, "br")){
					sContent += "<br/>";
				};
				if(oSearch.hasChildNodes()){
					/*	The childNodes are already copied with this node, so nodeNew = null */
					oResult = fetchContent(oSearch, null, sCase, nLinkCount, sLinkVars);
					sContent += oResult.sContent;
					nLinkCount = oResult.nLinkCount;
					sLinkVars = oResult.sLinkVars;
				};
				if(matchNodeNames(oSearch, "a")){
					sContent += "</a>";
				};
			};
			oRemove = oSearch;
			oSearch = oSearch.nextSibling;
			if(nodeNew != null){
				nodeRemoved = oRemove.parentNode.removeChild(oRemove);
				nodeNew.appendChild(nodeRemoved);
			};
		};

		return {"sContent" : sContent, "nLinkCount" : nLinkCount, "sLinkVars" : sLinkVars};
	};

	function createElement(sTagName){
		if(document.createElementNS && UA.bUseDOM){
			return document.createElementNS(sNameSpaceURI, sTagName);
		} else {
			return document.createElement(sTagName);
		};
	};

	function createObjectParameter(nodeObject, sName, sValue){
		var node = createElement("param");
		node.setAttribute("name", sName);
		node.setAttribute("value", sValue);
		nodeObject.appendChild(node);
	};

	/*	Konqueror does not treat empty classNames as strings, so we need a workaround */
	function appendToClassName(node, sAppend){
		var sClassName = node.className;
		if(sClassName == null){
			sClassName = sAppend;
		} else {
			sClassName = sClassName.normalize() + (sClassName == "" ? "" : "-") + sAppend;
		};
		node.className = sClassName;
	};

	function prepare(bNow){
		//var node = document.documentElement;
		//if(self.bHideBrowserText == false){
		//	node = document.getElementsByTagName("body")[0];
		//};
		//if((self.bHideBrowserText == false || bNow) && node){
		//	if(node.className == null || node.className.match(/\bPFWR\-hasFlash\b/) == null){
		//		appendToClassName(node, "PFWR-hasFlash");
		//	};
		//};
	};

	function replaceElements(sSelector, sFlashSrc, sTextAlign, sCase, sWmode, nScale, fZoom, flashWidth, flashHeight){
        var sFlashVars = "";
        var initScale = "";
        var flagResize =  1;
		var	flagZoom = 0;

        if(!mayReplace()){
			return stackReplaceElementArguments.push(arguments);
		};

		prepare();

		/*	Extract any named arguments.	*/
		named.extract(arguments, {
			sSelector : function(value){ sSelector = value },
			sFlashSrc : function(value){ sFlashSrc = value },
			sTextAlign : function(value){ sTextAlign = value },
			sCase : function(value){ sCase = value },
			sWmode : function(value){ sWmode = value },
			nScale : function(value){ nScale = value },
			fZoom : function(value){ fZoom = value},
			flashWidth : function(value) {flashWidth = value},
			flashHeight: function(value) {flashHeight = value},
			initScale : function (value) {initScale=value},
			flagResize : function (value) {flagResize=value}
		});

		if (initScale=="") {
			initScale="noScale";
		}

		if (flagResize==0) {
			initScale="showall";
			flagZoom = 1;
		}

		/* Check if we can find any nodes first */
		var listNodes = parseSelector(sSelector);
		if(listNodes.length == 0){ return false };

		/*	Set default values. */
		if(sTextAlign != null) {sFlashVars += "&textalign=" + sTextAlign};

		if(nScale == null){ nScale = 100 }

		sWmode = "transparent"
		/*if(!UA.bHasTransparencySupport){
			sWmode = "opaque";
		}*/

		if(sWmode == null){ sWmode = "" };

		/*	Do the actual replacement. */
		var node, sWidth, sFlashWidth, sHeight, sFlashHeight, sMargin, sPadding, sVars, nodeAlternate, nodeFlash, oContent, oContent_safe;
        var nodeFlashTemplate = null;

		for(var i = 0, limit = listNodes.length; i < limit; i++){
			node = listNodes[i];

			/* Prevents elements from being replaced multiple times. */
            // PFWR-alternate is for alternative span NOT to be replaced
			if(node.className != null && (node.className.match(/\bpfwr\b/) != null || node.className.match(/\bpfwr\-alternate\b/) != null)){ continue };

			nodeDiv = createElement("div");
              // get the current dimentions of future flash container
              // width
              if (node.getAttribute("width")!=null) {
                  // html style notation
                  sWidth = node.getAttribute("width");
                  if (sWidth.match("%")=="%") {
                      sFlashWidth = parseInt(node.offsetWidth * (parseInt(sWidth)/100) );
                      nodeDiv.style.width = "100%";
                      nodeDiv.setAttribute("width", "100%");
                  } else if (UA.bIsOpera && (sWidth.match("-")=="-")) {
                      sWidth = (-parseInt(sWidth)) + "%";
                      sFlashWidth = parseInt(node.offsetWidth * (-parseInt(sWidth)/100)) ;
                      nodeDiv.style.width = "100%";
                      nodeDiv.setAttribute("width", "100%");
                  } else {
                      sFlashWidth = parseInt(sWidth);
                  }
              } else {
                  if (node.style != null && node.style.width !=null && node.style.width !="") {
                      // css style notation
                      sWidth = node.style.width;
                      if (sWidth.match("%")=="%") {
                          sFlashWidth = node.offsetWidth;
                          nodeDiv.style.width = "100%";
                          nodeDiv.setAttribute("width", "100%");
                      } else {
                          sFlashWidth = parseInt(sWidth);
                      }
                  } else {
                      sWidth = node.offsetWidth;
                      sFlashWidth = sWidth;
                      sWidth += "px";
                  }
              }
			
			nodeID = node.getAttribute("id");
			if (!nodeID)
				nodeID = [conPrefix, sizeOfReplaced+1].join("");
            // we use the interpreter to calculate the height according to set width
            initWidth = parseInt(sWidth.replace(/(px)|(%)/gi,""));
            interpreted = PFWR_Interpreter(node.innerHTML, initWidth, nScale, sFlashSrc.slice(sFlashSrc.lastIndexOf("/")+1, sFlashSrc.length-4));

            //sWidth and sHeight are the width and height of the flash container
            // sFlashHeight and sFlashWidth are parameters to be passed to flash
            if (!UA.bIsIE) {

              sFlashHeight = interpreted.lines;
              sHeight = sFlashHeight + "px";

            } else {

               sFlashWidth = initWidth;
               sWidth = sFlashWidth + "px";

               sFlashHeight = interpreted.lines;
               sHeight = sFlashHeight + "px";
            }

			if (!fZoom) {
	            nodeDiv.setAttribute("width", initWidth);
	            nodeDiv.setAttribute("height", sFlashHeight);
			}
            nodeDiv.setAttribute("id", nodeID);
            node.innerHTML += "";

            // if for some reason we are not able to parse width and height we block ourself
			if(sWidth==null || sHeight==null || sWidth=="" || sHeight=="" || sWidth=="px" || sHeight=="px"){
				self.bIsDisabled = true;
				document.documentElement.className = document.documentElement.className.replace(/\bPFWR\-hasFlash\b/, "");
				return;
			};


            // create an alternative text node
            if(UA.bUseDOM) {
			    nodeAlternate = createElement("span");
			    nodeAlternate.className = altClass;
			    oContent = fetchContent(node, nodeAlternate, sCase);
                oContent_safe = escapeHex(interpreted.string).replace(/\+/g, "%2B").replace(/&/g, "%26").replace(/\"/g, "%22");
                sVars = "txt=" + oContent_safe + sFlashVars + "&w=" + sFlashWidth + "&h=" + sFlashHeight + "&scale=" + nScale +
				"&fzoom=" + flagZoom + oContent.sLinkVars;
                nodeAlternate.setAttribute("id", spanPrefix + parseInt(sizeOfReplaced + 1));
            } else {
                oContent_safe = escapeHex(interpreted.string).replace(/\+/g, "%2B").replace(/&/g, "%26").replace(/\"/g, "%22");
                sVars = "txt=" + oContent_safe + sFlashVars + "&w=" + sFlashWidth + "&h=" + sFlashHeight + "&scale=" + nScale + 
				"&fzoom=" + flagZoom;
            }

			appendToClassName(node, conClass);

			/*	Opera only supports the object element, other browsers are given the embed element,
				for backwards compatibility reasons between different browser versions.
				Opera versions below 7.60 use innerHTML, from 7.60 and up we use the DOM */

			if(nodeFlashTemplate == null || !UA.bUseDOM){


            /**
            NOTE AS OF 10/07/2007: DO NOT USE "Object" TAG - it causes problems with scaling of flash
            **/
                // create the "embed" flash objects
				if(!UA.bUseDOM){
                // all IE problems below this line
                   nodeDiv.innerHTML = ['<embed id="', objPrefix, sizeOfReplaced+1,'" name="', objPrefix, sizeOfReplaced+1,'" class="', objClass, '" type="application/x-shockwave-flash" src="', sFlashSrc, '" quality="best" wmode="', sWmode, '" flashvars="', sVars, '&flashName=', objPrefix, sizeOfReplaced+1,'" width="', sWidth, '" height="', sHeight, '" ', initWidthAttr, '="', initWidth, '" ', scaleAttr, '="', nScale,  '" ', oldStringAttr, '="', escape(interpreted.oldString), '" ', ' PFWR="true" allowScriptAccess="always" scale=', initScale, '></embed>','<span class="', altClass, '" id="', spanPrefix, sizeOfReplaced+1, '">', oContent_safe , '</span>'].join("");
                    sizeOfReplaced++;
				} else {
                // all Firefox & Opera problems below this line
				    nodeFlash = createElement("embed");
					nodeFlash.setAttribute("src", sFlashSrc);
					nodeFlash.setAttribute("quality", "best");
					nodeFlash.setAttribute("flashvars", sVars);
					nodeFlash.setAttribute("wmode", sWmode);
					nodeFlash.setAttribute("pluginspace", "http://www.macromedia.com/go/getflashplayer");
					nodeFlash.setAttribute("scale", initScale);

					nodeFlash.setAttribute("PFWR", "true");
                    nodeFlash.setAttribute("allowScriptAccess", "always");
					nodeFlash.setAttribute("type", "application/x-shockwave-flash");
					nodeFlash.className = objClass;
					if(!UA.bIsKHTML || !UA.bIsXML){
						nodeFlashTemplate = nodeFlash.cloneNode(true);
					};
				};
			} else {
				nodeFlash = nodeFlashTemplate.cloneNode(true);

			};
			if(UA.bUseDOM){
				/* General settings */

				nodeFlash.setAttribute("flashvars", sVars + "&flashName=" + objPrefix + parseInt(sizeOfReplaced+1));

                nodeFlash.setAttribute("id", "" + objPrefix + parseInt(sizeOfReplaced+1));
                nodeFlash.setAttribute("name", "" + objPrefix + parseInt(sizeOfReplaced+1));
				nodeFlash.setAttribute("width", sWidth);
				nodeFlash.setAttribute("height", sHeight);
                nodeFlash.setAttribute(initWidthAttr, initWidth);
                nodeFlash.setAttribute(oldStringAttr, escape(interpreted.oldString));
                nodeFlash.setAttribute(scaleAttr, nScale);
                // NOTE: do NOT set style since it overlaps and creates problems with % width and height
				nodeDiv.appendChild(nodeFlash);
                nodeDiv.appendChild(nodeAlternate);
//				nodeDiv.appendChild(nodeRemoved);
//	            nodeDiv.setAttribute("height", sFlashHeight);
                sizeOfReplaced++;
			};
			node.parentNode.replaceChild(nodeDiv, node);
			//nodeRemoved = node.parentNode.removeChild(node);
			
			replaced_ID = replaced_ID.concat(nodeID);
			nodeDiv.innerHTML += "";

		};

		if(UA.bIsIE && self.bFixFragIdBug){
			setTimeout(function(){document.title = sDocumentTitle}, 0);
		};

        // onResize patch

        onResizeIEpatch();

        if (flagResize==0)
        	needResize=0;

        // set style sheets for correct printing
        updatePrintCSS();
        // set the quantity of replaced elements
        bodyObj = document.getElementsByTagName("body")[0]
        bodyObj.setAttribute(bodyAttr, sizeOfReplaced);

        // set the window initial size
        win = getWindowSize();
        bodyObj.setAttribute(bodyScreenWAttr, win.winW);
        bodyObj.setAttribute(bodyScreenHAttr, win.winH);
	};

	function updateDocumentTitle(){
		sDocumentTitle = document.title;
	};

    function updatePrintCSS() {
        if (!self.bIsPrintCSSUpdated) {
          if (self.UA.bIsIE) {
            var cssLinks = document.getElementsByTagName("link");
            for(var i=0; i<cssLinks.length; i++) {
                if (cssLinks[i].getAttribute("rel") == "stylesheet" &&
                    cssLinks[i].getAttribute("media") == "print" &&
                    cssLinks[i].getAttribute("href").match("PFWR-print.css")) {

                    cssLinks[i].setAttribute("href", cssLinks[i].getAttribute("href").replace("PFWR-print.css", "PFWR-print-ie.css"));
                    self.bIsPrintCSSUpdated = true;
                    return;
                }
            }
          } else {
              self.bIsPrintCSSUpdated = true;
          }
        }
    }


    function onResizeIEpatch() {
      if (self.needIEonResizePatch==true) {
            var bodyObj = document.getElementsByTagName("body")[0];
            if (typeof bodyObj.onresize == "function") {
                var fOld = bodyObj.onresize;
                bodyObj.onresize = function(){ fOld(); doPFWRResize(); };
            } else {
                bodyObj.onresize = doPFWRResize;
            }
            // attaching onResize in IE causes it to go into an infinite loop
            // so we need this patch
            self.needIEonResizePatch = false;
        };
    };

	function setup(){
		if(self.bIsDisabled == true){ return };

		bIsSetUp = true;
		/*	Providing a hook for you to hide certain elements if Flash has been detected. */
		if(self.bHideBrowserText){
			prepare(true);
		};

        if (UA.bIsIE) { // IE
            self.needIEonResizePatch=true;
        } else {
    		if(window.attachEvent){
    			window.attachEvent("onload", PFWR);
                window.attachEvent("onresize", doPFWRResize);
    		} else if(!UA.bIsKonq && (document.addEventListener || window.addEventListener)){
    			if(document.addEventListener){
    				document.addEventListener("load", PFWR, false);
   	                document.addEventListener("resize", doPFWRResize, false);
    			};
    			if(window.addEventListener){
    				window.addEventListener("load", PFWR, false);
   	                window.addEventListener("resize", doPFWRResize, false);
    			};
    		} else {
    			if(typeof window.onload == "function"){
    				var fOld = window.onload;
    				window.onload = function(){ fOld(); PFWR(); };
    			} else {
    				window.onload = PFWR;
    			};
    			if(typeof window.onresize == "function"){
    				var fOld = window.onresize;
   					window.onresize = function(){ fOld(); doPFWRResize(); };
    			} else {
    				window.onresize = doPFWRResize;
    			};
    		};
        };

		if(!UA.bIsIE || window.location.hash == ""){
			self.bFixFragIdBug = false;
		} else {
			updateDocumentTitle();
		};
	};

	function debug(){
		prepare(true);
	};

	debug.replaceNow = function(){
		setup();
		PFWR();
	};

	/* Public Fields */
	self.UA = UA;
	self.bAutoInit = true;
	self.bFixFragIdBug = true;
	self.replaceElements = replaceElements;
	self.updateDocumentTitle = updateDocumentTitle;
	self.appendToClassName = appendToClassName;
	self.setup = setup;
	self.debug = debug;
	self.bIsDisabled = false;
	self.bHideBrowserText = true;

	return self;
}();

/*	PFWR setup. You can add browser detection here.
	PFWR's browser detection is exposed through PFWR.UA. */

var needResize = 1;
var replaced_ID = new Array();

if(typeof PFWR == "function" && !PFWR.UA.bIsIEMac){
	PFWR.setup();
};
