    // Copyright 2008 www.flexcapacitor.com, www.drumbeatinsight.com
    // Version 4.0

    // global array of html elements
    var fcHTMLControls = new Array();
    var fcEventTimeoutInterval = 200;
    var fcExistingOnBeforeUnload;
    var fcRelativeMovie = false;

    // blur xinha editor
    function fcAddBlurHandler() {
        this._doc.xinhaEditor = this;
        Xinha._addEvent(this._doc, "blur", function() {
            var movie = fcGetMovieById(this.xinhaEditor.movieId);
            //movie.xinhaBlur();
            window.focus();
            movie.focus();
        });
    }

    // add HTML element to the page
    function fcAddChild(o) {
        var movie = fcGetMovieById(o.movieId);
        fcHTMLControls.movieId = o.movieId;

        if (String(o.chrome)=="true") {
            fcAddChildPopUp(o);
        }
        else if (o.type=="division") {
            fcAddChildDivision(o);
        }
        else if (o.type=="iframe") {
            fcAddChildIFrame(o);
        }
        else if (o.type=="editor") {
            fcAddChildEditor(o);
        }
    }

    // add division to the page
    function fcAddChildDivision(o) {
        fcGetIncludes(o.includesBefore);
        var newElement = document.createElement("div");
        newElement.id = o.id;
        newElement.name = o.name;
        newElement.movieId = o.movieId;

        newElement.style.position = o.position;

        if (String(o.fitToContentHeight)=="true") {
            o.height = "";
        }
        fcSetSize(newElement,o.width,o.height);
        fcMoveElementTo(newElement,o.x,o.y);
        newElement.style.backgroundColor = "#" + o.backgroundColor;
        newElement.style.padding = o.padding;
        newElement.style.margin = "0px";
        // always 0px - do not add a border to the container div tag
        // add a border in mxml or add a child div tag in the htmlText property and add a border to that
        newElement.style.border = o.border;
        newElement.innerHTML = o.htmlText;

        document.body.appendChild(newElement);

        fcAddToGlobalArray(newElement, o);
        fcSetScrollPolicyById(o.id, o.htmlScrollPolicy);

        fcGetIncludes(o.includesAfter);

        if (String(o.visible)=="false") {
            fcHide(o.id,true,false);
        }

        fcDelayedDispatchEvent("htmlCreationComplete", o.movieId, o.id, fcEventTimeoutInterval);
    }

    // add an editor to the page
    function fcAddChildEditor(o) {
        // Add new editors here
        // There are three places to add new editor support.
        // here, getHTML, setHTML and if possible, call htmlCreationComplete when the editor has been created
        // see FCKeditor_OnComplete for an example

        // if the editor is generated with the same id, same textarea should be used
        var el = document.getElementById(o.id);
        if (el!=null) return;

        // we add this control early on editors
        fcHTMLControls[o.id] = new Object();

        fcGetIncludes(o.includesBefore);
        var editorName = o.name + "Editor";
        var newElement = document.createElement("div");
        newElement.id = o.id;
        newElement.name = o.name;
        newElement.movieId = o.movieId;

        newElement.style.position = o.position;
        fcSetSize(newElement,o.width,o.height);
        fcMoveElementTo(newElement,o.x,o.y);
        newElement.style.backgroundColor = "#" + o.backgroundColor;
        newElement.style.padding = o.padding;
        newElement.style.margin = "0px";
        newElement.style.border = o.border;

        var textareaElement = document.createElement("textarea");
        textareaElement.id = editorName;
        textareaElement.name = editorName;
        textareaElement.value = o.htmlText;
        fcSetSize(textareaElement,"100%","100%");
        newElement.appendChild(textareaElement);

        document.body.appendChild(newElement);
        fcSetScrollPolicyById(o.id, o.htmlScrollPolicy);

        // add additional editor support here
        if (o.editorType=="fckeditor") {
            // Create an instance of FCKeditor (using the target textarea as the name).
            var oFCKeditor = new FCKeditor( editorName ) ;
            oFCKeditor.BasePath = o.editorPath;
            if (o.configPath) {
                oFCKeditor.Config["CustomConfigurationsPath"] = o.configPath +"?" + ( new Date() * 1 ) ;
            }
            oFCKeditor.Width = '100%';
            oFCKeditor.Height = '100%';
            oFCKeditor.ReplaceTextarea();

            fcHTMLControls[o.id].editor = oFCKeditor;
        }
        else if (o.editorType=="tinymce") {
            var elm = document.getElementById(o.id);

            if (typeof o.editorOptions == "string") {
                // crashes firefox??? maybe set a timeout?
                //tinyMCE.init({mode:"exact",theme:"simple"});
            }
            else {
                tinyMCE.init(o.editorOptions);
            }

            if (tinyMCE.getInstanceById(editorName) == null) {
                // cannot find editor sometimes. causes crash. maybe set a timeout?
                //tinyMCE.execCommand('mceAddControl', false, editorName);
            }
            fcHTMLControls[o.id].editor = elm
            fcHTMLControls[o.id].loaded = true;
            // when editor is ready dispatch creation complete
            //fcDelayedDispatchEvent("htmlCreationComplete", o.movieId, o.id, fcEventTimeoutInterval);
        }
        else if (o.editorType=="xinha") {
            // if script not declared use only textarea
            if (typeof Xinha != "undefined") {
                var c = new Xinha.Config();
                c.showLoading = true;
                var ed = new Xinha(editorName, c);
                fcHTMLControls[o.id].editor = ed
                ed.movieId = o.movieId;
                ed.generate();
                ed._onGenerate = fcAddBlurHandler;
                ed.whenDocReady = function(e) {
                    fcHTMLControls[o.id].loaded = true;
                    fcDelayedDispatchEvent("htmlCreationComplete", o.movieId, o.id, fcEventTimeoutInterval);
                }
            } else {
                fcHTMLControls[o.id].editor = textareaElement;
            }
        }

        fcAddToGlobalArray(newElement, o);

        if (String(o.visible)=="false") {
            fcHide(o.id,true,false);
        }

    }

    // add iframe to the page
    function fcAddChildIFrame(o) {
        var newElement = document.createElement("iframe");
        newElement.id = o.id;
        newElement.name = o.name;
        newElement.movieId = o.movieId;
        newElement.width = o.width;
        newElement.height = o.height;
        newElement.frameBorder = o.frameborder;
        newElement.style.position = o.position;
        fcSetSize(newElement,o.width,o.height);
        fcMoveElementTo(newElement,o.x,o.y);
        //newElement.style.backgroundColor = "transparent";
        // always 0px - do not add a border to the iframe itself
        // add a child div and add a border to that or add border in mxml
        newElement.style.border = o.border;
        newElement.style.padding = o.padding;
        newElement.src = o.source;

        //  use innerHTML or DOM element creation methods to put content into body
        document.body.appendChild(newElement);

        newElement.onload = new function() {
            // set a flag so the application knows the page is loaded
            fcDelayedDispatchEvent("htmlCreationComplete", o.movieId, o.id, fcEventTimeoutInterval);
        }

        newElement.onunload = new function() {
            // set a flag so the application knows the page is unloading
            // can we purge this from memory here?
            fcDispatchEvent("htmlUnload", o.movieId, o.id);
        }

        fcAddToGlobalArray(newElement, o);

        if (String(o.visible)=="false") {
            fcHide(o.id,true,false);
        }

    }

    // add mocha ui pop up to the page
    function fcAddChildPopUp(o) {
        fcGetIncludes(o.includesBefore);
        var p = new Object();
        p.id = o.id;
        p.content = o.htmlText;
        p.x = o.x;
        p.y = o.y;
        if (String(o.centerPopUp)!="true") {
            p.x = o.x;
            p.y = o.y;
        }
        p.contentURL = String(o.source);
        p.bodyBgColor = "" + o.backgroundColor;
        p.title = o.title;
        p.modal = o.modal;
        p.width = o.width;
        p.height = o.height;
        p.minimizable = o.minimizable;
        p.maximizable = o.maximizable;
        //p.paddingVertical = parseInt(o.padding); 10
        //p.paddingHorizontal = parseInt(o.padding); 12

        p.onContentLoaded = function (e) {
            fcDelayedDispatchEvent("htmlPopUpContentLoaded", o.movieId, o.id, fcEventTimeoutInterval)
        }
        p.onFocus = function (e) {
            fcDispatchEvent("htmlPopUpFocus", o.movieId, o.id)
        }
        p.onResize = function (e) {
            fcDispatchEvent("htmlPopUpResize", o.movieId, o.id)
        }
        p.onMinimize = function (e) {
            fcDispatchEvent("htmlPopUpMinimize", o.movieId, o.id)
        }
        p.onMaximize = function (e) {
            fcDispatchEvent("htmlPopUpMaximize", o.movieId, o.id)
        }
        p.onClose = function (e) {
            // we need to listen to this event and handle it in flex html manager class for alerts
            fcDispatchEvent("htmlPopUpClose", o.movieId, o.id)
        }
        p.onCloseComplete = function (e) {
            fcDispatchEvent("htmlPopUpCloseComplete", o.movieId, o.id)
        }

        // html, xhr, or iframe
        if (o.type == "division") {
            p.loadMethod = "html";
        }
        else if (o.type == "iframe") {
            p.loadMethod = "iframe";
        }
        else if (o.type == "xhr") {
            p.loadMethod = "xhr";
        }

        if (String(o.chrome)=="true" && document.mochaUI) {
            document.mochaUI.newWindow(p, false);
        }

        fcAddToGlobalArray(fcGetElement(o.id), o);

        fcGetIncludes(o.includesAfter);

        if (String(o.visible)=="false") {
            //fcHide(o.id,true,false);
        }

        // dispatch when window is created
        fcDelayedDispatchEvent("htmlCreationComplete", o.movieId, o.id, fcEventTimeoutInterval);
        if (String(o.alert)=="true") {
            var newElement = document.createElement("div");
            newElement.id = o.id + "_alert_buttons";
            newElement.movieId = o.movieId;
            //newElement.style.position = "absolute";
            //newElement.style.bottom = "6px";
            //newElement.style.right = "6px";
            newElement.className = "mochaAlertButtons"; // set in css/mocha.css

            for (var i=0;i<o.alertButtons.length;i++) {
                var button = document.createElement("input");
                var value = o.alertButtons[i];
                button.type = "button";
                button.value = value;
                button.className = "mochaAlertButton"; // set in css/mocha.css

                button.onclick = function(e) {
                    fcDispatchEvent2("htmlAlertHandler", o.movieId, o.id, this.value);
                    var el = fcGetElement(o.id);
                    if(document.mochaUI) {
                        document.mochaUI.closeWindow(el);
                    }
                }
                newElement.appendChild(button);
            }

            var el = fcGetElement(o.id);
            el.appendChild(newElement);
        }
    }

    //usage: var currentTarget = fcEventTrigger (e);
    function fcEventTrigger (e) {
        if (!e) { e = event; }
        return e.target || e.srcElement;
    }

    // add to associative array - do we need to make any changes for garbage collecting?
    function fcAddToGlobalArray(el, o) {
        var newElement = new Object();
        newElement.element = el; // could cause memory leak do we need it?
        newElement.id = o.id;
        newElement.loaded = false;
        newElement.type = o.type;
        newElement.popUp = o.chrome;
        newElement.alert = o.alert;
        newElement.movieId = o.movieId;
        if (o.type == "editor") {
            // set first in addChildEditor
            newElement.editor = fcHTMLControls[o.id].editor;
        }
        else {
            newElement.editor = "";
        }

        fcHTMLControls[o.id] = newElement;
    }

    // evaluates a script and returns the value - note use ExternalInterface to call functions
    function fcCallScript(str) {
        try {
            var something = eval(str);
            return something;
        }
        catch(e) {
            return false;
        }
    }

    // dispatch creation complete event
    function fcDispatchEvent(eventName, movieId, id) {
        var movie = fcGetMovieById(movieId);
        // workaround for offset problem under Linux/Firefox (DaN, 2009-08-25):
        if (movie == undefined) {
            movie = document.getElementById("flashApp");
        }
        movie[eventName](id);
    }

    // dispatch creation complete event
    function fcDispatchEvent2(eventName, movieId, id, value) {
        var movie = fcGetMovieById(movieId);
        movie[eventName](id, value);
    }

    // call actionscript function after specified delay
    // we do this to give the browser and flash time to sync
    function fcDelayedDispatchEvent(eventName,movieId,id,delay) {
        setTimeout("fcDispatchEvent('"+eventName+"','"+movieId+"','"+id+"')",delay);
    }

    // handle when flash text field gets focus, text field in iframe is greedy
    function fcDefocus(movieId) {
        var movie = fcGetMovieById(movieId);
        window.focus();
        movie.focus();
    }

    // finds the absolute position of the swf movie
    function fcFindPosition(obj) {
        var left = obj.offsetLeft;
        var top = obj.offsetTop;
        if (obj.offsetParent) {
            var parentPos = this.fcFindPosition(obj.offsetParent);
            if (parentPos[0]) left += parentPos[0];
              if (parentPos[1]) top += parentPos[1];
         }
        return [left,top];
     }

    // The FCKeditor_OnComplete function is a special function called everytime an
    // editor instance is completely loaded and available for API interactions.
    function FCKeditor_OnComplete(editorInstance) {
        var editor = fcGetElement(editorInstance.Name);
        if (editor) {
            fcHTMLControls[editor.parentNode.id].loaded = true;
            fcDelayedDispatchEvent("htmlCreationComplete", editor.parentNode.movieId, editor.parentNode.id, fcEventTimeoutInterval);
        }
    }

    // gets the element by name
    function fcGetElement(id) {
        return document.getElementById(id);
    }

    // cannot get height of pages loaded from different domains
    // ie, page is hosted at www.yoursite.com and you load www.google.com will fail with return value of -1
    // works in ff and ie. not tested in mac browsers -
    function fcGetElementHeight(id){
        var el = fcGetElement(id);
        moz = (document.getElementById && !document.all);

        if (el) {

            // check the height value
            try {

                /*** return div height ***/
                if (el.nodeName.toLowerCase()=="div") {
                    var scrollHeight = el.scrollHeight;
                    var divHeight = el.style.height;
                    divHeight = (scrollHeight > parseInt(divHeight)) ? scrollHeight : divHeight;
                    return divHeight;
                }

                /*** return iframe height ***/
                //moz
                if (moz) {
                    return el.contentDocument.body.scrollHeight;
                }
                else if (el.Document) {
                    return el.Document.body.scrollHeight;
                }
            }
            catch(e) {
                //An error is raised if the content in the iframe is not from the same domain as the swf
                //alert('Error: ' + e.number + '; ' + e.description+'\nPossibly - Cannot access height of iframe because the content is from another dudes domain');
                return -1;
            }
        }
    }

    // get property value
    function fcGetElementValue(id, elProperty){

        // if periods are in the name assume absolute path
        // otherwise assume element id
        if (id.indexOf('.')!=-1) {
            var newArr = id.split('.');
            var elValue = "";

            try {
                el = window;
                for (var i=0;i < newArr.length;i++) {
                    el = el[newArr[i]];
                }
                return el;
            }
            catch (e) {
                //alert("Whoooops!! Cant find " + id);
                // should return null or undefined here
                return -1;
            }
        }
        else {
            // try and get property value
            try {
                var el = fcGetElement(id);
                var elValue = el[elProperty];
                return elValue;
            }
            catch(e) {
                //alert("Error: Can't find " + id + "." + elProperty);
                // should return null or undefined here
                return -1;
            }
        }
    }

    // get HTML content
    function fcGetHTML(id, elementType, editorType, chrome) {
        var el = fcGetElement(id);
        if (el!=null) {

            if (elementType =="division" && String(chrome)=="true") {
                var elContent = fcGetElement(id + "_content");
                if (elContent != null) {
                    return String(elContent.innerHTML);
                }
            }
            else if (elementType=="division") {
                return el.innerHTML;
            }
            else if (elementType == "editor") {
                var oEditor;

                // add additional editor support here
                if (editorType=="fckeditor") {
                    if ( typeof( FCKeditorAPI ) != 'undefined' ) {
                        oEditor = FCKeditorAPI.GetInstance( id + "Editor" );
                        if ( oEditor )	{
                            // Get the current text in the editor.
                            return oEditor.GetXHTML();
                        }
                    }
                }
                else if (editorType=="tinymce") {
                    return tinyMCE.getContent(id);
                }
                else if (editorType=="xinha") {
                    //var ed = editors[id];
                    var ed = fcHTMLControls[id].editor;
                    if (typeof Xinha != "undefined") {
                        return ed.getHTML();
                    }
                    return ed.value;
                }

            }
        }
        return "";
    }

    // get the scripts dynamically to include
    function fcGetIncludes(includes) {
        var len = includes.length;
        //var head = document.getElementsByTagName("head");
        // sometimes this doesn't work. possibly browser or sandbox issues. in those cases edit the html page and add scripts manually
        for (var i=0;i<len;i++) {
            var el = document.createElement("script");
            //el.onload = onload2;
            el.setAttribute("src",includes[i]);
            el.setAttribute("type","text/javascript");
            document.body.appendChild(el);
        }
    }

    // get reference to the flash movie
    function fcGetMovieById(id) {
        if (navigator.appName.indexOf ("Microsoft") !=-1) {
            return window[id];
        } else if (window.document[id]) {
            return window.document[id];
        } else {
            return window.document.getElementById(id);
        }
    }

    // hide element by name
    // set height of content to 0px so the
    // flash context menu appears in the right location
    // note: display none also fixes the issue but have not implemented yet
    function fcHide(id, hideOffscreen, offscreenOffset) {
        var el = fcGetElement(id);
        if (hideOffscreen) {
            //el.style.width = "0px";
            //el.style.height = "0px";
        }
        //el.style.visibility = "hidden";
        el.style.display = "none";
    }

    // move element to new location
    function fcMoveElementTo(el,x,y) {
        var movie = fcGetMovieById(el.movieId);
        if (fcRelativeMovie) {
            el.style.left = parseInt(x) + fcFindPosition(movie)[0] + "px";
            el.style.top = parseInt(y) + fcFindPosition(movie)[1] + "px";
        }
        else {
            el.style.left = parseInt(x) + "px";
            el.style.top = parseInt(y) + "px";
        }
    }

    // warn user if they or a link try to navigate them away from the page - used to prevent data loss / save changes
    function fcPromptOnUnload(prompt, message) {
        if (String(prompt) == "true") {
            // todo wrap existing function if it exists
            //fcExistingOnBeforeUnload = (window.onbeforeunload!=null) ? window.onbeforeunload : null;
            window.onbeforeunload = function (e) {
                //if (fcExistingOnBeforeUnload) {
                //	fcExistingOnBeforeUnload();
                //}
                //fcPurge(document.body);
                return message;
            };
        }
        else {
            window.onbeforeunload = function (e) {
                // see you later
                //if (fcExistingOnBeforeUnload) {
                //	fcExistingOnBeforeUnload();
                //}
            }
        }
    }

    // call before removing from DOM - necessary?
    // credit - http://javascript.crockford.com/memory/leak.html
    function fcPurge(d) {
        var a = d.attributes, i, l, n;
        if (a) {
            l = a.length;
            for (i = 0; i < l; i += 1) {
                n = a[i].name;
                if (typeof d[n] === 'function') {
                    d[n] = null;
                }
            }
        }
        a = d.childNodes;
        if (a) {
            l = a.length;
            for (i = 0; i < l; i += 1) {
                fcPurge(d.childNodes[i]);
            }
        }
    }

    // forces redraw
    function fcRefresh(id) {
        var el = fcGetElement(id);
        el.style.cssText = el.style.cssText;
    }

    // remove and get memory back
    function fcRemove(id) {
        //fcHide(id, true);
        var el = fcGetElement(id);
        var elParent = el.parentNode;
        fcPurge(el);
        fcHTMLControls[id] = null;
        elParent.removeChild(el);
    }

    // clips the html content
    function fcSetClip(id, top, right, bottom, left) {
        var el = fcGetElement(id);
        if (el!=null) {
            el.style.clip = "rect(" + top + " " + right + " " + bottom + " " + left  + ")";
        }
    }

    // set document title
    function fcSetDocumentTitle(title) {
        window.document.title = title;
    }

    // set HTML content
    function fcSetHTML(id, htmlText, elementType, editorType, chrome) {
        var el = fcGetElement(id);
        if (el!=null) {

            if (elementType =="division" && String(chrome)=="true") {
                var elContent = fcGetElement(id + "_content");
                elContent.innerHTML = htmlText;
            }
            else if (elementType =="division") {
                el.innerHTML = htmlText;
            }
            else if (elementType == "editor") {
                var oEditor;

                // add additional editor support here
                if (editorType == "fckeditor") {
                    if ( typeof( FCKeditorAPI ) != 'undefined' ) {
                        oEditor = FCKeditorAPI.GetInstance( id + "Editor" );
                        if ( oEditor )	{
                            // Set the text in the editor.
                            oEditor.SetHTML( htmlText ) ;
                        }
                    }
                }
                else if (editorType=="tinymce") {
                    var editor = tinyMCE.getInstanceById(id+"Editor");
                    editor.setHTML(htmlText);
                }
                else if (editorType=="xinha") {
                    //var ed = editors[id];
                    var ed = fcHTMLControls[id].editor;
                    if (typeof Xinha != "undefined") {
                        ed.setEditorContent(htmlText);
                    }
                    else {
                        ed.value = htmlText;
                    }
                }
            }
        }
    }

    // set position - should we use fcFindPosition here?
    function fcSetPosition(id,x,y) {
        var el = fcGetElement(id);
        var movie = fcGetMovieById(fcHTMLControls[id].movieId);
        if (fcHTMLControls[id].popUp == true ) { return }

        // workaround for offset problem under Linux/Firefox (DaN, 2009-08-25):
        if (movie == undefined) {
            movie = document.getElementById("flashApp");
        }

        // LEFT
        if (x != undefined) {
            el.style.left = parseInt(x) + fcFindPosition(movie)[0] + "px";
        }
        // TOP
        if (y != undefined) {
            el.style.top = parseInt(y) + fcFindPosition(movie)[1] + "px";
        }
    }

    // set scroll policy of element
    function fcSetScrollPolicy(el, overflow) {
        if (overflow != "resize") {
            el.style.overflow = overflow;
        }
    }

    // save cpu when movie is at upper left corner of window
    function fcSetRelativeMovie(isRelative) {
        fcRelativeMovie = (String(isRelative)!="false") ? true : false;
    }

    // set scroll policy of element by id
    function fcSetScrollPolicyById(id, overflow) {
        var el = fcGetElement(id);

        // setting this to anything other than auto in ff fails it
        if (overflow != "resize") {
            el.style.overflow = overflow;
        }
    }

    // set size
    function fcSetSize(el,w,h) {

        if (String(w)!="undefined" && String(w)!="") {
            // if width is a percentage pass in the string as is
            if (String(w).indexOf("%")!=-1) {
                el.style.width = w;
            }
            else {
                el.style.width = parseInt(w) + "px";
            }
        }

        if (String(h)!="undefined" && String(h)!="") {
            if (String(h).indexOf("%")!=-1) {
                el.style.height = h;
            }
            else {
                el.style.height = parseInt(h) + "px";
            }
        }
    }

    // set size called by id
    function fcSetSizeByValue(id,w,h) {
        var el = fcGetElement(id);
        if (el.style.display=="none") { return; }
        if (fcHTMLControls[id].popUp == true ) { return }

        if (String(w)!="undefined" && String(w)!="") {
            // if width is a percentage pass in the string as is
            if (String(w).indexOf("%")!=-1) {
                el.style.width = w;
            }
            else {
                el.style.width = parseInt(w) + "px";
            }
        }

        if (String(h)!="undefined" && String(h)!="") {
            if (String(h).indexOf("%")!=-1) {
                el.style.height = h;
            }
            else {
                el.style.height = parseInt(h) + "px";
            }
        }
    }

    // set iframe location
    function fcSetSource(id,source) {
        var el = fcGetElement(id);
        el.src = source;
    }

    // show element by name
    // set display to block and we dont have to set size
    function fcShow(id, hideOffscreen, left, width, height) {
        var el = fcGetElement(id);
        //el.style.visibility = "visible";
        el.style.display = "block";
        if (hideOffscreen) {
            //el.style.width = parseInt(width) + "px";
            //el.style.height = parseInt(height) + "px";
        }
    }

    function fcFlexOnload(movieId) {
        // calling callback is unreliable - swf movie may not be loaded yet
        //movie.onLoadComplete();
        fcHTMLControls.pageLoaded = "true";
    }

    // end of line
