/**
 * @author Nicolas Desy
 * Copyright © 2005-2006 Les solutions Net-Logik. All rights reserved.
 */

Delegate = {
    create : function(o,f){
        return function(){ return f.apply(o,arguments); };
    }
};


/**
 * Classe qui g la communication avec le serveur
 *
 * METHODES
 * reset()
 * setAttribute(key, value)
 * setData(data)
 * addListener(listener)
 * sendAndLoad(url)
 */
XML = function(){				
    this._listener = [];	
    this.reset();
    this.asyn = true;
}

XML.SPECIAL_CHARS = [
    {code:8211, value:"-"},
    {code:8217, value:"'"},
    {code:339, value:"oe"},
    {code:37, value:"%25"},
    {code:38, value:"&amp;"},
    {code:43, value:"%2B"},
    {code:37, value:"%2F;"} 
];


/* idea :
 
function callback(response){
 
}
 
XML.sendAndLoad("loadText.do", {textId:12, lang:"fr"}, callback, "POST");
 */




XML.sendAndLoad = function(){
    
}

XML.prototype.setAsyn = function(value)
{
    this.asyn = value;
}

XML.prototype.reset = function(){
    this._params = null;
    this._method = "GET";
}

XML.prototype.setAttribute = function(/*String*/ key, /*String*/ value){		
    
    if(this._params == null){
        this._params = {};
    }
    
    
    

    
   // if(typeof value == "string"){   
        var chars = XML.SPECIAL_CHARS;
        var nbchars = chars.length;
        var size = value.length;
        for(var i=0; i<size; i++){
            for(var j=0; j<nbchars; j++){
                if(value.charCodeAt(i) == chars[j].code){   
               //     alert("char replaced : " + chars[j].code + " : " + chars[j].value);
                    value = value.substring(0, i) + chars[j].value + value.substring(i+1);  
                    size = value.length;
                    i += chars[j].value.length-1;
                    j = nbchars;
                }
            }
        }
  //  }
    
    value = escape(value);
   // value = encodeURIComponent(value);
    this._params[key] = value;	
}

XML.prototype.setData = function(/*String*/ data){		
    this._params = data;
    this._method = "POST";
}

XML.prototype.addListener = function(/*Function*/ listener){
    this._listener.push(listener);
}

XML.prototype.sendAndLoad = function(/*String*/ url) {
    var conn = null;
    
    try {
        conn = new XMLHttpRequest();		
    }
    catch (error) {        
        try {
            conn = new ActiveXObject("Microsoft.XMLHTTP");
        }
        catch (error) {
            try {
                conn = new ActiveXObject("Msxml2.XMLHTTP");
            }
            catch (error) {}
        }
    }
    
    var ls = this._listener;
    
    conn.onreadystatechange = function() {
        try{        
            if (conn.readyState == 4 && conn.status == 200){             
                var i = ls.length;				
                while(--i > -1) ls[i](conn);			
            }
        }catch (error) {}
    }
    
    var params = "";
    
    if(this._params != null) {                	
        for(var i in this._params) {           
            params += "&"+ i + "=" + this._params[i];
        }		
        
        if(this._method == "GET") {
            url += "?" + params.substring(1);
            this.reset();	
            params = null;
        }	
    }	
    
    conn.open(this._method, url,this.asyn);
    
    if(this._method == "POST") {
        conn.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
    }
    
    conn.send(params);
    
    if(this.asyn == false)
    {
        if (conn.readyState == 4 && conn.status == 200)
        {
            return conn.responseText;
        }
    }
}	


/**
 * Search 
 *
 * Usage : 
 *      XML.findChildren(divElement, "p", {class:"dark"});
 *      XML.findChildren(formElement, "input", null, {type:"text"});
 *      XML.findChildren(formElement, "input", null, {type:"text", class:"darkField"});
 */ 
XML.findChildren = function(target, name, value, attributes, recurse){
    
    if(!target || !target.childNodes || !name) return [];
    
    var checkAttributes = (attributes != undefined);
    var checkValue = (value != undefined);   
    var result = [];
    var ns = (recurse) ? target.getElementsByTagName(name) : target.childNodes;
    var length=ns.length;
   
    for(var i=0; i<length; i++){
        var node = ns[i];             
        
        if(node.nodeName.toLowerCase() == name) {
            if(checkAttributes){
                var isValid = true;
                
                for(var attributeName in attributes){
                    if(node.getAttribute(attributeName) != attributes[attributeName]){
                        isValid = false;
                        break;
                    }
                }
                
                if(isValid){
                    if(checkValue){
                        if(node.firstChild.nodeValue == value){
                            result.push(node);
                        }
                    }else{
                        result.push(node);
                    }
                }
            }else{
                if(checkValue){                   
                    if(node.firstChild.nodeValue == value){
                        result.push(node);
                    }
                }else{                  
                    result.push(node);
                }
            }
        }
    }
    return result;
}


XML.insertAfter = function(target, newNode){   
    if(target.nextSibling){
        target.parentNode.insertBefore(newNode, target.nextSibling);
    }else{
        target.parentNode.appendChild(newNode);
    }
}

XML.prependChild = function(target, newNode){
    if(target.firstChild){
        target.insertBefore(newNode, target.firstChild);
    }else{
        target.appendChild(newNode);
    }
}

XML.createElement = function(name, text){
    var el = document.createElement(name);
    el.innerHTML = text;  
    return el;
}

XML.nextElement = function(target){
    var result = target.nextSibling;    
    while(result && result.nodeType != 1){
        if(!result.nextSibling) {
            return null;
        }
        result = result.nextSibling
    }
    return result;
}

XML.previousElement = function(target){
    var result = target.previousSibling;       
    while(result && result.nodeType != 1){      
        if(!result.previousSibling) {
            return null;
        }
        result = result.previousSibling
    }
    return result;
}


XML.toString = function(doc){
    var xsx = new XMLSerializer();   
    return xsx.serializeToString(doc);
}
var __LIST=function(els,root){this.els=els;};var getItems=function(el,name,recurse,ref){
var rs=(ref)?ref:[];var ns=(recurse)?el.getElementsByTagName(name):el.childNodes;var i=-1;var l=ns.length;
while(++i<l){var n=ns[i];if(n.nodeName==name)rs.push(n);}return new __LIST(rs);
};var LO=__LIST.prototype;LO.items=function(){return this.els;};
LO.getItems=function(name,recurse){var rs=[];var els=this.els;var i=-1;var l=els.length;while(++i<l)
{getItems(els[i],name,recurse,rs);}return new __LIST(rs, this);};

function updateUserForm(action, id, input) {
    doc = new XML(); 
    doc.addListener(updatedUserForm);
    doc._method = "POST";
    doc.setAttribute("profId", id);
    doc.setAttribute(input.name, escape(input.value));
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.sendAndLoad(action);
}

function updatedUserForm(response) {
    //alert(response.responseText);
}

function getSubCategory(catSelect, form) {
        doc = new XML();
        doc.addListener(onCategoryLoaded);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.setAttribute("catid", catSelect.options[catSelect.selectedIndex].value);
        if (catSelect.options[catSelect.selectedIndex].value == -1) {
            if (form == 'listing') {
                hideLSub();
            } else {
                hideSubCats();
            }
        } else {
            if (form == 'listing') {
                showLSub();
            } else {
            showSubCats();
            }
        }
        doc.sendAndLoad("actions-ajaxCategoryAction.do");
}
        
        
function onCategoryLoaded(response) {
	var doc = response.responseXML.documentElement;
	var liste = document.getElementById("subSelect");
        
        removeAllOptions(liste);
        
	var cats = getItems(doc, "sub").items();
	var catsL = cats.length;
	for(var i1=0; i1<catsL; i1++){
		var cat = cats[i1];
		addOption(liste, cat.getAttribute("name"), cat.getAttribute("id"), false);
	}
}


function hideSubCats() {
    var delSubComp1 = document.getElementById("delSubComp1");
    var delSubComp2 = document.getElementById("delSubComp2");
    var delSubComp3 = document.getElementById("delSubComp3");
    delSubComp1.style.display = "none";
    delSubComp2.style.display = "none";
    delSubComp3.style.display = "none";    
}


function showSubCats() {
    var delSubComp1 = document.getElementById("delSubComp1");
    var delSubComp2 = document.getElementById("delSubComp2");
    var delSubComp3 = document.getElementById("delSubComp3");
    delSubComp1.style.display = "block";
    delSubComp2.style.display = "block";
    delSubComp3.style.display = "block";    
}

function hideLSub() {
    var subCatRow = document.getElementById("subCatRow");
    subCatRow.style.display = "none";
}

function showLSub() {
    var subCatRow = document.getElementById("subCatRow");
    subCatRow.style.display = "block";
}

function saleCheck(saleChkBox) {
    var saleRow = document.getElementById("saleRow");
    if (saleChkBox.checked) {
        saleRow.style.display = "block";
    } else {
        saleRow.style.display = "none";
    }
}

function rentCheck(rentChkBox) {
    var rentRow = document.getElementById("rentRow");
    if (rentChkBox.checked) {
        rentRow.style.display = "block";
    } else {
        rentRow.style.display = "none";
    }
}

function getSubCategoryListing(catSelect) {
        doc = new XML();
        doc.addListener(onCategoryLoadedListing);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.setAttribute("catid", catSelect.options[catSelect.selectedIndex].value);
        if (catSelect.options[catSelect.selectedIndex].value == -1) {
            hideLists();
            hideListsSel();
        } else {
            showLists();
            hideListsSel();
        }
        doc.sendAndLoad("actions-ajaxCategoryAction.do");
}
        
        
function onCategoryLoadedListing(response) {
	var doc = response.responseXML.documentElement;
	var liste = document.getElementById("subListSelect");
        
        removeAllOptions(liste);
        
	var cats = getItems(doc, "sub").items();
	var catsL = cats.length;
        addOption(liste, "--CHOISIR--", -1, false);
	for(var i1=0; i1<catsL; i1++){
		var cat = cats[i1];
		addOption(liste, cat.getAttribute("name"), cat.getAttribute("id"), false);
	}
}

function showLists() {
    var delListComp1 = document.getElementById("delListComp1");
    var delListComp2 = document.getElementById("delListComp2");
    delListComp1.style.display = "block";
    delListComp2.style.display = "block";
}

function hideLists() {
    var delListComp1 = document.getElementById("delListComp1");
    var delListComp2 = document.getElementById("delListComp2");
    delListComp1.style.display = "none";
    delListComp2.style.display = "none";
}

function getListing(select) {
        doc = new XML();
        doc.addListener(onListingLoaded);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.setAttribute("subid", select.options[select.selectedIndex].value);
        var catSel = document.getElementById("catListSelect");
        doc.setAttribute("catid", catSel.options[select.selectedIndex].value);
        if (select.options[select.selectedIndex].value == -1) {
            hideListsSel();
        } else {
            showListsSel();
        }
        doc.sendAndLoad("actions-ajaxListingAction.do");
}
        
        
function onListingLoaded(response) {
	var doc = response.responseXML.documentElement;
	var liste = document.getElementById("listingSelect");
        
        removeAllOptions(liste);
        
	var cats = getItems(doc, "list").items();
	var catsL = cats.length;
        addOption(liste, "--CHOISIR--", -1, false);
	for(var i1=0; i1<catsL; i1++){
		var cat = cats[i1];
		addOption(liste, cat.getAttribute("name"), cat.getAttribute("id"), false);
	}
}

function hideListsSel() {
    var delListComp3 = document.getElementById("delListComp3");
    var delListComp4 = document.getElementById("delListComp4");
    var delListComp5 = document.getElementById("delListComp5");
    delListComp3.style.display = "none";    
    delListComp4.style.display = "none";    
    delListComp5.style.display = "none";    
}

function showListsSel() {
    var delListComp3 = document.getElementById("delListComp3");
    var delListComp4 = document.getElementById("delListComp4");
    var delListComp5 = document.getElementById("delListComp5");
    delListComp3.style.display = "block";    
    delListComp4.style.display = "block";    
    delListComp5.style.display = "block";    
}

function saleCheckAcnt(saleChkBox) {
    var saleRow = document.getElementById("saleRowAcnt");
    if (saleChkBox.checked) {
        saleRow.style.display = "block";
    } else {
        saleRow.style.display = "none";
    }
}

function rentCheckAcnt(rentChkBox) {
    var rentRow = document.getElementById("rentRowAcnt");
    if (rentChkBox.checked) {
        rentRow.style.display = "block";
    } else {
        rentRow.style.display = "none";
    }
}


function getSubCategoryMyAccount(catSelect) {
        doc = new XML();
        doc.addListener(onCategoryLoadedMyAccount);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.setAttribute("catid", catSelect.options[catSelect.selectedIndex].value);
        doc.sendAndLoad("actions-ajaxCategoryAction.do");
}
        
        
function onCategoryLoadedMyAccount(response) {
	var doc = response.responseXML.documentElement;
	var liste = document.getElementById("acntSelect");
        
        removeAllOptions(liste);
        
	var cats = getItems(doc, "sub").items();
	var catsL = cats.length;
	for(var i1=0; i1<catsL; i1++){
		var cat = cats[i1];
		addOption(liste, cat.getAttribute("name"), cat.getAttribute("id"), false);
	}
}

function getArticles(editionSel) {
        doc = new XML();
        doc.addListener(onEditionLoaded);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.setAttribute("editionid", editionSel.options[editionSel.selectedIndex].value);
        doc.setAttribute("lang", "FR");
        if (editionSel.options[editionSel.selectedIndex].value == -1) {
            hideArticleSel();
        } else {
            showArticleSel();
        }
        doc.sendAndLoad("actions-ajaxListPressArticle.do");
}
        
        
function onEditionLoaded(response) {
	var doc = response.responseXML.documentElement;
	var liste = document.getElementById("articleSel");
        removeAllOptions(liste);
        
	var cats = getItems(doc, "Article").items();
        addOption(liste, "-- Chosir un Article --", -1, false);
        
	var catsL = cats.length;
	for(var i1=0; i1<catsL; i1++){
		var cat = cats[i1];
		addOption(liste, cat.getAttribute("Name"), cat.getAttribute("Id"), false);
	}
}

function hideArticleSel() {
    var articleRow = document.getElementById("articleRow");
    var articleBtn = document.getElementById("articleBtn");
    articleRow.style.display = "none";    
    articleBtn.style.display = "none";    
}

function showArticleSel() {
    var articleRow = document.getElementById("articleRow");
    var articleBtn = document.getElementById("articleBtn");
    articleRow.style.display = "block";    
    articleBtn.style.display = "block";    
}

function getEditions(editionGroupSel, enabled) {
        doc = new XML();
        if (enabled == 'enabled') {
            doc.addListener(onEditionGroupLoaded2);
        } else if (enabled == 'disabled') {
            doc.addListener(onEditionGroupLoaded3);
        } else {
            doc.addListener(onEditionGroupLoaded);
        }
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.setAttribute("editiongroupid", editionGroupSel.options[editionGroupSel.selectedIndex].value);
        if (enabled == 'enabled') {
            doc.setAttribute("enabled", enabled);
        }
        doc.setAttribute("lang", "FR");
        if (editionGroupSel.options[editionGroupSel.selectedIndex].value == -1) {
            if (enabled == 'enabled') {
                hideEditionSel2();
            } else if (enabled == 'disabled') {
                hideEditionSel3();
            } else {
                hideEditionSel();
            }
        } else {
            if (enabled == 'enabled') {
                showEditionSel2();
            } else if (enabled == 'disabled') {
                showEditionSel3();
            } else {
                showEditionSel();
            }
        }
        doc.sendAndLoad("actions-ajaxListPressEdition.do");
}
        
        
function onEditionGroupLoaded(response) {
	var doc = response.responseXML.documentElement;
	var liste = document.getElementById("editionSel");
        removeAllOptions(liste);
        
	var cats = getItems(doc, "Edition").items();
        addOption(liste, "-- Chosir une &eacute;dition --", -1, false);
        
	var catsL = cats.length;
	for(var i1=0; i1<catsL; i1++){
		var cat = cats[i1];
		addOption(liste, cat.getAttribute("Name"), cat.getAttribute("Id"), false);
	}
}

function onEditionGroupLoaded2(response) {
	var doc = response.responseXML.documentElement;
	var liste = document.getElementById("editionSel2");
        removeAllOptions(liste);
        
	var cats = getItems(doc, "Edition").items();
        addOption(liste, "-- Chosir une &eacute;dition Inactive --", -1, false);
        
	var catsL = cats.length;
	for(var i1=0; i1<catsL; i1++){
		var cat = cats[i1];
		addOption(liste, cat.getAttribute("Name"), cat.getAttribute("Id"), false);
	}
}

function onEditionGroupLoaded3(response) {
	var doc = response.responseXML.documentElement;
	var liste = document.getElementById("editionSel3");
        removeAllOptions(liste);
        
	var cats = getItems(doc, "Edition").items();
        addOption(liste, "-- Chosir une &eacute;dition Active --", -1, false);
        
	var catsL = cats.length;
	for(var i1=0; i1<catsL; i1++){
		var cat = cats[i1];
		addOption(liste, cat.getAttribute("Name"), cat.getAttribute("Id"), false);
	}
}

function hideEditionSel() {
    var editionRow = document.getElementById("editionRow");
    var editionBtn = document.getElementById("editionBtn");
    editionRow.style.display = "none";    
    editionBtn.style.display = "none";    
}

function showEditionSel() {
    var editionRow = document.getElementById("editionRow");
    var editionBtn = document.getElementById("editionBtn");
    editionRow.style.display = "block";    
    editionBtn.style.display = "block";    
}

function hideEditionSel2() {
    var editionRow = document.getElementById("editionRow2");
    var editionBtn = document.getElementById("editionBtn2");
    editionRow.style.display = "none";    
    editionBtn.style.display = "none";    
}

function showEditionSel2() {
    var editionRow = document.getElementById("editionRow2");
    var editionBtn = document.getElementById("editionBtn2");
    editionRow.style.display = "block";    
    editionBtn.style.display = "block";    
}

function hideEditionSel3() {
    var editionRow = document.getElementById("editionRow3");
    var editionBtn = document.getElementById("editionBtn3");
    editionRow.style.display = "none";    
    editionBtn.style.display = "none";    
}

function showEditionSel3() {
    var editionRow = document.getElementById("editionRow3");
    var editionBtn = document.getElementById("editionBtn3");
    editionRow.style.display = "block";    
    editionBtn.style.display = "block";    
}

function hideArticleImage() {
    var row1 = document.getElementById("row1");
    var row2 = document.getElementById("row2");
    var row3 = document.getElementById("row3");
    var row4 = document.getElementById("row4");
    row1.style.display = "none";
    row2.style.display = "none";
    row3.style.display = "none";
    row4.style.display = "block";
}

function showArticleImage() {
    var row1 = document.getElementById("row1");
    var row2 = document.getElementById("row2");
    var row3 = document.getElementById("row3");
    var row4 = document.getElementById("row4");
    row1.style.display = "block";
    row2.style.display = "block";
    row3.style.display = "block";
    row4.style.display = "none";
}

function showPreview() {
        doc = new XML();
        doc.addListener(onPreviewLoaded);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        var rawtext = document.getElementById('pressTextField');
        doc.setAttribute("rawformat", rawtext.value);
        doc.sendAndLoad("actions-ajaxPreviewArticle.do");
}
        
        
function onPreviewLoaded(response) {
	var previewdiv = document.getElementById("preview");
        previewdiv.innerHTML = response.responseText;
        previewdiv.style.display = "block";
        var previewlbl = document.getElementById('previewlabel');
        previewlbl.style.display = "block";
}

function killPreview() {
    var previewdiv = document.getElementById("preview");
    var previewlbl = document.getElementById('previewlabel');
    previewdiv.style.display = "none";
    previewlbl.style.display = "none";
}   

function modifyPosition(id) {
        doc = new XML();
        doc.addListener(onModifyLoaded);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        var sel = document.getElementById('pressModifyPosition');
        doc.setAttribute("position", sel.options[sel.selectedIndex].value);
        doc.setAttribute("textid", id);
        doc.sendAndLoad("actions-ajaxModifyImage.do");
}
        
        
function onModifyLoaded(response) {
	var targetdiv = document.getElementById("currentPos");
        targetdiv.innerHTML = "Position courrante: " + response.responseText;
}

function deleteArticleImage(id) {
    if (confirm("Voulez-vous vraiment supprimer cette image?")) {
        doc = new XML();
        doc.addListener(onDeleteLoaded);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.setAttribute("textid", id);
        doc.sendAndLoad("actions-ajaxDeleteImage.do");
    }
}
        
        
function onDeleteLoaded(response) {
	var targetdiv = document.getElementById("currentImage");
        targetdiv.style.display = "none";
}

function showArticleImageInsitu() {
	var targetdiv = document.getElementById("currentImage");
        targetdiv.style.display = "block";
}    


function getEventsList(select) {
        doc = new XML();
        doc.addListener(onEventsLoaded);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.setAttribute("categoryId", select.options[select.selectedIndex].value);
        doc.sendAndLoad("actions-ajaxListEvents.do");
}
        
        
function onEventsLoaded(response) {
	var doc = response.responseXML.documentElement;
	var liste = document.getElementById("eventTarget");
        
        removeAllOptions(liste);
        
	var cats = getItems(doc, "Event").items();
	var catsL = cats.length;
	for(var i1=0; i1<catsL; i1++){
		var cat = cats[i1];
		addOption(liste, cat.getAttribute("name"), cat.getAttribute("id"), false);
	}
}

function updateAdminLabel(key, valueId) {
    var tempvalue = document.getElementById(valueId);
    value = tempvalue.value;
    tempvalue.style.backgroundColor = '#FFFFFF';
    doc = new XML();
    doc.addListener(onAdminLabelUpdated);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.setAttribute("id", key);
    doc.setAttribute("text", value);
    doc.sendAndLoad("actions-updateLabelInsitu.do");
} 

function onAdminLabelUpdated(response) {
    alert("La label a été mise à jour. N'oubliez pas de tester vos changements!");
}

function resetAdminLabel(formId, textId) {
    document.getElementById(textId).style.backgroundColor = '#FFFFFF';
    document.getElementById(formId).reset();

}


function hideOnlineUsersDiv() {
    document.getElementById('onlineUsersDiv').style.display = "none";
}

function hideNewUsersDiv() {
    document.getElementById('newUsersDiv').style.display = "none";
}

function hideVisitorsDiv() {
    document.getElementById('visitorsDiv').style.display = "none";
}


function showOnlineUsersDiv() {
    document.getElementById('onlineUsersDiv').style.display = "block";
}

function showNewUsersDiv() {
    document.getElementById('newUsersDiv').style.display = "block";
}

function showVisitorsDiv() {
    document.getElementById('visitorsDiv').style.display = "block";
}


function bannerNcho(sel) {
    doc = new XML();
    doc.addListener(onBannerNchoWrapAround);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.setAttribute("bannerId", sel.options[sel.selectedIndex].value);
    doc.sendAndLoad("actions-ajaxBannerInfo.do");
}
        
        
function onBannerNchoWrapAround(response) {
    var gaetanne = response.responseXML.documentElement;
    document.getElementById('bannerTitleMod').value = gaetanne.getAttribute("title");
    document.getElementById('bannerHrefMod').value = gaetanne.getAttribute("href");
    var tar = gaetanne.getAttribute("target");
    var tarSel = document.getElementById('bannerTargetMod');
    removeAllOptions(tarSel);
    if (tar == '_blank') {
        addOption(tarSel, 'blank', '_blank', true);
        addOption(tarSel, 'self', '_self', false);
    } else {
        addOption(tarSel, 'blank', '_blank', false);
        addOption(tarSel, 'self', '_self', true);
    }
}


function CMSRichMediaBannerLoad(bannerName) {
    doc = new XML();
    doc.addListener(onCMSRichMediaBannerLoad);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.setAttribute("bannerName", bannerName);
    document.cmsEditBannerFormName.locationName.value = bannerName;
    doc.sendAndLoad("actions-ajaxCMSRichMediaBanner.do");
}
        
        
function onCMSRichMediaBannerLoad(response) {
    var res = response.responseXML.documentElement;
    var banners = getItems(res, "banner").items();
    var bannersL = banners.length;
    
    
    var content = '<table style="border: 1px solid black" cellpadding="0" cellspacing="0" width="100%">';
    content += "<tr class='cmsFormTr'><td width='20' bgcolor='#818996'>Media</td><td width='30' bgcolor='#818996'>Alias</td><td width='10' bgcolor='#818996' align='center'>Actions</td></tr>";
    for(var i1=0; i1<bannersL; i1++){
      var banner = banners[i1];
      content += 
          "<tr><td>"+banner.getAttribute("type")+"</td><td><a href='" + banner.getAttribute("url") +"'>"+ banner.getAttribute("alias") +"</a></td><td align='center'><a href=\"javascript:CMSRichMediaBannerDelete('"+ banner.getAttribute("id") +"')\"><img src='../shared/images/cms/btn-supprimer.jpg' /></a></td></tr>"

    }    
    content += "</table>";
    
    document.getElementById('DivonCMSRichMediaBannerLoad').innerHTML = content;
}

function CMSRichMediaBannerDelete(bannerId) {
    doc = new XML();
    doc.addListener(onCMSRichMediaBannerDelete);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.setAttribute("bannerId", bannerId);
    doc.sendAndLoad("actions-ajaxCMSRichMediaBannerDelete.do");
}
        
        
function onCMSRichMediaBannerDelete(response) {
    // HERE I SHOULD REFRESH DISPLAY
  /*  var res = response.responseXML.documentElement;
    var banners = getItems(res, "banner").items();
    var bannersL = banners.length;
    document.getElementById('DivonCMSRichMediaBannerLoad').innerHTML = "<tr class='cmsFormTr'>	<td width='20'>Media</td><td width='30'>Url</td><td width='10'>Actions</td></tr>";
    
    for(var i1=0; i1<bannersL; i1++){
      var banner = banners[i1];
      document.getElementById('DivonCMSRichMediaBannerLoad').innerHTML = 
          document.getElementById('DivonCMSRichMediaBannerLoad').innerHTML + 
          "<tr><td>"+banner.getAttribute("type")+"</td><td>"+ banner.getAttribute("url") +"</td><td>Edit / Delete / Suspend</td></tr>"

    }*/
}





/**
 Contient les regles de validation suivantes :
 
 REQUIRED
 INTEGER
 FLOAT
 NOT_EQUALS
 STRING_LENGTH
 NUMERIC_LENGTH
 VALID_EMAIL
 LINK
 DATE_AFTER
 **/


Delegate = {
    create : function(o, f){
        return function(){ 
            f.apply(o, arguments); 
        };
    }
};


/**
 *
 */
function getSelected(name, defaultValue){
    var types = document.forms[0][name];      
    for(var i=0; i<types.length; i++){
        if(types[i].checked) {
            return types[i].value;
        }
    }       
    return defaultValue;
}


/**
 *@param field L'ID du champ du formulaire
 *@param error L'ID de l'élément pour afficher les messages d'erreur
 *@param validations Un Array contenant les validations pour ce champ
 *@param name Le nom du champ a envoyer au serveur
 *@param type Le type de champ (Field.STRING ou Field.NUMERIC)
 */
Field = function(field, error, validations, name, type) {
    
    this._field = field;
    this._error = error;
    this._validations = validations;
    this._isAutoSaved = !isNaN(type);
    this._name = name;
    this._type = type;

    
    if(document.getElementById(this._field) != null) {
        this._fieldEl = document.getElementById(this._field);
        this._fieldEl.onchange = Delegate.create(this, this.isValid);
    }
    else
        this._fieldEl = this._field;
    
 
    this._fieldValue = "";
    if(typeof this._fieldEl != 'string' && this._fieldEl.value)
        this._fieldValue = this._fieldEl.value;
    

    this._errorEl = document.getElementById(this._error);

    
    
    for(var i in validations){       
        validations[i].__field = this._fieldEl;       
        if(validations[i].init){
            validations[i].init(this._fieldEl);
        }
    }
}

Field.BACKGROUND_COLOR = "#FFF";
Field.ERROR_COLOR = "#FFFFCC";


/**
 *
 */
Field.getValidations = function(str){
    
    var validations = [];
    var params = str.split(",");    
    
    for(var i=0; i<params.length; i++){
        var temp = params[i];
        if("required" == temp){
            validations.push(Validation.REQUIRED);
        }
        else if("int" == temp){
            validations.push(Validation.INTEGER);
        }
        else if("float" == temp){
            validations.push(Validation.FLOAT);
        }
        else if("image" == temp){
            validations.push(Validation.IMAGE());
        }
        else if("email" == temp) {
            validations.push(Validation.EMAIL());
        }
        else if("link" == temp) {
            validations.push(Validation.LINK());
        }
        else if("emailexists" == temp) {
            validations.push(Validation.EMAILEXISTS());
        }        
        else if(temp.indexOf("date_after") > -1) {
            validations.push(Validation.DATE_AFTER(temp.split("|")[1]));
        }
        else if(temp.indexOf("password_compare") > -1) {
            validations.push(Validation.PASSWORD_COMPARE(temp.split("|")[1]));
        }
        else if(temp.indexOf("noteq") > -1){
            validations.push(Validation.NOT_EQUALS(temp.split("|")[1]));
        }
        else if("tinymce" == temp) {
            validations.push(Validation.TINYMCE);
        }
        else if(temp.indexOf("strlen") > -1){
            var t = temp.split("|");
            validations.push(Validation.STRING_LENGTH(parseInt(t[1]), parseInt(t[2])));
        }
        else if(temp.indexOf("range") > -1){
            var t = temp.split("|");
            validations.push(Validation.NUMERIC_LENGTH(parseInt(t[1]), parseInt(t[2])));
        }
        else if(temp.indexOf("update") > -1){
            var t = temp.split("|");
            validations.push(Validation.UPDATE(t[1], t[2]));
        }
        else if(temp.indexOf("formula") > -1){
            var t = temp.split("|");
            validations.push(Validation.FORMULA(t[1], t[2]));
        }
    }
    
    return validations;
}

/**
 *
 */
Field.getDigitOnly = function(field) {
    var value = field.value; 
    var length = value.length;
    var result = "";
    for(var i=0; i<length; i++) {
        var ch = value.charAt(i);        
        if(!isNaN(ch) && (ch != " " || ch == ".")) {
            result += value.charAt(i);
        }
    }
    
    return parseFloat(result); 
}



/**
 *
 */
Field.prototype.isValid = function() {      
    
    for(var i=0; i<this._validations.length; i++) {     
        if(!this._validations[i].isValid(this._fieldEl,this._fieldValue)) {
            this._errorEl.style.display = "block";
            this._errorEl.innerHTML = this._validations[i].getMessage();

            if(typeof this._fieldEl != 'string')
                this._fieldEl.style.backgroundColor = Field.ERROR_COLOR;
            return false;            
        }else {
            if(this._validations[i].isCancellable()){
                return true;
            }
        }
    }
    
    this._errorEl.innerHTML = "&nbsp;";
    if(typeof this._fieldEl != 'string')
        this._fieldEl.style.backgroundColor = Field.BACKGROUND_COLOR;
    this._errorEl.style.display = "none";           
    this._fieldValue = this._fieldEl.value;
    
    return true;
}

Field.STRING = 1;
Field.NUMERIC = 2;


Validation = {};

/**
 *
 */
Validation.REQUIRED = {
    isValid : function(field, oldValue){
        if(field.value == null || field.value == "") {
             return false;
        }
        
        return true;
    },
    getMessage : function(){ 
        return "Ce champ est requis"; 
    },
    isCancellable : function(){ 
        return false; 
    },
    toString : function(){ 
        return "REQUIRED";
    }
};



Validation.IMAGE = function() {
    return {
        isValid : function(field, oldValue){        
            return field.value.toLowerCase().match(/^.*(jpg|jpeg|gif)$/);            
        },
        getMessage : function(){ 
            return "Le fichier doit &ecirc;tre de type JPG, JPEG ou GIF."; 
        },
        isCancellable : function(){ 
            return false; 
        },
        toString : function(){ 
            return "UPDATE" 
        },
        init : function(field){  
            
        }
    };
}


Validation.UPDATE = function(name, fieldName) {
    return {
        isValid : function(field, oldValue){ 
            FormUpdate.notifyContext(name, fieldName, field.value);
            return true; 
        },
        getMessage : function(){ 
            return ""; 
        },
        isCancellable : function(){ 
            return false; 
        },
        toString : function(){ 
            return "UPDATE" 
        },
        init : function(field){          
            FormUpdate.notifyContext(name, fieldName, field.value);
            
            field.onkeyup = function(){
                FormUpdate.notifyContext(name, fieldName, field.value);
            }
        }
    };
}

Validation.FORMULA = function(name, formula) {
    
    var val = {
        isValid : function(field, oldValue){ 
            return true; 
        },
        getMessage : function(){ 
            return ""; 
        },
        isCancellable : function(){ 
            return false; 
        },
        toString : function(){ 
            return "FORMULA"; 
        },
        update : function(evt){        
            var temp = FormUpdate.compute(evt.context, formula);
            if(temp == null || isNaN(temp)){
                val.__field.value = "";
            }else{
                val.__field.value = temp;
            }
        }
    };
    
    FormUpdate.getContext(name).events.addEventListener("update", val.update);
    
    return val;
}


/**
 *
 */
Validation.NO_WHITESPACE = {
    
    isValid : function(field, oldValue){
        var str = field.value;
        if(!str) { 
            return false;
        }else{
            str = str.replace(/^\s*|\s*$/g, "");            
            if(str.length > 0){
                field.value = str;
                return true;
            }
            return false;
        }
    },
    getMessage : function() {
        return "Ce champ ne peut &ecirc;tre que des espaces blancs.";
    },
    isCancellable : function() {
        return false; 
    },
    toString : function() { 
        return "NO_WHITESPACE"; 
    }
    
}

/**
 *
 */
Validation.INTEGER = {
    isValid : function(field, oldValue){     
        var value = field.value;
        var length = value.length;
        for(var i=0; i<length; i++) {
            if(isNaN(value.charAt(i))) {                
                field.value = oldValue;
                return false;
            }
        }
        return true; 
    },
    getMessage : function(){ 
        return "Ce champ doit &ecirc;tre un nombre entier.";
    },
    isCancellable : function(){ 
        return false; 
    },
    toString : function(){ 
        return "INTEGER" 
    }
}


/**
 *
 */
Validation.INTEGER_OR_ZERO = {
    
    isValid : function(field, oldValue){     
        var value = field.value;
        var length = value.length;
        for(var i=0; i<length; i++) {
            if(isNaN(value.charAt(i))) {                
                field.value = oldValue;
                field.value = 0;
            }
        }
        return true; 
    },
    isCancellable : function(){ 
        return false; 
    },
    toString : function(){ 
        return "INTEGER" 
    }
    
}

/**
 *
 */
Validation.FLOAT = {
    isValid : function(field, oldValue) { 
        var valid = true;
        var dotUsed = false;
        var value = field.value;
        var length = value.length;
        
        for(var i=0; i<length; i++) {
            var ch = value.charAt(i);
            if(ch == ".") {
                if(dotUsed) {
                    field.value = oldValue;
                    return false;
                }else{
                    dotUsed = true;
                }
            }
            else if(isNaN(ch)) {
                field.value = oldValue;
                return false;
            }
        }
        return true; 
    },
    getMessage : function(){ 
        return "Ce champ doit &ecirc;tre un nombre r&eacute;el."; 
    },
    isCancellable : function(){ 
        return false; 
    },
    toString : function(){ 
        return "FLOAT" 
    }
}


/**
 *
 */
Validation.NOT_EQUALS = function(value) {
    return {
        isValid : function(field, oldValue){ 
            return field.value != value; 
        },
        getMessage : function(){ 
            return "Ce champ est requis"; 
        },
        isCancellable : function(){ 
            return false; 
        },
        toString : function(){ 
            return "NOT_EQUALS('"+value+"')" 
        }
    };
}

/**
 *
 */
Validation.STRING_LENGTH = function(min, max) {
    return {
        
        isValid : function(field, oldValue) {
            try{
                if(!isNaN(min) && field.value.length < min) {
                    this._errorType = "min";
                    return false;
                }
                if(!isNaN(max) && field.value.length > max) {
                    this._errorType = "max";
                    return false;
                }
            }catch(e){
                alert("error : " + e + " in " + this.toString());
            }
            return true;
        },
        
        isCancellable : function(){ return false; },
        
        getMessage : function() {
            if(this._errorType == "min"){
                return "Ce champ doit avoir un minimum de " + min + 
                " charact&egrave;res."; 
            }
            if(this._errorType == "max"){
                return "Ce champ doit avoir un maximum de " + max + 
                " charact&egrave;res."; 
            }
            return "&nbsp;";
        },
        
        toString : function(){ return "STRING_LENGTH("+min+","+max+")" }
    };
}

/**
 *
 */
Validation.NUMERIC_LENGTH = function(min, max) {
    return {
        
        isValid : function(field, oldValue) {
            //var value = parseInt(Field.getDigitOnly(field));
            var value = parseFloat(field.value);
            

            if(isNaN(min) == false) {
                if(value < min) {
                    this._errorType = "min";
                    return false;
                }
            }
            
    
            if(isNaN(max) == false) {
                if(value > max) {
                    this._errorType = "max";
                    return false;
                }
            }
         
            return true;
        },
        
        getMessage : function() {
            if(this._errorType == "min"){
                return "La valeur de ce champ doit &ecirc;tre sup&eacute;rieur &agrave; " + min + "."; 
            }
            if(this._errorType == "max"){
                return "La valeur de ce champ doit &ecirc;tre inf&eacute;rieur &agrave; " + max + "."; 
            }
            return "&nbsp;";
        },
        
        isCancellable : function(){ 
            return false; 
        },
        
        toString : function(){ 
            return "NUMERIC_LENGTH("+min+","+max+")";
        }
    };
}

/**
 * Validation pour la saisie double de mot de passe (inscription ou changement
 * de mot de passe)
 * 
 * @param (String) Id du champs du 2e champs de mot de passe
 */
Validation.PASSWORD_COMPARE = function(fieldCompare) {
    var enoughChar = true;
    var passSame = true;
    return {
        isValid : function(field,oldValue) {
            var input1 = field;
            var input2 = document.getElementById(fieldCompare);
            
            //Dans le cas où l'usager n'a pas saisie un des deux champs 
            //la différence n'est pas tenue en compte
            
            enoughChar = (input1.value.length > 3);
            
            passSame = (input1.value == "" || input2.value == "" || 
            input1.value == input2.value);
            
            return enoughChar && passSame;
        },
        
        getMessage : function() {
            fieldCompare.value = fieldCompare.value;
            if (!enoughChar) {
                return "Le mot de passe doit &ecirc;tre au moins 4 charact&egrave;res.";
            } else {
                return "Les deux mots de passe diff&egrave;rent.";
            }
        },
        
        isCancellable : function() { 
            return false; 
        },
        
        toString : function() {
            return "PASSWORD_COMPARE()";
        }
    };
}

/**
 * Validation basique de courriel
 */
Validation.EMAIL = function() {
    return {
        isValid : function(field,oldValue) {
            var emailParts = field.value.split("@");
            
            if(emailParts.length < 2) //Ne contient pas de @
                return false;
            
            if(!(emailParts[1].indexOf(".") != -1)) //N'a pas de domaine
                return false;
            
            return true;
        },
        
        getMessage : function() {
            return "Le courriel n'est pas valide.";
        },
        
        isCancellable : function() { 
            return false; 
        },
        
        toString : function() {
            return "EMAIL()";
        }
    };
}


/**
 * Validation d'un lien
 */
Validation.LINK = function() {
    return {
        isValid : function(field,oldValue) {
            //console.info(field.value.indexOf("http://"));
            return (field.value.indexOf("http://") == 0 || field.value == "");
        },
        
        getMessage : function() {
            return "Votre lien doit d&eacute;buter par \"http://\".";
        },
        
        isCancellable : function() { 
            return false; 
        },
        
        toString : function() {
            return "LINK()";
        }
    };
}

/**
 * Validation du contenu de tinymce
 */
Validation.TINYMCE = {
    isValid : function(field,oldValue) {
        var value;
        if(typeof field == 'object')
            value = tinyMCE.getContent(field.id);
        else
            value = tinyMCE.getContent(field)
            
        if(value == null || value.length == 0)
            return false;
        
        return true;
    },
        
    getMessage : function() {
        return "Ce champ est requis";
    },
        
    isCancellable : function() { 
        return false; 
    },
        
    toString : function() {
        return "TINYMCE";
    }
};


/**
 * Vérification qu'une date vienne après une autre
 */
Validation.DATE_AFTER = function(secondDate) {
    return {
        isValid : function(field,oldValue) {
            var valueAfter = field.value;
            var valueBefore = document.getElementById(secondDate).value;
            //console.info("valueAfter: "+valueAfter);
            //console.info("valueDefore: "+valueBefore);
            
            res = dateCompare(valueAfter,valueBefore);
            //console.info("res: "+res);
            return (res > 0);
            /*
            var partsAfter = valueAfter.split("/");
            var partsBefore = valueBefore.split("/");
             
            alert(partsAfter);
            if(!(partsAfter.length < 5 || partsBefore.length < 5))
            {
                alert(1);
             
                var dateAfter = new Date();
                dateAfter = Date.UTC(partsAfter[0],partsAfter[1],partsAfter[2],partsAfter[3],partsAfter[4],0,0);
             
                var dateBefore = new Date();
                dateBefore = Date.UTC(partsBefore[0],partsBefore[1],partsBefore[2],partsBefore[3],partsBefore[4],0,0);
             
                console.info("Date: "+dateAfter.toLocaleString());
                console.info("Date: "+dateBefore.toLocaleString());
            }*/
            //return true;  
        },
        
        getMessage : function() {
            return "La date doit &ecirc;tre plus r&eacute;cente que la date pr&eacute;c&eacute;dente.";
        },
        
        isCancellable : function() { 
            return false; 
        },
        
        toString : function() {
            return "DATE_AFTER()";
        }
    };
}



/**
 * Méthodes de comparaison de date (String)
 */
function dateCompare(dateString1,dateString2) {
    var partsAfter = dateString1.split("/");
    var partsBefore = dateString2.split("/");
    
    //alert(partsAfter);
    if(!(partsAfter.length < 5 || partsBefore.length < 5)) {
        //alert(1);
        
        var dateAfter = new Date();
        dateAfter = Date.UTC(partsAfter[0],partsAfter[1],partsAfter[2],partsAfter[3],partsAfter[4],0,0);
        
        var dateBefore = new Date();
        dateBefore = Date.UTC(partsBefore[0],partsBefore[1],partsBefore[2],partsBefore[3],partsBefore[4],0,0);
        
        //console.info("Date: "+dateAfter);
        //console.info("Date: "+dateBefore);
        
        if (dateAfter > dateBefore)
            return 1;
        else if (dateAfter < dateBefore)
            return -1;
        else
            return 0;
        
    }
    return 9; //Format invalide
    //console.info("Date invalide");
}

/**
 * Validation d'un email s'Il exite dans la bd ou non
 */

//var recu = false;

Validation.EMAILEXISTS = function() {
    var exists = false;
    var invalid = false;
    var emailInvalid = false;
    var email;
    return {
        isValid : function(field,oldValue) {
            email = field.value;
            
            if (email == "") {
                emailInvalid = true;
            } else {
                try {                            
                    doc = new XML();
                    doc.addListener(function() {});
                    doc.setAttribute("email", field.value);
                    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
                    doc.setAsyn(false);
                    response = doc.sendAndLoad("actions-existsUser.do");
                    
                    if(response.indexOf('true') != -1){
                        exists = true;
                        showExistsAlert(email);
                    } else if (response.indexOf('invalid') != -1) {
                        showInvalidAlert(email);
                        invalid = true;
                    } else if (response.indexOf('emailInvalid') != -1) {
                        emailInvalid = true;
                    }
                } catch(e) {
                    alert('err: '+e);
                }
            }
            var resp = true;
            if (emailInvalid) { 
                resp = false; 
            } else if (exists) { 
                resp = false; 
            } else if (invalid) { 
                resp = false; 
            }
            return (resp);
        },
        
        getMessage : function() {
            if (emailInvalid) {
                emailInvalid = false;
                hideAlert();
                return "Ce courriel n'est pas valide.";
            } else if (exists) {
                exists = false;
                return "Ce courriel existe d&eacute;j&agrave;.";
            } else if (invalid) {
                invalid = false;
                return "Ce compte est déjà existant, mais inactif.";
                //return "Vous vous &ecirc;tes d&eacute;j&agrave; inscrit, nous vous avons envoy&eacute; un courriel explicatif pour activer votre compte.";
            }
        },
        
        isCancellable : function() { 
            hideAlert();
            return false; 
        },
        
        toString : function() {
            return "LINK()";
        }
    };
}

function sendAction(email) {
    doc2 = new XML();
    doc2._method = "POST";
    doc2.setAttribute("email", email);
    doc2.setAttribute("uniqId", Math.round(Math.random()*10000));
    var response = doc2.sendAndLoad("actions-validateEmail.do");
    //alert(response);
    alert('Un courriel d\'activation a \u00E9t\u00E9 envoy\u00E9 \u00E0 '+email);
    hideAlert();
}


function hideAlert() {
    document.getElementById('alertBox').style.display = "none";
}

function showExistsAlert(email) {
    document.getElementById('alertMessage').innerHTML = "\u003Ca href\u003D\u0022page-lostpwd.do?email="+email+"\u0022\u003E Cliquez ici\u003C\u002Fa\u003E pour r\u00E9cup\u00E9rer votre mot de passe.";
    document.getElementById('alertBox').style.display = "block";
}

function showInvalidAlert(email) {
    document.getElementById('alertMessage').innerHTML = "Cependant\u002C le compte associé au courriel n\u0027a pas \u00E9t\u00E9 activ\u00E9\u002E\u003Cbr \u002F\u003E \u003Ca href\u003D\u0022javascript\u003AsendAction\u0028'"+email+"' \u0029\u003B\u0022\u003E Cliquez ici\u003C\u002Fa\u003E pour recevoir un courriel d\u0027activation \u00E0 cette adresse.";
    document.getElementById('alertBox').style.display = "block";
}
TabbedPane = function(sections) {	
    this._sections = [];
    this._sectionsMaps = {};
    this._currentSection = null;    
    if(sections && sections.length){
        for(var i=0; i<sections.length; i++){
            this.addSection(sections[i]);
        }
    }
}

var TB = TabbedPane.prototype;

TabbedPane.getInstance = function() {
    if(!this.__instance){
        this.__instance = new TabbedPane();
    }
    return this.__instance;
}

TB.submit = function(form){
    var invalidTab = this.getInvalidSection();       
    if(invalidTab != null){
        this.forceShowSection(invalidTab);
        invalidTab.showErrors();
    }else{
        this.preSubmit();
        form.submit();
    }
}

TB.handleSubmit = function(){
    var invalidTab = this.getInvalidSection();       
    if(invalidTab != null){
        this.forceShowSection(invalidTab);
        invalidTab.showErrors();
        return false;
    }else{
        this.preSubmit();
    }
    return true;
}

TB.addSection = function(section) {	
    var index = this._sections.length;	
    section.index = index;	
    this._sections[index] = section;
    this._sectionsMaps[section._id] = section;
}

TB.getSection = function(id) {	
    return this._sectionsMaps[id];
}


/**
 * override this method to add a behavior before submiting the form
 */
TB.preSubmit = function(){}


/**
 * Procède à la validation de toutes les sections,
 * Si une section n'est pas valide, elle sera retournée.
 * Si toute les section sont valide, on retourne null.
 */
TB.getInvalidSection = function() {
    for(var i=0; i<this._sections.length; i++){
        if(!this._sections[i].isValid()){
            return this._sections[i];
        }
    }   
    return null;
}



/**
 * Retourne la section précedente à celle envoyé en parametre
 */
TB.getPreviousSection = function() {
    for(var i=0; i<this._sections.length; i++){
        if(this._sections[i] === this._currentSection && i > 0){
            return this._sections[i-1];
        }
    }   
    return null;
}


/**
 *Affiche une section
 *@param tab Une référence à une instance de la classe "TabbedPaneSection"
 */
TB.forceShowSection = function(tab) {
    if(this._currentSection != null){
        this._currentSection.hide();
    }
    this._currentSection = tab;
    this._currentSection.show();
}


/**
 *Affiche une section (seulement si la section courante est valide)
 *@param id Le nom de la section
 */
TB.showSection = function(id) {    
    for(var i=0; i<this._sections.length; i++) {      
        if(this._sections[i]._id == id) {
            if(this._currentSection != null) {	                             
                if(this._currentSection.isValid()){	
                    this._currentSection.hide();
                }else{                    
                    this._currentSection.showErrors();
                    return;
                }
            }                        
            
            this._currentSection = this._sections[i];
            this._currentSection.show();
            this.onSelect(id);
            return;
        }
    }
}


/**
 *Retourne la section suivante. (null s'il n'y a pas de suivate) 
 */
TB.getNextSection = function() {
    for(var i=0; i<this._sections.length; i++){
        if(this._sections[i] === this._currentSection){
            return this._sections[i+1];
        }
    }
    return null;                       
}

TB.getCurrentSection = function() {    
    return this._currentSection;                       
}

TB.onSelect = function(){}

TabbedPaneSection = function(id) {
    this._id = id;
    this._element = document.getElementById("tab_" + id);
    this._visible = false;
    this._fields = [];
    this._btn = document.getElementById("btn_" + id);
}


var TBS = TabbedPaneSection.prototype;

TBS.addValidation = function(validation) {
    this._validations.push(validation);
}

TBS.addField = function(fieldName, error, validations, name, type) {
    if(typeof validations == "string"){
         validations = Field.getValidations(validations);
    }

    this._fields.push(new Field(fieldName, error, validations, name, type));
}

TBS.show = function() {
    // FIXME: should reworks again for multi-tabbed forms
    //this._element.style.display = "block";
    //this.onOpen();
}

TBS.hide = function() {
    // FIXME: should reworks again for multi-tabbed forms
    //this._element.style.display = "none";
    //this.onClose();
}

TBS.isOpen = function() {
    return (this._element.style.display == "block");
}

TBS.isValid = function() {
    var fields = this._fields;
    var length = fields.length;

    var ok = true;    
    for(var i=0; i<length; i++){
        if(!fields[i].isValid()){
            ok = false;
        }
    }    
    return ok;
}

TBS.showErrors = function(){
    alert("Certains champs ne sont pas valides. " + 
    "Assurez-vous que tous les champs sont valides avant de soumettre le formulaire.");
}

TBS.onOpen = function(){          
    
}

TBS.onClose = function(){ 
    
}
/**
 * Classe qui permet d'executer des commandes dans le onLoad du body
 *
 *@author Nicolas Desy 
 */ 


InitCommand = {}; 
InitCommand._commandQueue = [];

/**
 * Ajoute une commande dans la queue
 * @cmd La commande : soit une fonction ou bien un object avec une methode execute()
 */ 
InitCommand.addCommand = function(cmd){
    if(typeof cmd == "function"){
        InitCommand._commandQueue.push({execute:cmd});
    }else{
        InitCommand._commandQueue.push(cmd);
    }
}

InitCommand.clear = function(){
    InitCommand._commandQueue = [];
}



window.onload = function(){
    var queue = InitCommand._commandQueue;
    for(var i=0; i<queue.length; i++){
        if(queue[i] != null)
            queue[i].execute();
    }
}
// ===================================================================
// Author: Matt Kruse <matt@mattkruse.com>
// WWW: http://www.mattkruse.com/
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however it is
// appreciated by the author if at least my web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download. 
// If you wish to share this code with others, please just point them
// to the URL instead.
// Please DO NOT link directly to my .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================

/* 
OptionTransfer.js
Last Modified: 7/12/2004
 
DESCRIPTION: This widget is used to easily and quickly create an interface
where the user can transfer choices from one select box to another. For
example, when selecting which columns to show or hide in search results.
This object adds value by automatically storing the values that were added
or removed from each list, as well as the state of the final list. 
 
COMPATABILITY: Should work on all Javascript-compliant browsers.
 
USAGE:
// Create a new OptionTransfer object. Pass it the field names of the left
// select box and the right select box.
var ot = new OptionTransfer("from","to");
 
// Optionally tell the lists whether or not to auto-sort when options are 
// moved. By default, the lists will be sorted.
ot.setAutoSort(true);
 
// Optionally set the delimiter to be used to separate values that are
// stored in hidden fields for the added and removed options, as well as
// final state of the lists. Defaults to a comma.
ot.setDelimiter("|");
 
// You can set a regular expression for option texts which are _not_ allowed to
// be transferred in either direction
ot.setStaticOptionRegex("static");
 
// These functions assign the form fields which will store the state of
// the lists. Each one is optional, so you can pick to only store the
// new options which were transferred to the right list, for example.
// Each function takes the name of a HIDDEN or TEXT input field.
 
// Store list of options removed from left list into an input field
ot.saveRemovedLeftOptions("removedLeft");
// Store list of options removed from right list into an input field
ot.saveRemovedRightOptions("removedRight");
// Store list of options added to left list into an input field
ot.saveAddedLeftOptions("addedLeft");
// Store list of options radded to right list into an input field
ot.saveAddedRightOptions("addedRight");
// Store all options existing in the left list into an input field
ot.saveNewLeftOptions("newLeft");
// Store all options existing in the right list into an input field
ot.saveNewRightOptions("newRight");
 
// IMPORTANT: This step is required for the OptionTransfer object to work
// correctly.
// Add a call to the BODY onLoad="" tag of the page, and pass a reference to
// the form which contains the select boxes and input fields.
BODY onLoad="ot.init(document.forms[0])"
 
// ADDING ACTIONS INTO YOUR PAGE
// Finally, add calls to the object to move options back and forth, either
// from links in your page or from double-clicking the options themselves.
// See example page, and use the following methods:
ot.transferRight();
ot.transferAllRight();
ot.transferLeft();
ot.transferAllLeft();
 
 
NOTES:
1) Requires the functions in selectbox.js
 
 */ 

function hasOptions(obj) {
    if (obj!=null && obj.options!=null) { return true; }
    return false;
}

// -------------------------------------------------------------------
// selectUnselectMatchingOptions(select_object,regex,select/unselect,true/false)
//  This is a general function used by the select functions below, to
//  avoid code duplication
// -------------------------------------------------------------------
function selectUnselectMatchingOptions(obj,regex,which,only) {
    if (window.RegExp) {
        if (which == "select") {
            var selected1=true;
            var selected2=false;
        }
        else if (which == "unselect") {
            var selected1=false;
            var selected2=true;
        }
        else {
            return;
        }
        var re = new RegExp(regex);
        if (!hasOptions(obj)) { return; }
        for (var i=0; i<obj.options.length; i++) {
            if (re.test(obj.options[i].text)) {
                obj.options[i].selected = selected1;
            }
            else {
                if (only == true) {
                    obj.options[i].selected = selected2;
                }
            }
        }
    }
}

// -------------------------------------------------------------------
// selectMatchingOptions(select_object,regex)
//  This function selects all options that match the regular expression
//  passed in. Currently-selected options will not be changed.
// -------------------------------------------------------------------
function selectMatchingOptions(obj,regex) {
    selectUnselectMatchingOptions(obj,regex,"select",false);
}
// -------------------------------------------------------------------
// selectOnlyMatchingOptions(select_object,regex)
//  This function selects all options that match the regular expression
//  passed in. Selected options that don't match will be un-selected.
// -------------------------------------------------------------------
function selectOnlyMatchingOptions(obj,regex) {
    selectUnselectMatchingOptions(obj,regex,"select",true);
}
// -------------------------------------------------------------------
// unSelectMatchingOptions(select_object,regex)
//  This function Unselects all options that match the regular expression
//  passed in. 
// -------------------------------------------------------------------
function unSelectMatchingOptions(obj,regex) {
    selectUnselectMatchingOptions(obj,regex,"unselect",false);
}

// -------------------------------------------------------------------
// sortSelect(select_object)
//   Pass this function a SELECT object and the options will be sorted
//   by their text (display) values
// -------------------------------------------------------------------
function sortSelect(obj) {
    var o = new Array();
    if (!hasOptions(obj)) { return; }
    for (var i=0; i<obj.options.length; i++) {
        o[o.length] = new Option( obj.options[i].text, obj.options[i].value, obj.options[i].defaultSelected, obj.options[i].selected) ;
    }
    if (o.length==0) { return; }
    o = o.sort( 
    function(a,b) { 
        if ((a.text+"") < (b.text+"")) { return -1; }
        if ((a.text+"") > (b.text+"")) { return 1; }
        return 0;
    } 
    );
    
    for (var i=0; i<o.length; i++) {
        obj.options[i] = new Option(o[i].text, o[i].value, o[i].defaultSelected, o[i].selected);
    }
}

// -------------------------------------------------------------------
// selectAllOptions(select_object)
//  This function takes a select box and selects all options (in a 
//  multiple select object). This is used when passing values between
//  two select boxes. Select all options in the right box before 
//  submitting the form so the values will be sent to the server.
// -------------------------------------------------------------------
function selectAllOptions(obj) {
    if (!hasOptions(obj)) { return; }
    for (var i=0; i<obj.options.length; i++) {
        obj.options[i].selected = true;
    }
}

// -------------------------------------------------------------------
// moveSelectedOptions(select_object,select_object[,autosort(true/false)[,regex]])
//  This function moves options between select boxes. Works best with
//  multi-select boxes to create the common Windows control effect.
//  Passes all selected values from the first object to the second
//  object and re-sorts each box.
//  If a third argument of 'false' is passed, then the lists are not
//  sorted after the move.
//  If a fourth string argument is passed, this will function as a
//  Regular Expression to match against the TEXT or the options. If 
//  the text of an option matches the pattern, it will NOT be moved.
//  It will be treated as an unmoveable option.
//  You can also put this into the <SELECT> object as follows:
//    onDblClick="moveSelectedOptions(this,this.form.target)
//  This way, when the user double-clicks on a value in one box, it
//  will be transferred to the other (in browsers that support the 
//  onDblClick() event handler).
// -------------------------------------------------------------------

function getSelectedOption(liste) {
    if (!hasOptions(liste)) { return null; }
    var options = liste.options;
    for (var i=0; i<options.length; i++) {     
        if (options[i].selected) {
            return options[i];
        }
    }
    return null;
}


function getOptionByValue(liste, value) {
   // alert("getOptionByValue="+value);
    if (!hasOptions(liste)) { return null; }
    var options = liste.options;
    for (var i=0; i<options.length; i++) {     
        if (options[i].value == value) {
            return options[i];
        }
    }
    return null;
}


function setOptionLabel(liste, opt, label) {
   // alert("getOptionByValue="+value);
    if (!hasOptions(liste)) { return ; }
    var options = liste.options;
    for (var i=0; i<options.length; i++) {     
        if (options[i].value == opt.value) {
            options[i] = new Option(label, options[i].value, false, options[i].selected);
            return;
        }
    }
}

/**
 * Retourne un Array contenant l'item sélectionné, le précedent et le suivant
 * Le tableau à toujours 3 élément, s'il est impossible de retrouver l'item précedent,
 *   par exemple si l'item sélectionné est le premier dans la liste, il aura la valeur 'null'
 * result[0] = item précédant
 * result[1] = item sélectionné
 * result[2] = item suivant
 */
function getSelectedRange(liste) {   
    var range = [null,null,null];
    if (!hasOptions(liste)) { return range; }    
    var options = liste.options;
    for (var i=0; i<options.length; i++) {     
        if (options[i].selected) {
            range[1] = options[i];
            if(i > 0) range[0] = options[i-1];
            if(i < options.length-1) range[2] = options[i+1];
            return range;
        }
    }
    return range;
}

function moveSelectedOptions(from,to) {
    // Unselect matching options, if required
    if (arguments.length>3) {
        var regex = arguments[3];
        if (regex != "") {
            unSelectMatchingOptions(from,regex);
        }
    }
    // Move them over
    if (!hasOptions(from)) { return; }
    for (var i=0; i<from.options.length; i++) {
        var o = from.options[i];
        if (o.selected) {
            if (!hasOptions(to)) { var index = 0; } else { var index=to.options.length; }
            to.options[index] = new Option( o.text, o.value, false, false);
        }
    }
    // Delete them from original
    for (var i=(from.options.length-1); i>=0; i--) {
        var o = from.options[i];
        if (o.selected) {
            from.options[i] = null;
        }
    }
    if ((arguments.length<3) || (arguments[2]==true)) {
        sortSelect(from);
        sortSelect(to);
    }
    from.selectedIndex = -1;
    to.selectedIndex = -1;
}

// -------------------------------------------------------------------
// copySelectedOptions(select_object,select_object[,autosort(true/false)])
//  This function copies options between select boxes instead of 
//  moving items. Duplicates in the target list are not allowed.
// -------------------------------------------------------------------
function copySelectedOptions(from,to) {
    var options = new Object();
    if (hasOptions(to)) {
        for (var i=0; i<to.options.length; i++) {
            options[to.options[i].value] = to.options[i].text;
        }
    }
    if (!hasOptions(from)) { return; }
    for (var i=0; i<from.options.length; i++) {
        var o = from.options[i];
        if (o.selected) {
            if (options[o.value] == null || options[o.value] == "undefined" || options[o.value]!=o.text) {
                if (!hasOptions(to)) { var index = 0; } else { var index=to.options.length; }
                to.options[index] = new Option( o.text, o.value, false, false);
            }
        }
    }
    if ((arguments.length<3) || (arguments[2]==true)) {
        sortSelect(to);
    }
    from.selectedIndex = -1;
    to.selectedIndex = -1;
}

// -------------------------------------------------------------------
// moveAllOptions(select_object,select_object[,autosort(true/false)[,regex]])
//  Move all options from one select box to another.
// -------------------------------------------------------------------
function moveAllOptions(from,to) {
    selectAllOptions(from);
    if (arguments.length==2) {
        moveSelectedOptions(from,to);
    }
    else if (arguments.length==3) {
        moveSelectedOptions(from,to,arguments[2]);
    }
    else if (arguments.length==4) {
        moveSelectedOptions(from,to,arguments[2],arguments[3]);
    }
}

// -------------------------------------------------------------------
// copyAllOptions(select_object,select_object[,autosort(true/false)])
//  Copy all options from one select box to another, instead of
//  removing items. Duplicates in the target list are not allowed.
// -------------------------------------------------------------------
function copyAllOptions(from,to) {
    selectAllOptions(from);
    if (arguments.length==2) {
        copySelectedOptions(from,to);
    }
    else if (arguments.length==3) {
        copySelectedOptions(from,to,arguments[2]);
    }
}

// -------------------------------------------------------------------
// swapOptions(select_object,option1,option2)
//  Swap positions of two options in a select list
// -------------------------------------------------------------------
function swapOptions(obj,i,j) {
    var o = obj.options;
    var i_selected = o[i].selected;
    var j_selected = o[j].selected;
    var temp = new Option(o[i].text, o[i].value, o[i].defaultSelected, o[i].selected);
    var temp2= new Option(o[j].text, o[j].value, o[j].defaultSelected, o[j].selected);
    o[i] = temp2;
    o[j] = temp;
    o[i].selected = j_selected;
    o[j].selected = i_selected;
}

// -------------------------------------------------------------------
// moveOptionUp(select_object)
//  Move selected option in a select list up one
// -------------------------------------------------------------------
function moveOptionUp(obj) {
    if (!hasOptions(obj)) { return; }
    for (i=0; i<obj.options.length; i++) {
        if (obj.options[i].selected) {
            if (i != 0 && !obj.options[i-1].selected) {
                swapOptions(obj,i,i-1);
                obj.options[i-1].selected = true;
            }
        }
    }
}

// -------------------------------------------------------------------
// moveOptionDown(select_object)
//  Move selected option in a select list down one
// -------------------------------------------------------------------
function moveOptionDown(obj) {
    if (!hasOptions(obj)) { return; }
    for (i=obj.options.length-1; i>=0; i--) {
        if (obj.options[i].selected) {
            if (i != (obj.options.length-1) && ! obj.options[i+1].selected) {
                swapOptions(obj,i,i+1);
                obj.options[i+1].selected = true;
            }
        }
    }
}

// -------------------------------------------------------------------
// removeSelectedOptions(select_object)
//  Remove all selected options from a list
//  (Thanks to Gene Ninestein)
// -------------------------------------------------------------------
function removeSelectedOptions(from) { 
    if (!hasOptions(from)) { return; }
    if (from.type=="select-one") {
        from.options[from.selectedIndex] = null;
    }
    else {
        for (var i=(from.options.length-1); i>=0; i--) { 
            var o=from.options[i]; 
            if (o.selected) { 
                from.options[i] = null; 
            } 
        }
    }
    from.selectedIndex = -1; 
} 

// -------------------------------------------------------------------
// removeAllOptions(select_object)
//  Remove all options from a list
// -------------------------------------------------------------------
function removeAllOptions(from) { 
    if (!hasOptions(from)) { return; }
    for (var i=(from.options.length-1); i>=0; i--) { 
        from.options[i] = null; 
    } 
    from.selectedIndex = -1; 
} 

// -------------------------------------------------------------------
// addOption(select_object,display_text,value,selected)
//  Add an option to a list
// -------------------------------------------------------------------
function addOption(obj,text,value,selected) {
    if (obj!=null && obj.options!=null) {
        obj.options[obj.options.length] = new Option(text, value, false, selected);
    }
}


function OT_transferLeft() { moveSelectedOptions(this.right,this.left,this.autoSort,this.staticOptionRegex); this.update(); }
function OT_transferRight() { moveSelectedOptions(this.left,this.right,this.autoSort,this.staticOptionRegex); this.update(); }
function OT_transferAllLeft() { moveAllOptions(this.right,this.left,this.autoSort,this.staticOptionRegex); this.update(); }
function OT_transferAllRight() { moveAllOptions(this.left,this.right,this.autoSort,this.staticOptionRegex); this.update(); }
function OT_saveRemovedLeftOptions(f) { this.removedLeftField = f; }
function OT_saveRemovedRightOptions(f) { this.removedRightField = f; }
function OT_saveAddedLeftOptions(f) { this.addedLeftField = f; }
function OT_saveAddedRightOptions(f) { this.addedRightField = f; }
function OT_saveNewLeftOptions(f) { this.newLeftField = f; }
function OT_saveNewRightOptions(f) { this.newRightField = f; }
function OT_update() {
    var removedLeft = new Object();
    var removedRight = new Object();
    var addedLeft = new Object();
    var addedRight = new Object();
    var newLeft = new Object();
    var newRight = new Object();
    for (var i=0;i<this.left.options.length;i++) {
        var o=this.left.options[i];
        newLeft[o.value]=1;
        if (typeof(this.originalLeftValues[o.value])=="undefined") {
            addedLeft[o.value]=1;
            removedRight[o.value]=1;
        }
    }
    for (var i=0;i<this.right.options.length;i++) {
        var o=this.right.options[i];
        newRight[o.value]=1;
        if (typeof(this.originalRightValues[o.value])=="undefined") {
            addedRight[o.value]=1;
            removedLeft[o.value]=1;
        }
    }
    if (this.removedLeftField!=null) { this.removedLeftField.value = OT_join(removedLeft,this.delimiter); }
    if (this.removedRightField!=null) { this.removedRightField.value = OT_join(removedRight,this.delimiter); }
    if (this.addedLeftField!=null) { this.addedLeftField.value = OT_join(addedLeft,this.delimiter); }
    if (this.addedRightField!=null) { this.addedRightField.value = OT_join(addedRight,this.delimiter); }
    if (this.newLeftField!=null) { this.newLeftField.value = OT_join(newLeft,this.delimiter); }
    if (this.newRightField!=null) { this.newRightField.value = OT_join(newRight,this.delimiter); }
}
function OT_join(o,delimiter) {
    var val; var str="";
    for(val in o){
        if (str.length>0) { str=str+delimiter; }
        str=str+val;
    }
    return str;
}
function OT_setDelimiter(val) { this.delimiter=val; }
function OT_setAutoSort(val) { this.autoSort=val; }
function OT_setStaticOptionRegex(val) { this.staticOptionRegex=val; }
function OT_init(theform) {
    this.form = theform;
    if(!theform[this.left]){alert("OptionTransfer init(): Left select list does not exist in form!");return false;}
    if(!theform[this.right]){alert("OptionTransfer init(): Right select list does not exist in form!");return false;}
    this.left=theform[this.left];
    this.right=theform[this.right];
    for(var i=0;i<this.left.options.length;i++) {
        this.originalLeftValues[this.left.options[i].value]=1;
    }
    for(var i=0;i<this.right.options.length;i++) {
        this.originalRightValues[this.right.options[i].value]=1;
    }
    if(this.removedLeftField!=null) { this.removedLeftField=theform[this.removedLeftField]; }
    if(this.removedRightField!=null) { this.removedRightField=theform[this.removedRightField]; }
    if(this.addedLeftField!=null) { this.addedLeftField=theform[this.addedLeftField]; }
    if(this.addedRightField!=null) { this.addedRightField=theform[this.addedRightField]; }
    if(this.newLeftField!=null) { this.newLeftField=theform[this.newLeftField]; }
    if(this.newRightField!=null) { this.newRightField=theform[this.newRightField]; }
    this.update();
}
// -------------------------------------------------------------------
// OptionTransfer()
//  This is the object interface.
// -------------------------------------------------------------------
function OptionTransfer(l,r) {
    this.form = null;
    this.left=l;
    this.right=r;
    this.autoSort=true;
    this.delimiter=",";
    this.staticOptionRegex = "";
    this.originalLeftValues = new Object();
    this.originalRightValues = new Object();
    this.removedLeftField = null;
    this.removedRightField = null;
    this.addedLeftField = null;
    this.addedRightField = null;
    this.newLeftField = null;
    this.newRightField = null;
    this.transferLeft=OT_transferLeft;
    this.transferRight=OT_transferRight;
    this.transferAllLeft=OT_transferAllLeft;
    this.transferAllRight=OT_transferAllRight;
    this.saveRemovedLeftOptions=OT_saveRemovedLeftOptions;
    this.saveRemovedRightOptions=OT_saveRemovedRightOptions;
    this.saveAddedLeftOptions=OT_saveAddedLeftOptions;
    this.saveAddedRightOptions=OT_saveAddedRightOptions;
    this.saveNewLeftOptions=OT_saveNewLeftOptions;
    this.saveNewRightOptions=OT_saveNewRightOptions;
    this.setDelimiter=OT_setDelimiter;
    this.setAutoSort=OT_setAutoSort;
    this.setStaticOptionRegex=OT_setStaticOptionRegex;
    this.init=OT_init;
    this.update=OT_update;
}
//\/////
//\  overLIB 4.17 - You may not remove or change this notice.
//\  Copyright Erik Bosrup 1998-2004. All rights reserved.
//\
//\  Contributors are listed on the homepage.
//\  This file might be old, always check for the latest version at:
//\  http://www.bosrup.com/web/overlib/
//\
//\  Please read the license agreement (available through the link above)
//\  before using overLIB. Direct any licensing questions to erik@bosrup.com.
//\
//\  Do not sell this as your own work or remove this copyright notice. 
//\  For full details on copying or changing this script please read the
//\  license agreement at the link above. Please give credit on sites that
//\  use overLIB and submit changes of the script so other people can use
//\  them as well.
//   $Revision: 1.3 $                $Date: 2006/02/09 15:15:27 $
//\/////
//\mini

////////
// PRE-INIT
// Ignore these lines, configuration is below.
////////
var olLoaded = 0;var pmStart = 10000000; var pmUpper = 10001000; var pmCount = pmStart+1; var pmt=''; var pms = new Array(); var olInfo = new Info('4.17', 1);
var FREPLACE = 0; var FBEFORE = 1; var FAFTER = 2; var FALTERNATE = 3; var FCHAIN=4;
var olHideForm=0;  // parameter for hiding SELECT and ActiveX elements in IE5.5+ 
var olHautoFlag = 0;  // flags for over-riding VAUTO and HAUTO if corresponding
var olVautoFlag = 0;  // positioning commands are used on the command line
registerCommands('donothing,inarray,caparray,sticky,background,noclose,caption,left,right,center,offsetx,offsety,fgcolor,bgcolor,textcolor,capcolor,closecolor,width,border,cellpad,status,autostatus,autostatuscap,height,closetext,snapx,snapy,fixx,fixy,relx,rely,fgbackground,bgbackground,padx,pady,fullhtml,above,below,capicon,textfont,captionfont,closefont,textsize,captionsize,closesize,timeout,function,delay,hauto,vauto,closeclick,wrap,followmouse,mouseoff,closetitle,cssoff,compatmode,cssclass,fgclass,bgclass,textfontclass,captionfontclass,closefontclass');

////////
// DEFAULT CONFIGURATION
// Settings you want everywhere are set here. All of this can also be
// changed on your html page or through an overLIB call.
////////
if (typeof ol_fgcolor=='undefined') var ol_fgcolor="#FFFFFF";
if (typeof ol_bgcolor=='undefined') var ol_bgcolor="#993300";
if (typeof ol_textcolor=='undefined') var ol_textcolor="#993300";
if (typeof ol_capcolor=='undefined') var ol_capcolor="#FFFFFF";
if (typeof ol_closecolor=='undefined') var ol_closecolor="#FFFFFF";
if (typeof ol_textfont=='undefined') var ol_textfont="Verdana,Arial,Helvetica";
if (typeof ol_captionfont=='undefined') var ol_captionfont="Verdana,Arial,Helvetica";
if (typeof ol_closefont=='undefined') var ol_closefont="Verdana,Arial,Helvetica";
if (typeof ol_textsize=='undefined') var ol_textsize="1";
if (typeof ol_captionsize=='undefined') var ol_captionsize="1";
if (typeof ol_closesize=='undefined') var ol_closesize="1";
if (typeof ol_width=='undefined') var ol_width="300";
if (typeof ol_border=='undefined') var ol_border="1";
if (typeof ol_cellpad=='undefined') var ol_cellpad=2;
if (typeof ol_offsetx=='undefined') var ol_offsetx=10;
if (typeof ol_offsety=='undefined') var ol_offsety=10;
if (typeof ol_text=='undefined') var ol_text="Default Text";
if (typeof ol_cap=='undefined') var ol_cap="";
if (typeof ol_sticky=='undefined') var ol_sticky=0;
if (typeof ol_background=='undefined') var ol_background="";
if (typeof ol_close=='undefined') var ol_close="X";
if (typeof ol_hpos=='undefined') var ol_hpos=RIGHT;
if (typeof ol_status=='undefined') var ol_status="";
if (typeof ol_autostatus=='undefined') var ol_autostatus=0;
if (typeof ol_height=='undefined') var ol_height=-1;
if (typeof ol_snapx=='undefined') var ol_snapx=0;
if (typeof ol_snapy=='undefined') var ol_snapy=0;
if (typeof ol_fixx=='undefined') var ol_fixx=-1;
if (typeof ol_fixy=='undefined') var ol_fixy=-1;
if (typeof ol_relx=='undefined') var ol_relx=null;
if (typeof ol_rely=='undefined') var ol_rely=null;
if (typeof ol_fgbackground=='undefined') var ol_fgbackground="";
if (typeof ol_bgbackground=='undefined') var ol_bgbackground="";
if (typeof ol_padxl=='undefined') var ol_padxl=1;
if (typeof ol_padxr=='undefined') var ol_padxr=1;
if (typeof ol_padyt=='undefined') var ol_padyt=1;
if (typeof ol_padyb=='undefined') var ol_padyb=1;
if (typeof ol_fullhtml=='undefined') var ol_fullhtml=0;
if (typeof ol_vpos=='undefined') var ol_vpos=BELOW;
if (typeof ol_aboveheight=='undefined') var ol_aboveheight=0;
if (typeof ol_capicon=='undefined') var ol_capicon="";
if (typeof ol_frame=='undefined') var ol_frame=self;
if (typeof ol_timeout=='undefined') var ol_timeout=0;
if (typeof ol_function=='undefined') var ol_function=null;
if (typeof ol_delay=='undefined') var ol_delay=0;
if (typeof ol_hauto=='undefined') var ol_hauto=0;
if (typeof ol_vauto=='undefined') var ol_vauto=0;
if (typeof ol_closeclick=='undefined') var ol_closeclick=0;
if (typeof ol_wrap=='undefined') var ol_wrap=0;
if (typeof ol_followmouse=='undefined') var ol_followmouse=1;
if (typeof ol_mouseoff=='undefined') var ol_mouseoff=0;
if (typeof ol_closetitle=='undefined') var ol_closetitle='Close';
if (typeof ol_compatmode=='undefined') var ol_compatmode=0;
if (typeof ol_css=='undefined') var ol_css=CSSOFF;
if (typeof ol_fgclass=='undefined') var ol_fgclass="";
if (typeof ol_bgclass=='undefined') var ol_bgclass="";
if (typeof ol_textfontclass=='undefined') var ol_textfontclass="";
if (typeof ol_captionfontclass=='undefined') var ol_captionfontclass="";
if (typeof ol_closefontclass=='undefined') var ol_closefontclass="";

////////
// ARRAY CONFIGURATION
////////

// You can use these arrays to store popup text here instead of in the html.
if (typeof ol_texts=='undefined') var ol_texts = new Array("Text 0", "Text 1");
if (typeof ol_caps=='undefined') var ol_caps = new Array("Caption 0", "Caption 1");

////////
// END OF CONFIGURATION
// Don't change anything below this line, all configuration is above.
////////





////////
// INIT
////////
// Runtime variables init. Don't change for config!
var o3_text="";
var o3_cap="";
var o3_sticky=0;
var o3_background="";
var o3_close="Close";
var o3_hpos=RIGHT;
var o3_offsetx=2;
var o3_offsety=2;
var o3_fgcolor="";
var o3_bgcolor="";
var o3_textcolor="";
var o3_capcolor="";
var o3_closecolor="";
var o3_width=100;
var o3_border=1;
var o3_cellpad=2;
var o3_status="";
var o3_autostatus=0;
var o3_height=-1;
var o3_snapx=0;
var o3_snapy=0;
var o3_fixx=-1;
var o3_fixy=-1;
var o3_relx=null;
var o3_rely=null;
var o3_fgbackground="";
var o3_bgbackground="";
var o3_padxl=0;
var o3_padxr=0;
var o3_padyt=0;
var o3_padyb=0;
var o3_fullhtml=0;
var o3_vpos=BELOW;
var o3_aboveheight=0;
var o3_capicon="";
var o3_textfont="Verdana,Arial,Helvetica";
var o3_captionfont="Verdana,Arial,Helvetica";
var o3_closefont="Verdana,Arial,Helvetica";
var o3_textsize="1";
var o3_captionsize="1";
var o3_closesize="1";
var o3_frame=self;
var o3_timeout=0;
var o3_timerid=0;
var o3_allowmove=0;
var o3_function=null; 
var o3_delay=0;
var o3_delayid=0;
var o3_hauto=0;
var o3_vauto=0;
var o3_closeclick=0;
var o3_wrap=0;
var o3_followmouse=1;
var o3_mouseoff=0;
var o3_closetitle='';
var o3_compatmode=0;
var o3_css=CSSOFF;
var o3_fgclass="";
var o3_bgclass="";
var o3_textfontclass="";
var o3_captionfontclass="";
var o3_closefontclass="";

// Display state variables
var o3_x = 0;
var o3_y = 0;
var o3_showingsticky = 0;
var o3_removecounter = 0;

// Our layer
var over = null;
var fnRef, hoveringSwitch = false;
var olHideDelay;

// Decide browser version
var isMac = (navigator.userAgent.indexOf("Mac") != -1);
var olOp = (navigator.userAgent.toLowerCase().indexOf('opera') > -1 && document.createTextNode);  // Opera 7
var olNs4 = (navigator.appName=='Netscape' && parseInt(navigator.appVersion) == 4);
var olNs6 = (document.getElementById) ? true : false;
var olKq = (olNs6 && /konqueror/i.test(navigator.userAgent));
var olIe4 = (document.all) ? true : false;
var olIe5 = false; 
var olIe55 = false; // Added additional variable to identify IE5.5+
var docRoot = 'document.body';

// Resize fix for NS4.x to keep track of layer
if (olNs4) {
	var oW = window.innerWidth;
	var oH = window.innerHeight;
	window.onresize = function() { if (oW != window.innerWidth || oH != window.innerHeight) location.reload(); }
}

// Microsoft Stupidity Check(tm).
if (olIe4) {
	var agent = navigator.userAgent;
	if (/MSIE/.test(agent)) {
		var versNum = parseFloat(agent.match(/MSIE[ ](\d\.\d+)\.*/i)[1]);
		if (versNum >= 5){
			olIe5=true;
			olIe55=(versNum>=5.5&&!olOp) ? true : false;
			if (olNs6) olNs6=false;
		}
	}
	if (olNs6) olIe4 = false;
}

// Check for compatability mode.
if (document.compatMode && document.compatMode == 'CSS1Compat') {
	docRoot= ((olIe4 && !olOp) ? 'document.documentElement' : docRoot);
}

// Add window onload handlers to indicate when all modules have been loaded
// For Netscape 6+ and Mozilla, uses addEventListener method on the window object
// For IE it uses the attachEvent method of the window object and for Netscape 4.x
// it sets the window.onload handler to the OLonload_handler function for Bubbling
if(window.addEventListener) window.addEventListener("load",OLonLoad_handler,false);
else if (window.attachEvent) window.attachEvent("onload",OLonLoad_handler);

// Capture events, alt. diffuses the overlib function.
var olCheckMouseCapture = true;
if ((olNs4 || olNs6 || olIe4)) {
	olMouseCapture();
} else {
	overlib = no_overlib;
	nd = no_overlib;
	ver3fix = true;
}


////////
// PUBLIC FUNCTIONS
////////

// overlib(arg0,...,argN)
// Loads parameters into global runtime variables.
function overlib() {
	if (!olLoaded || isExclusive(overlib.arguments)) return true;
	if (olCheckMouseCapture) olMouseCapture();
	if (over) {
		over = (typeof over.id != 'string') ? o3_frame.document.all['overDiv'] : over;
		cClick();
	}

	// Load defaults to runtime.
  olHideDelay=0;
	o3_text=ol_text;
	o3_cap=ol_cap;
	o3_sticky=ol_sticky;
	o3_background=ol_background;
	o3_close=ol_close;
	o3_hpos=ol_hpos;
	o3_offsetx=ol_offsetx;
	o3_offsety=ol_offsety;
	o3_fgcolor=ol_fgcolor;
	o3_bgcolor=ol_bgcolor;
	o3_textcolor=ol_textcolor;
	o3_capcolor=ol_capcolor;
	o3_closecolor=ol_closecolor;
	o3_width=ol_width;
	o3_border=ol_border;
	o3_cellpad=ol_cellpad;
	o3_status=ol_status;
	o3_autostatus=ol_autostatus;
	o3_height=ol_height;
	o3_snapx=ol_snapx;
	o3_snapy=ol_snapy;
	o3_fixx=ol_fixx;
	o3_fixy=ol_fixy;
	o3_relx=ol_relx;
	o3_rely=ol_rely;
	o3_fgbackground=ol_fgbackground;
	o3_bgbackground=ol_bgbackground;
	o3_padxl=ol_padxl;
	o3_padxr=ol_padxr;
	o3_padyt=ol_padyt;
	o3_padyb=ol_padyb;
	o3_fullhtml=ol_fullhtml;
	o3_vpos=ol_vpos;
	o3_aboveheight=ol_aboveheight;
	o3_capicon=ol_capicon;
	o3_textfont=ol_textfont;
	o3_captionfont=ol_captionfont;
	o3_closefont=ol_closefont;
	o3_textsize=ol_textsize;
	o3_captionsize=ol_captionsize;
	o3_closesize=ol_closesize;
	o3_timeout=ol_timeout;
	o3_function=ol_function;
	o3_delay=ol_delay;
	o3_hauto=ol_hauto;
	o3_vauto=ol_vauto;
	o3_closeclick=ol_closeclick;
	o3_wrap=ol_wrap;	
	o3_followmouse=ol_followmouse;
	o3_mouseoff=ol_mouseoff;
	o3_closetitle=ol_closetitle;
	o3_css=ol_css;
	o3_compatmode=ol_compatmode;
	o3_fgclass=ol_fgclass;
	o3_bgclass=ol_bgclass;
	o3_textfontclass=ol_textfontclass;
	o3_captionfontclass=ol_captionfontclass;
	o3_closefontclass=ol_closefontclass;
	
	setRunTimeVariables();
	
	fnRef = '';
	
	// Special for frame support, over must be reset...
	o3_frame = ol_frame;
	
	if(!(over=createDivContainer())) return false;

	parseTokens('o3_', overlib.arguments);
	if (!postParseChecks()) return false;

	if (o3_delay == 0) {
		return runHook("olMain", FREPLACE);
 	} else {
		o3_delayid = setTimeout("runHook('olMain', FREPLACE)", o3_delay);
		return false;
	}
}

// Clears popups if appropriate
function nd(time) {
	if (olLoaded && !isExclusive()) {
		hideDelay(time);  // delay popup close if time specified

		if (o3_removecounter >= 1) { o3_showingsticky = 0 };
		
		if (o3_showingsticky == 0) {
			o3_allowmove = 0;
			if (over != null && o3_timerid == 0) runHook("hideObject", FREPLACE, over);
		} else {
			o3_removecounter++;
		}
	}
	
	return true;
}

// The Close onMouseOver function for stickies
function cClick() {
	if (olLoaded) {
		runHook("hideObject", FREPLACE, over);
		o3_showingsticky = 0;	
	}	
	return false;
}

// Method for setting page specific defaults.
function overlib_pagedefaults() {
	parseTokens('ol_', overlib_pagedefaults.arguments);
}


////////
// OVERLIB MAIN FUNCTION
////////

// This function decides what it is we want to display and how we want it done.
function olMain() {
	var layerhtml, styleType;
 	runHook("olMain", FBEFORE);
 	
	if (o3_background!="" || o3_fullhtml) {
		// Use background instead of box.
		layerhtml = runHook('ol_content_background', FALTERNATE, o3_css, o3_text, o3_background, o3_fullhtml);
	} else {
		// They want a popup box.
		styleType = (pms[o3_css-1-pmStart] == "cssoff" || pms[o3_css-1-pmStart] == "cssclass");

		// Prepare popup background
		if (o3_fgbackground != "") o3_fgbackground = "background=\""+o3_fgbackground+"\"";
		if (o3_bgbackground != "") o3_bgbackground = (styleType ? "background=\""+o3_bgbackground+"\"" : o3_bgbackground);

		// Prepare popup colors
		if (o3_fgcolor != "") o3_fgcolor = (styleType ? "bgcolor=\""+o3_fgcolor+"\"" : o3_fgcolor);
		if (o3_bgcolor != "") o3_bgcolor = (styleType ? "bgcolor=\""+o3_bgcolor+"\"" : o3_bgcolor);

		// Prepare popup height
		if (o3_height > 0) o3_height = (styleType ? "height=\""+o3_height+"\"" : o3_height);
		else o3_height = "";

		// Decide which kinda box.
		if (o3_cap=="") {
			// Plain
			layerhtml = runHook('ol_content_simple', FALTERNATE, o3_css, o3_text);
		} else {
			// With caption
			if (o3_sticky) {
				// Show close text
				layerhtml = runHook('ol_content_caption', FALTERNATE, o3_css, o3_text, o3_cap, o3_close);
			} else {
				// No close text
				layerhtml = runHook('ol_content_caption', FALTERNATE, o3_css, o3_text, o3_cap, "");
			}
		}
	}	

	// We want it to stick!
	if (o3_sticky) {
		if (o3_timerid > 0) {
			clearTimeout(o3_timerid);
			o3_timerid = 0;
		}
		o3_showingsticky = 1;
		o3_removecounter = 0;
	}

	// Created a separate routine to generate the popup to make it easier
	// to implement a plugin capability
	if (!runHook("createPopup", FREPLACE, layerhtml)) return false;

	// Prepare status bar
	if (o3_autostatus > 0) {
		o3_status = o3_text;
		if (o3_autostatus > 1) o3_status = o3_cap;
	}

	// When placing the layer the first time, even stickies may be moved.
	o3_allowmove = 0;

	// Initiate a timer for timeout
	if (o3_timeout > 0) {          
		if (o3_timerid > 0) clearTimeout(o3_timerid);
		o3_timerid = setTimeout("cClick()", o3_timeout);
	}

	// Show layer
	runHook("disp", FREPLACE, o3_status);
	runHook("olMain", FAFTER);

	return (olOp && event && event.type == 'mouseover' && !o3_status) ? '' : (o3_status != '');
}

////////
// LAYER GENERATION FUNCTIONS
////////
// These functions just handle popup content with tags that should adhere to the W3C standards specification.

// Makes simple table without caption
function ol_content_simple(text) {
	txt='<table width="'+o3_width+ '" border="0" cellpadding="'+o3_border+'" cellspacing="0" '+(o3_bgclass ? 'class="'+o3_bgclass+'"' : o3_bgcolor+' '+o3_height)+'><tr><td><table width="100%" border="0" cellpadding="' + o3_cellpad + '" cellspacing="0" '+(o3_fgclass ? 'class="'+o3_fgclass+'"' : o3_fgcolor+' '+o3_fgbackground+' '+o3_height)+'><tr><td valign="TOP"'+(o3_textfontclass ? ' class="'+o3_textfontclass+'">' : '>')+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize))+'</td></tr></table></td></tr></table>';

	set_background("");
	return txt;
}

// Makes table with caption and optional close link
function ol_content_caption(text,title,close) {
	var nameId;
	closing="";
	closeevent="onmouseover";
	if (o3_closeclick==1) closeevent= (o3_closetitle ? "title='" + o3_closetitle +"'" : "") + " onclick";
	if (o3_capicon!="") {
		nameId=' hspace=\"5\"'+' align=\"middle\" alt=\"\"';
		if (typeof o3_dragimg!='undefined'&&o3_dragimg) nameId=' hspace=\"5\"'+' name=\"'+o3_dragimg+'\" id=\"'+o3_dragimg+'\" align=\"middle\" alt=\"Drag Enabled\" title=\"Drag Enabled\"';
		o3_capicon='<img src=\"'+o3_capicon+'\"'+nameId+' />';
	}

	if (close != "") 
		closing='<td '+(!o3_compatmode && o3_closefontclass ? 'class="'+o3_closefontclass : 'align="RIGHT')+'"><a href="javascript:return '+fnRef+'cClick();"'+((o3_compatmode && o3_closefontclass) ? ' class="' + o3_closefontclass + '" ' : ' ')+closeevent+'="return '+fnRef+'cClick();">'+(o3_closefontclass ? '' : wrapStr(0,o3_closesize,'close'))+close+(o3_closefontclass ? '' : wrapStr(1,o3_closesize,'close'))+'</a></td>';
	txt='<table width="'+o3_width+ '" border="0" cellpadding="'+o3_border+'" cellspacing="0" '+(o3_bgclass ? 'class="'+o3_bgclass+'"' : o3_bgcolor+' '+o3_bgbackground+' '+o3_height)+'><tr><td><table width="100%" border="0" cellpadding="0" cellspacing="0"><tr><td'+(o3_captionfontclass ? ' class="'+o3_captionfontclass+'">' : '>')+(o3_captionfontclass ? '' : '<b>'+wrapStr(0,o3_captionsize,'caption'))+o3_capicon+title+(o3_captionfontclass ? '' : wrapStr(1,o3_captionsize)+'</b>')+'</td>'+closing+'</tr></table><table width="100%" border="0" cellpadding="' + o3_cellpad + '" cellspacing="0" '+(o3_fgclass ? 'class="'+o3_fgclass+'"' : o3_fgcolor+' '+o3_fgbackground+' '+o3_height)+'><tr><td valign="TOP"'+(o3_textfontclass ? ' class="'+o3_textfontclass+'">' :'>')+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize)) + '</td></tr></table></td></tr></table>';

	set_background("");
	return txt;
}

// Sets the background picture,padding and lots more. :)
function ol_content_background(text,picture,hasfullhtml) {
	if (hasfullhtml) {
		txt=text;
	} else {
		txt='<table width="'+o3_width+'" border="0" cellpadding="0" cellspacing="0" height="'+o3_height+'"><tr><td colspan="3" height="'+o3_padyt+'"></td></tr><tr><td width="'+o3_padxl+'"></td><td valign="TOP" width="'+(o3_width-o3_padxl-o3_padxr)+(o3_textfontclass ? '" class="'+o3_textfontclass : '')+'">'+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize))+'</td><td width="'+o3_padxr+'"></td></tr><tr><td colspan="3" height="'+o3_padyb+'"></td></tr></table>';
	}

	set_background(picture);
	return txt;
}

// Loads a picture into the div.
function set_background(pic) {
	if (pic == "") {
		if (olNs4) {
			over.background.src = null; 
		} else if (over.style) {
			over.style.backgroundImage = "none";
		}
	} else {
		if (olNs4) {
			over.background.src = pic;
		} else if (over.style) {
			over.style.width=o3_width + 'px';
			over.style.backgroundImage = "url("+pic+")";
		}
	}
}

////////
// HANDLING FUNCTIONS
////////
var olShowId=-1;

// Displays the popup
function disp(statustext) {
	runHook("disp", FBEFORE);
	
	if (o3_allowmove == 0) {
		runHook("placeLayer", FREPLACE);
		(olNs6&&olShowId<0) ? olShowId=setTimeout("runHook('showObject', FREPLACE, over)", 1) : runHook("showObject", FREPLACE, over);
		o3_allowmove = (o3_sticky || o3_followmouse==0) ? 0 : 1;
	}
	
	runHook("disp", FAFTER);

	if (statustext != "") self.status = statustext;
}

// Creates the actual popup structure
function createPopup(lyrContent){
	runHook("createPopup", FBEFORE);
	
	if (o3_wrap) {
		var wd,ww,theObj = (olNs4 ? over : over.style);
		theObj.top = theObj.left = ((olIe4&&!olOp) ? 0 : -10000) + (!olNs4 ? 'px' : 0);
		layerWrite(lyrContent);
		wd = (olNs4 ? over.clip.width : over.offsetWidth);
		if (wd > (ww=windowWidth())) {
			lyrContent=lyrContent.replace(/\&nbsp;/g, ' ');
			o3_width=ww;
			o3_wrap=0;
		} 
	}

	layerWrite(lyrContent);
	
	// Have to set o3_width for placeLayer() routine if o3_wrap is turned on
	if (o3_wrap) o3_width=(olNs4 ? over.clip.width : over.offsetWidth);
	
	runHook("createPopup", FAFTER, lyrContent);

	return true;
}

// Decides where we want the popup.
function placeLayer() {
	var placeX, placeY, widthFix = 0;
	
	// HORIZONTAL PLACEMENT, re-arranged to work in Safari
	if (o3_frame.innerWidth) widthFix=18; 
	iwidth = windowWidth();

	// Horizontal scroll offset
	winoffset=(olIe4) ? eval('o3_frame.'+docRoot+'.scrollLeft') : o3_frame.pageXOffset;

	placeX = runHook('horizontalPlacement',FCHAIN,iwidth,winoffset,widthFix);

	// VERTICAL PLACEMENT, re-arranged to work in Safari
	if (o3_frame.innerHeight) {
		iheight=o3_frame.innerHeight;
	} else if (eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientHeight=='number'")&&eval('o3_frame.'+docRoot+'.clientHeight')) { 
		iheight=eval('o3_frame.'+docRoot+'.clientHeight');
	}			

	// Vertical scroll offset
	scrolloffset=(olIe4) ? eval('o3_frame.'+docRoot+'.scrollTop') : o3_frame.pageYOffset;
	placeY = runHook('verticalPlacement',FCHAIN,iheight,scrolloffset);

	// Actually move the object.
	repositionTo(over, placeX, placeY);
}

// Moves the layer
function olMouseMove(e) {
	var e = (e) ? e : event;

	if (e.pageX) {
		o3_x = e.pageX;
		o3_y = e.pageY;
	} else if (e.clientX) {
		o3_x = eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft');
		o3_y = eval('e.clientY+o3_frame.'+docRoot+'.scrollTop');
	}
	
	if (o3_allowmove == 1) runHook("placeLayer", FREPLACE);

	// MouseOut handler
	if (hoveringSwitch && !olNs4 && runHook("cursorOff", FREPLACE)) {
		(olHideDelay ? hideDelay(olHideDelay) : cClick());
		hoveringSwitch = !hoveringSwitch;
	}
}

// Fake function for 3.0 users.
function no_overlib() { return ver3fix; }

// Capture the mouse and chain other scripts.
function olMouseCapture() {
	capExtent = document;
	var fN, str = '', l, k, f, wMv, sS, mseHandler = olMouseMove;
	var re = /function[ ]*(\w*)\(/;
	
	wMv = (!olIe4 && window.onmousemove);
	if (document.onmousemove || wMv) {
		if (wMv) capExtent = window;
		f = capExtent.onmousemove.toString();
		fN = f.match(re);
		if (fN == null) {
			str = f+'(e); ';
		} else if (fN[1] == 'anonymous' || fN[1] == 'olMouseMove' || (wMv && fN[1] == 'onmousemove')) {
			if (!olOp && wMv) {
				l = f.indexOf('{')+1;
				k = f.lastIndexOf('}');
				sS = f.substring(l,k);
				if ((l = sS.indexOf('(')) != -1) {
					sS = sS.substring(0,l).replace(/^\s+/,'').replace(/\s+$/,'');
					if (eval("typeof " + sS + " == 'undefined'")) window.onmousemove = null;
					else str = sS + '(e);';
				}
			}
			if (!str) {
				olCheckMouseCapture = false;
				return;
			}
		} else {
			if (fN[1]) str = fN[1]+'(e); ';
			else {
				l = f.indexOf('{')+1;
				k = f.lastIndexOf('}');
				str = f.substring(l,k) + '\n';
			}
		}
		str += 'olMouseMove(e); ';
		mseHandler = new Function('e', str);
	}

	capExtent.onmousemove = mseHandler;
	if (olNs4) capExtent.captureEvents(Event.MOUSEMOVE);
}

////////
// PARSING FUNCTIONS
////////

// Does the actual command parsing.
function parseTokens(pf, ar) {
	// What the next argument is expected to be.
	var v, mode=-1, par = (pf != 'ol_');	
	var fnMark = (par && !ar.length ? 1 : 0);

	for (i = 0; i < ar.length; i++) {
		if (mode < 0) {
			// Arg is maintext,unless its a number between pmStart and pmUpper
			// then its a command.
			if (typeof ar[i] == 'number' && ar[i] > pmStart && ar[i] < pmUpper) {
				fnMark = (par ? 1 : 0);
				i--;   // backup one so that the next block can parse it
			} else {
				switch(pf) {
					case 'ol_':
						ol_text = ar[i].toString();
						break;
					default:
						o3_text=ar[i].toString();  
				}
			}
			mode = 0;
		} else {
			// Note: NS4 doesn't like switch cases with vars.
			if (ar[i] >= pmCount || ar[i]==DONOTHING) { continue; }
			if (ar[i]==INARRAY) { fnMark = 0; eval(pf+'text=ol_texts['+ar[++i]+'].toString()'); continue; }
			if (ar[i]==CAPARRAY) { eval(pf+'cap=ol_caps['+ar[++i]+'].toString()'); continue; }
			if (ar[i]==STICKY) { if (pf!='ol_') eval(pf+'sticky=1'); continue; }
			if (ar[i]==BACKGROUND) { eval(pf+'background="'+ar[++i]+'"'); continue; }
			if (ar[i]==NOCLOSE) { if (pf!='ol_') opt_NOCLOSE(); continue; }
			if (ar[i]==CAPTION) { eval(pf+"cap='"+escSglQuote(ar[++i])+"'"); continue; }
			if (ar[i]==CENTER || ar[i]==LEFT || ar[i]==RIGHT) { eval(pf+'hpos='+ar[i]); if(pf!='ol_') olHautoFlag=1; continue; }
			if (ar[i]==OFFSETX) { eval(pf+'offsetx='+ar[++i]); continue; }
			if (ar[i]==OFFSETY) { eval(pf+'offsety='+ar[++i]); continue; }
			if (ar[i]==FGCOLOR) { eval(pf+'fgcolor="'+ar[++i]+'"'); continue; }
			if (ar[i]==BGCOLOR) { eval(pf+'bgcolor="'+ar[++i]+'"'); continue; }
			if (ar[i]==TEXTCOLOR) { eval(pf+'textcolor="'+ar[++i]+'"'); continue; }
			if (ar[i]==CAPCOLOR) { eval(pf+'capcolor="'+ar[++i]+'"'); continue; }
			if (ar[i]==CLOSECOLOR) { eval(pf+'closecolor="'+ar[++i]+'"'); continue; }
			if (ar[i]==WIDTH) { eval(pf+'width='+ar[++i]); continue; }
			if (ar[i]==BORDER) { eval(pf+'border='+ar[++i]); continue; }
			if (ar[i]==CELLPAD) { i=opt_MULTIPLEARGS(++i,ar,(pf+'cellpad')); continue; }
			if (ar[i]==STATUS) { eval(pf+"status='"+escSglQuote(ar[++i])+"'"); continue; }
			if (ar[i]==AUTOSTATUS) { eval(pf +'autostatus=('+pf+'autostatus == 1) ? 0 : 1'); continue; }
			if (ar[i]==AUTOSTATUSCAP) { eval(pf +'autostatus=('+pf+'autostatus == 2) ? 0 : 2'); continue; }
			if (ar[i]==HEIGHT) { eval(pf+'height='+pf+'aboveheight='+ar[++i]); continue; } // Same param again.
			if (ar[i]==CLOSETEXT) { eval(pf+"close='"+escSglQuote(ar[++i])+"'"); continue; }
			if (ar[i]==SNAPX) { eval(pf+'snapx='+ar[++i]); continue; }
			if (ar[i]==SNAPY) { eval(pf+'snapy='+ar[++i]); continue; }
			if (ar[i]==FIXX) { eval(pf+'fixx='+ar[++i]); continue; }
			if (ar[i]==FIXY) { eval(pf+'fixy='+ar[++i]); continue; }
			if (ar[i]==RELX) { eval(pf+'relx='+ar[++i]); continue; }
			if (ar[i]==RELY) { eval(pf+'rely='+ar[++i]); continue; }
			if (ar[i]==FGBACKGROUND) { eval(pf+'fgbackground="'+ar[++i]+'"'); continue; }
			if (ar[i]==BGBACKGROUND) { eval(pf+'bgbackground="'+ar[++i]+'"'); continue; }
			if (ar[i]==PADX) { eval(pf+'padxl='+ar[++i]); eval(pf+'padxr='+ar[++i]); continue; }
			if (ar[i]==PADY) { eval(pf+'padyt='+ar[++i]); eval(pf+'padyb='+ar[++i]); continue; }
			if (ar[i]==FULLHTML) { if (pf!='ol_') eval(pf+'fullhtml=1'); continue; }
			if (ar[i]==BELOW || ar[i]==ABOVE) { eval(pf+'vpos='+ar[i]); if (pf!='ol_') olVautoFlag=1; continue; }
			if (ar[i]==CAPICON) { eval(pf+'capicon="'+ar[++i]+'"'); continue; }
			if (ar[i]==TEXTFONT) { eval(pf+"textfont='"+escSglQuote(ar[++i])+"'"); continue; }
			if (ar[i]==CAPTIONFONT) { eval(pf+"captionfont='"+escSglQuote(ar[++i])+"'"); continue; }
			if (ar[i]==CLOSEFONT) { eval(pf+"closefont='"+escSglQuote(ar[++i])+"'"); continue; }
			if (ar[i]==TEXTSIZE) { eval(pf+'textsize="'+ar[++i]+'"'); continue; }
			if (ar[i]==CAPTIONSIZE) { eval(pf+'captionsize="'+ar[++i]+'"'); continue; }
			if (ar[i]==CLOSESIZE) { eval(pf+'closesize="'+ar[++i]+'"'); continue; }
			if (ar[i]==TIMEOUT) { eval(pf+'timeout='+ar[++i]); continue; }
			if (ar[i]==FUNCTION) { if (pf=='ol_') { if (typeof ar[i+1]!='number') { v=ar[++i]; ol_function=(typeof v=='function' ? v : null); }} else {fnMark = 0; v = null; if (typeof ar[i+1]!='number') v = ar[++i];  opt_FUNCTION(v); } continue; }
			if (ar[i]==DELAY) { eval(pf+'delay='+ar[++i]); continue; }
			if (ar[i]==HAUTO) { eval(pf+'hauto=('+pf+'hauto == 0) ? 1 : 0'); continue; }
			if (ar[i]==VAUTO) { eval(pf+'vauto=('+pf+'vauto == 0) ? 1 : 0'); continue; }
			if (ar[i]==CLOSECLICK) { eval(pf +'closeclick=('+pf+'closeclick == 0) ? 1 : 0'); continue; }
			if (ar[i]==WRAP) { eval(pf +'wrap=('+pf+'wrap == 0) ? 1 : 0'); continue; }
			if (ar[i]==FOLLOWMOUSE) { eval(pf +'followmouse=('+pf+'followmouse == 1) ? 0 : 1'); continue; }
			if (ar[i]==MOUSEOFF) { eval(pf +'mouseoff=('+pf+'mouseoff==0) ? 1 : 0'); v=ar[i+1]; if (pf != 'ol_' && eval(pf+'mouseoff') && typeof v == 'number' && (v < pmStart || v > pmUpper)) olHideDelay=ar[++i]; continue; }
			if (ar[i]==CLOSETITLE) { eval(pf+"closetitle='"+escSglQuote(ar[++i])+"'"); continue; }
			if (ar[i]==CSSOFF||ar[i]==CSSCLASS) { eval(pf+'css='+ar[i]); continue; }
			if (ar[i]==COMPATMODE) { eval(pf+'compatmode=('+pf+'compatmode==0) ? 1 : 0'); continue; }
			if (ar[i]==FGCLASS) { eval(pf+'fgclass="'+ar[++i]+'"'); continue; }
			if (ar[i]==BGCLASS) { eval(pf+'bgclass="'+ar[++i]+'"'); continue; }
			if (ar[i]==TEXTFONTCLASS) { eval(pf+'textfontclass="'+ar[++i]+'"'); continue; }
			if (ar[i]==CAPTIONFONTCLASS) { eval(pf+'captionfontclass="'+ar[++i]+'"'); continue; }
			if (ar[i]==CLOSEFONTCLASS) { eval(pf+'closefontclass="'+ar[++i]+'"'); continue; }
			i = parseCmdLine(pf, i, ar);
		}
	}

	if (fnMark && o3_function) o3_text = o3_function();
	
	if ((pf == 'o3_') && o3_wrap) {
		o3_width = 0;
		
		var tReg=/<.*\n*>/ig;
		if (!tReg.test(o3_text)) o3_text = o3_text.replace(/[ ]+/g, '&nbsp;');
		if (!tReg.test(o3_cap))o3_cap = o3_cap.replace(/[ ]+/g, '&nbsp;');
	}
	if ((pf == 'o3_') && o3_sticky) {
		if (!o3_close && (o3_frame != ol_frame)) o3_close = ol_close;
		if (o3_mouseoff && (o3_frame == ol_frame)) opt_NOCLOSE(' ');
	}
}


////////
// LAYER FUNCTIONS
////////

// Writes to a layer
function layerWrite(txt) {
	txt += "\n";
	if (olNs4) {
		var lyr = o3_frame.document.layers['overDiv'].document
		lyr.write(txt)
		lyr.close()
	} else if (typeof over.innerHTML != 'undefined') {
		if (olIe5 && isMac) over.innerHTML = '';
		over.innerHTML = txt;
	} else {
		range = o3_frame.document.createRange();
		range.setStartAfter(over);
		domfrag = range.createContextualFragment(txt);
		
		while (over.hasChildNodes()) {
			over.removeChild(over.lastChild);
		}
		
		over.appendChild(domfrag);
	}
}

// Make an object visible
function showObject(obj) {
	runHook("showObject", FBEFORE);

	var theObj=(olNs4 ? obj : obj.style);
	theObj.visibility = 'visible';

	runHook("showObject", FAFTER);
}

// Hides an object
function hideObject(obj) {
	runHook("hideObject", FBEFORE);

	var theObj=(olNs4 ? obj : obj.style);
	if (olNs6 && olShowId>0) { clearTimeout(olShowId); olShowId=0; }
	theObj.visibility = 'hidden';
	theObj.top = theObj.left = ((olIe4&&!olOp) ? 0 : -10000) + (!olNs4 ? 'px' : 0);

	if (o3_timerid > 0) clearTimeout(o3_timerid);
	if (o3_delayid > 0) clearTimeout(o3_delayid);

	o3_timerid = 0;
	o3_delayid = 0;
	self.status = "";

	if (obj.onmouseout || obj.onmouseover) {
		if (olNs4) obj.releaseEvents(Event.MOUSEOUT || Event.MOUSEOVER);
		obj.onmouseout = obj.onmouseover = null;
	}

	runHook("hideObject", FAFTER);
}

// Move a layer
function repositionTo(obj, xL, yL) {
	var theObj=(olNs4 ? obj : obj.style);
	theObj.left = xL + (!olNs4 ? 'px' : 0);
	theObj.top = yL + (!olNs4 ? 'px' : 0);
}

// Check position of cursor relative to overDiv DIVision; mouseOut function
function cursorOff() {
	var left = parseInt(over.style.left);
	var top = parseInt(over.style.top);
	var right = left + (over.offsetWidth >= parseInt(o3_width) ? over.offsetWidth : parseInt(o3_width));
	var bottom = top + (over.offsetHeight >= o3_aboveheight ? over.offsetHeight : o3_aboveheight);

	if (o3_x < left || o3_x > right || o3_y < top || o3_y > bottom) return true;

	return false;
}


////////
// COMMAND FUNCTIONS
////////

// Calls callme or the default function.
function opt_FUNCTION(callme) {
	o3_text = (callme ? (typeof callme=='string' ? (/.+\(.*\)/.test(callme) ? eval(callme) : callme) : callme()) : (o3_function ? o3_function() : 'No Function'));

	return 0;
}

// Handle hovering
function opt_NOCLOSE(unused) {
	if (!unused) o3_close = "";

	if (olNs4) {
		over.captureEvents(Event.MOUSEOUT || Event.MOUSEOVER);
		over.onmouseover = function () { if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid = 0; } }
		over.onmouseout = function (e) { if (olHideDelay) hideDelay(olHideDelay); else cClick(e); }
	} else {
		over.onmouseover = function () {hoveringSwitch = true; if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid =0; } }
	}

	return 0;
}

// Function to scan command line arguments for multiples
function opt_MULTIPLEARGS(i, args, parameter) {
  var k=i, re, pV, str='';

  for(k=i; k<args.length; k++) {
		if(typeof args[k] == 'number' && args[k]>pmStart) break;
		str += args[k] + ',';
	}
	if (str) str = str.substring(0,--str.length);

	k--;  // reduce by one so the for loop this is in works correctly
	pV=(olNs4 && /cellpad/i.test(parameter)) ? str.split(',')[0] : str;
	eval(parameter + '="' + pV + '"');

	return k;
}

// Remove &nbsp; in texts when done.
function nbspCleanup() {
	if (o3_wrap) {
		o3_text = o3_text.replace(/\&nbsp;/g, ' ');
		o3_cap = o3_cap.replace(/\&nbsp;/g, ' ');
	}
}

// Escape embedded single quotes in text strings
function escSglQuote(str) {
  return str.toString().replace(/'/g,"\\'");
}

// Onload handler for window onload event
function OLonLoad_handler(e) {
	var re = /\w+\(.*\)[;\s]+/g, olre = /overlib\(|nd\(|cClick\(/, fn, l, i;

	if(!olLoaded) olLoaded=1;

  // Remove it for Gecko based browsers
	if(window.removeEventListener && e.eventPhase == 3) window.removeEventListener("load",OLonLoad_handler,false);
	else if(window.detachEvent) { // and for IE and Opera 4.x but execute calls to overlib, nd, or cClick()
		window.detachEvent("onload",OLonLoad_handler);
		var fN = document.body.getAttribute('onload');
		if (fN) {
			fN=fN.toString().match(re);
			if (fN && fN.length) {
				for (i=0; i<fN.length; i++) {
					if (/anonymous/.test(fN[i])) continue;
					while((l=fN[i].search(/\)[;\s]+/)) != -1) {
						fn=fN[i].substring(0,l+1);
						fN[i] = fN[i].substring(l+2);
						if (olre.test(fn)) eval(fn);
					}
				}
			}
		}
	}
}

// Wraps strings in Layer Generation Functions with the correct tags
//    endWrap true(if end tag) or false if start tag
//    fontSizeStr - font size string such as '1' or '10px'
//    whichString is being wrapped -- 'text', 'caption', or 'close'
function wrapStr(endWrap,fontSizeStr,whichString) {
	var fontStr, fontColor, isClose=((whichString=='close') ? 1 : 0), hasDims=/[%\-a-z]+$/.test(fontSizeStr);
	fontSizeStr = (olNs4) ? (!hasDims ? fontSizeStr : '1') : fontSizeStr;
	if (endWrap) return (hasDims&&!olNs4) ? (isClose ? '</span>' : '</div>') : '</font>';
	else {
		fontStr='o3_'+whichString+'font';
		fontColor='o3_'+((whichString=='caption')? 'cap' : whichString)+'color';
		return (hasDims&&!olNs4) ? (isClose ? '<span style="font-family: '+quoteMultiNameFonts(eval(fontStr))+'; color: '+eval(fontColor)+'; font-size: '+fontSizeStr+';">' : '<div style="font-family: '+quoteMultiNameFonts(eval(fontStr))+'; color: '+eval(fontColor)+'; font-size: '+fontSizeStr+';">') : '<font face="'+eval(fontStr)+'" color="'+eval(fontColor)+'" size="'+(parseInt(fontSizeStr)>7 ? '7' : fontSizeStr)+'">';
	}
}

// Quotes Multi word font names; needed for CSS Standards adherence in font-family
function quoteMultiNameFonts(theFont) {
	var v, pM=theFont.split(',');
	for (var i=0; i<pM.length; i++) {
		v=pM[i];
		v=v.replace(/^\s+/,'').replace(/\s+$/,'');
		if(/\s/.test(v) && !/['"]/.test(v)) {
			v="\'"+v+"\'";
			pM[i]=v;
		}
	}
	return pM.join();
}

// dummy function which will be overridden 
function isExclusive(args) {
	return false;
}

// function will delay close by time milliseconds
function hideDelay(time) {
	if (time&&!o3_delay) {
		if (o3_timerid > 0) clearTimeout(o3_timerid);

		o3_timerid=setTimeout("cClick()",(o3_timeout=time));
	}
}

// Was originally in the placeLayer() routine; separated out for future ease
function horizontalPlacement(browserWidth, horizontalScrollAmount, widthFix) {
	var placeX, iwidth=browserWidth, winoffset=horizontalScrollAmount;
	var parsedWidth = parseInt(o3_width);

	if (o3_fixx > -1 || o3_relx != null) {
		// Fixed position
		placeX=(o3_relx != null ? ( o3_relx < 0 ? winoffset +o3_relx+ iwidth - parsedWidth - widthFix : winoffset+o3_relx) : o3_fixx);
	} else {  
		// If HAUTO, decide what to use.
		if (o3_hauto == 1) {
			if ((o3_x - winoffset) > (iwidth / 2)) {
				o3_hpos = LEFT;
			} else {
				o3_hpos = RIGHT;
			}
		}  		

		// From mouse
		if (o3_hpos == CENTER) { // Center
			placeX = o3_x+o3_offsetx-(parsedWidth/2);

			if (placeX < winoffset) placeX = winoffset;
		}

		if (o3_hpos == RIGHT) { // Right
			placeX = o3_x+o3_offsetx;

			if ((placeX+parsedWidth) > (winoffset+iwidth - widthFix)) {
				placeX = iwidth+winoffset - parsedWidth - widthFix;
				if (placeX < 0) placeX = 0;
			}
		}
		if (o3_hpos == LEFT) { // Left
			placeX = o3_x-o3_offsetx-parsedWidth;
			if (placeX < winoffset) placeX = winoffset;
		}  	

		// Snapping!
		if (o3_snapx > 1) {
			var snapping = placeX % o3_snapx;

			if (o3_hpos == LEFT) {
				placeX = placeX - (o3_snapx+snapping);
			} else {
				// CENTER and RIGHT
				placeX = placeX+(o3_snapx - snapping);
			}

			if (placeX < winoffset) placeX = winoffset;
		}
	}	

	return placeX;
}

// was originally in the placeLayer() routine; separated out for future ease
function verticalPlacement(browserHeight,verticalScrollAmount) {
	var placeY, iheight=browserHeight, scrolloffset=verticalScrollAmount;
	var parsedHeight=(o3_aboveheight ? parseInt(o3_aboveheight) : (olNs4 ? over.clip.height : over.offsetHeight));

	if (o3_fixy > -1 || o3_rely != null) {
		// Fixed position
		placeY=(o3_rely != null ? (o3_rely < 0 ? scrolloffset+o3_rely+iheight - parsedHeight : scrolloffset+o3_rely) : o3_fixy);
	} else {
		// If VAUTO, decide what to use.
		if (o3_vauto == 1) {
			if ((o3_y - scrolloffset) > (iheight / 2) && o3_vpos == BELOW && (o3_y + parsedHeight + o3_offsety - (scrolloffset + iheight) > 0)) {
				o3_vpos = ABOVE;
			} else if (o3_vpos == ABOVE && (o3_y - (parsedHeight + o3_offsety) - scrolloffset < 0)) {
				o3_vpos = BELOW;
			}
		}

		// From mouse
		if (o3_vpos == ABOVE) {
			if (o3_aboveheight == 0) o3_aboveheight = parsedHeight; 

			placeY = o3_y - (o3_aboveheight+o3_offsety);
			if (placeY < scrolloffset) placeY = scrolloffset;
		} else {
			// BELOW
			placeY = o3_y+o3_offsety;
		} 

		// Snapping!
		if (o3_snapy > 1) {
			var snapping = placeY % o3_snapy;  			

			if (o3_aboveheight > 0 && o3_vpos == ABOVE) {
				placeY = placeY - (o3_snapy+snapping);
			} else {
				placeY = placeY+(o3_snapy - snapping);
			} 			

			if (placeY < scrolloffset) placeY = scrolloffset;
		}
	}

	return placeY;
}

// checks positioning flags
function checkPositionFlags() {
	if (olHautoFlag) olHautoFlag = o3_hauto=0;
	if (olVautoFlag) olVautoFlag = o3_vauto=0;
	return true;
}

// get Browser window width
function windowWidth() {
	var w;
	if (o3_frame.innerWidth) w=o3_frame.innerWidth;
	else if (eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientWidth=='number'")&&eval('o3_frame.'+docRoot+'.clientWidth')) 
		w=eval('o3_frame.'+docRoot+'.clientWidth');
	return w;			
}

// create the div container for popup content if it doesn't exist
function createDivContainer(id,frm,zValue) {

    try{
	id = (id || 'overDiv'), frm = (frm || o3_frame), zValue = (zValue || 1000);
	var objRef, divContainer = layerReference(id);

	if (divContainer == null) {
		if (olNs4) {
			divContainer = frm.document.layers[id] = new Layer(window.innerWidth, frm);
			objRef = divContainer;
		} else {
			var body = (olIe4 ? frm.document.all.tags('BODY')[0] : frm.document.getElementsByTagName("BODY")[0]);
			if (olIe4&&!document.getElementById) {
				body.insertAdjacentHTML("beforeEnd",'<div id="'+id+'"></div>');
				divContainer=layerReference(id);
			} else {
				divContainer = frm.document.createElement("DIV");
				divContainer.id = id;
				body.appendChild(divContainer);
			}
			objRef = divContainer.style;
		}

		with (objRef) {
			position = 'absolute';
			visibility = 'hidden';
			top = left = -10000 + (!olNs4) ? 'px' : 0;
			zIndex = zValue;
		}
	}
     }catch(ex){
        return createDivContainer(id,frm,zValue);
     }
     
     return divContainer;
}

// get reference to a layer with ID=id
function layerReference(id) {
	return (olNs4 ? o3_frame.document.layers[id] : (document.all ? o3_frame.document.all[id] : o3_frame.document.getElementById(id)));
}
////////
//  PLUGIN ACTIVATION FUNCTIONS
////////

// Runs plugin functions to set runtime variables.
function setRunTimeVariables(){
	if (typeof runTime != 'undefined' && runTime.length) {
		for (var k = 0; k < runTime.length; k++) {
			runTime[k]();
		}
	}
}

// Runs plugin functions to parse commands.
function parseCmdLine(pf, i, args) {
	if (typeof cmdLine != 'undefined' && cmdLine.length) { 
		for (var k = 0; k < cmdLine.length; k++) { 
			var j = cmdLine[k](pf, i, args);
			if (j >- 1) {
				i = j;
				break;
			}
		}
	}

	return i;
}

// Runs plugin functions to do things after parse.
function postParseChecks(){
	if (typeof postParse != 'undefined' && postParse.length) {
		for (var k = 0; k < postParse.length; k++) {
			if (postParse[k]()) continue;
			return false;  // end now since have an error
		}
	}
	return true;
}


////////
//  PLUGIN REGISTRATION FUNCTIONS
////////

// Registers commands and creates constants.
function registerCommands(cmdStr) {
	if (typeof cmdStr!='string') return;

	var pM = cmdStr.split(',');
	pms = pms.concat(pM);

	for (var i = 0; i< pM.length; i++) {
		eval(pM[i].toUpperCase()+'='+pmCount++);
	}
}

// Registers no-parameter commands
function registerNoParameterCommands(cmdStr) {
	if (!cmdStr && typeof cmdStr!='string') return;
	pmt=(!pmt) ? cmdStr : pmt + ',' + cmdStr;
}

// Register a function to hook at a certain point.
function registerHook(fnHookTo, fnRef, hookType, optPm) {
	var hookPt, last = typeof optPm;
	
	if (fnHookTo == 'plgIn'||fnHookTo == 'postParse') return;
	if (typeof hookPts == 'undefined') hookPts = new Array();
	if (typeof hookPts[fnHookTo] == 'undefined') hookPts[fnHookTo] = new FunctionReference();

	hookPt = hookPts[fnHookTo];

	if (hookType != null) {
		if (hookType == FREPLACE) {
			hookPt.ovload = fnRef;  // replace normal overlib routine
			if (fnHookTo.indexOf('ol_content_') > -1) hookPt.alt[pms[CSSOFF-1-pmStart]]=fnRef; 

		} else if (hookType == FBEFORE || hookType == FAFTER) {
			var hookPt=(hookType == 1 ? hookPt.before : hookPt.after);

			if (typeof fnRef == 'object') {
				hookPt = hookPt.concat(fnRef);
			} else {
				hookPt[hookPt.length++] = fnRef;
			}

			if (optPm) hookPt = reOrder(hookPt, fnRef, optPm);

		} else if (hookType == FALTERNATE) {
			if (last=='number') hookPt.alt[pms[optPm-1-pmStart]] = fnRef;
		} else if (hookType == FCHAIN) {
			hookPt = hookPt.chain; 
			if (typeof fnRef=='object') hookPt=hookPt.concat(fnRef); // add other functions 
			else hookPt[hookPt.length++]=fnRef;
		}

		return;
	}
}

// Register a function that will set runtime variables.
function registerRunTimeFunction(fn) {
	if (isFunction(fn)) {
		if (typeof runTime == 'undefined') runTime = new Array();
		if (typeof fn == 'object') {
			runTime = runTime.concat(fn);
		} else {
			runTime[runTime.length++] = fn;
		}
	}
}

// Register a function that will handle command parsing.
function registerCmdLineFunction(fn){
	if (isFunction(fn)) {
		if (typeof cmdLine == 'undefined') cmdLine = new Array();
		if (typeof fn == 'object') {
			cmdLine = cmdLine.concat(fn);
		} else {
			cmdLine[cmdLine.length++] = fn;
		}
	}
}

// Register a function that does things after command parsing. 
function registerPostParseFunction(fn){
	if (isFunction(fn)) {
		if (typeof postParse == 'undefined') postParse = new Array();
		if (typeof fn == 'object') {
			postParse = postParse.concat(fn);
		} else {
			postParse[postParse.length++] = fn;
		}
	}
}

////////
//  PLUGIN REGISTRATION FUNCTIONS
////////

// Runs any hooks registered.
function runHook(fnHookTo, hookType) {
	var l = hookPts[fnHookTo], k, rtnVal, optPm, arS, ar = runHook.arguments;

	if (hookType == FREPLACE) {
		arS = argToString(ar, 2);

		if (typeof l == 'undefined' || !(l = l.ovload)) return eval(fnHookTo+'('+arS+')');
		else return eval('l('+arS+')');

	} else if (hookType == FBEFORE || hookType == FAFTER) {
		if (typeof l == 'undefined') return;
		l=(hookType == 1 ? l.before : l.after);

		if (!l.length) return;

		arS = argToString(ar, 2);
		for (var k = 0; k < l.length; k++) eval('l[k]('+arS+')'); 

	} else if (hookType == FALTERNATE) {
		optPm = ar[2];
		arS = argToString(ar, 3);

		if (typeof l == 'undefined' || (l = l.alt[pms[optPm-1-pmStart]]) == 'undefined') {
			return eval(fnHookTo+'('+arS+')');
		} else {
			return eval('l('+arS+')');
		}
	} else if (hookType == FCHAIN) {
		arS=argToString(ar,2);
		l=l.chain;

		for (k=l.length; k > 0; k--) if((rtnVal=eval('l[k-1]('+arS+')'))!=void(0)) return rtnVal;
	}
}

////////
//  UTILITY FUNCTIONS
////////

// Checks if something is a function.
function isFunction(fnRef) {
	var rtn = true;

	if (typeof fnRef == 'object') {
		for (var i = 0; i < fnRef.length; i++) {
			if (typeof fnRef[i]=='function') continue;
			rtn = false;
			break;
		}
	} else if (typeof fnRef != 'function') {
		rtn = false;
	}
	
	return rtn;
}

// Converts an array into an argument string for use in eval.
function argToString(array, strtInd, argName) {
	var jS = strtInd, aS = '', ar = array;
	argName=(argName ? argName : 'ar');
	
	if (ar.length > jS) {
		for (var k = jS; k < ar.length; k++) aS += argName+'['+k+'], ';
		aS = aS.substring(0, aS.length-2);
	}
	
	return aS;
}

// Places a hook in the correct position in a hook point.
function reOrder(hookPt, fnRef, order) {
	if (!order || typeof order == 'undefined' || typeof order == 'number') return;
	
	var newPt = new Array(), match;

	if (typeof order=='function') {
		if (typeof fnRef=='object') {
			newPt = newPt.concat(fnRef);
		} else {
			newPt[newPt.length++]=fnRef;
		}
		
		for (var i = 0; i < hookPt.length; i++) {
			match = false;
			if (typeof fnRef == 'function' && hookPt[i] == fnRef) {
				continue;
			} else {
				for(var j = 0; j < fnRef.length; j++) if (hookPt[i] == fnRef[j]) {
					match = true;
					break;
				}
			}
			if (!match) newPt[newPt.length++] = hookPt[i];
		}

		newPt[newPt.length++] = order;

	} else if (typeof order == 'object') {
		if (typeof fnRef == 'object') {
			newPt = newPt.concat(fnRef);
		} else {
			newPt[newPt.length++] = fnRef;
		}
		
		for (var j = 0; j < hookPt.length; j++) {
			match = false;
			if (typeof fnRef == 'function' && hookPt[j] == fnRef) {
				continue;
			} else {
				for (var i = 0; i < fnRef.length; i++) if (hookPt[j] == fnRef[i]) {
					match = true;
					break;
				}
			}
			if (!match) newPt[newPt.length++]=hookPt[j];
		}

		for (i = 0; i < newPt.length; i++) hookPt[i] = newPt[i];
		newPt.length = 0;
		
		for (var j = 0; j < hookPt.length; j++) {
			match = false;
			for (var i = 0; i < order.length; i++) {
				if (hookPt[j] == order[i]) {
					match = true;
					break;
				}
			}
			if (!match) newPt[newPt.length++] = hookPt[j];
		}
		newPt = newPt.concat(order);
	}

	for(i = 0; i < newPt.length; i++) hookPt[i] = newPt[i];

	return hookPt;
}

////////
// OBJECT CONSTRUCTORS
////////

// Object for handling hooks.
function FunctionReference() {
	this.ovload = null;
	this.before = new Array();
	this.after = new Array();
	this.alt = new Array();
	this.chain = new Array();
}

// Object for simple access to the overLIB version used.
// Examples: simpleversion:351 major:3 minor:5 revision:1
function Info(version, prerelease) {
	this.version = version;
	this.prerelease = prerelease;

	this.simpleversion = Math.round(this.version*100);
	this.major = parseInt(this.simpleversion / 100);
	this.minor = parseInt(this.simpleversion / 10) - this.major * 10;
	this.revision = parseInt(this.simpleversion) - this.major * 100 - this.minor * 10;
	this.meets = meets;
}

// checks for Core Version required
function meets(reqdVersion) {
	return (!reqdVersion) ? false : this.simpleversion >= Math.round(100*parseFloat(reqdVersion));
}


////////
// STANDARD REGISTRATIONS
////////
registerHook("ol_content_simple", ol_content_simple, FALTERNATE, CSSOFF);
registerHook("ol_content_caption", ol_content_caption, FALTERNATE, CSSOFF);
registerHook("ol_content_background", ol_content_background, FALTERNATE, CSSOFF);
registerHook("ol_content_simple", ol_content_simple, FALTERNATE, CSSCLASS);
registerHook("ol_content_caption", ol_content_caption, FALTERNATE, CSSCLASS);
registerHook("ol_content_background", ol_content_background, FALTERNATE, CSSCLASS);
registerPostParseFunction(checkPositionFlags);
registerHook("hideObject", nbspCleanup, FAFTER);
registerHook("horizontalPlacement", horizontalPlacement, FCHAIN);
registerHook("verticalPlacement", verticalPlacement, FCHAIN);
if (olNs4||(olIe5&&isMac)||olKq) olLoaded=1;
registerNoParameterCommands('sticky,autostatus,autostatuscap,fullhtml,hauto,vauto,closeclick,wrap,followmouse,mouseoff,compatmode');
function CountriesProvincesSelect(id1, id2, id3) {
    this._countriesSelectId = id1;
    this._provincesSelectId = id2;
    this._provinceLabelId = id3;
    
    this._def_country = -1;
    this._def_province = -1;
}

CountriesProvincesSelect.prototype.setDefault = function(country, province) {
    this._def_country = country;
    this._def_province = province;
}

CountriesProvincesSelect.prototype._countriesSelectId;
CountriesProvincesSelect.prototype._provincesSelectId;
CountriesProvincesSelect.prototype._provinceLabelId;
CountriesProvincesSelect.prototype._doc;

CountriesProvincesSelect.prototype._def_country;
CountriesProvincesSelect.prototype._def_province;

CountriesProvincesSelect.prototype.loadCountries = function() {
    var countriesSelectId = this._countriesSelectId;
    var provincesSelectId = this._provincesSelectId;
    var provinceLabelId = this._provinceLabelId;
    defCountry = this._def_country;
    defProvince = this._def_province;
    
    document.getElementById(countriesSelectId).onchange = function() {
        GetProvincesByCountry();
    }
    
    var GetProvincesByCountry = function() {
        var sel = document.getElementById(countriesSelectId);
        var pays = sel.options[sel.selectedIndex].value;

        if(pays == 2) {
            document.getElementById(provinceLabelId).innerHTML = "&Eacute;tat";
        }
        else {
            document.getElementById(provinceLabelId).innerHTML = "Province";
        }

        var doc = new XML(); 
        doc.addListener(OnProvincesLoad);
        doc._method = "POST";
        doc.setAttribute("pays", pays);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.sendAndLoad("actions-getProv.do");
    }

    var OnCountriesLoad = function(response) {

        var doc = response.responseXML.documentElement;
        var liste = document.getElementById(countriesSelectId);
        removeAllOptions(liste);

        var cats = getItems(doc, "Country").items();
        var catsL = cats.length;

        var selection = -1;
        for(var i1=0; i1<catsL; i1++){
            var id = cats[i1].getAttribute("id");
            var name = cats[i1].getAttribute("name");
            addOption(liste, name, id, false);
            
            if(id == defCountry) {
                selection = i1;
            }
        }     

        if(selection != -1) {
            liste.selectedIndex = selection;
        }

        GetProvincesByCountry();
    }
    
    var OnProvincesLoad = function(response) {
        var doc = response.responseXML.documentElement;
        var liste = document.getElementById(provincesSelectId);
        removeAllOptions(liste);

        var cats = getItems(doc, "Province").items();
        var catsL = cats.length;
        
        var selection = -1;
        for(var i1=0; i1<catsL; i1++){
            var id = cats[i1].getAttribute("id");
            var name = cats[i1].getAttribute("name");
            addOption(liste, name, id, false);
            
            if(id == defProvince) {
                selection = i1;
            }
        }
        
        if(selection != -1) {
            liste.selectedIndex = selection;
        }
    }
        
    this._doc = new XML();    
    this._doc.addListener(OnCountriesLoad);
    this._doc._method = "POST";
    this._doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    this._doc.sendAndLoad("actions-getCountries.do"); 
}
var doc = null;

var __LIST=function(els,root){this.els=els;};var getItems=function(el,name,recurse,ref){
    var rs=(ref)?ref:[];var ns=(recurse)?el.getElementsByTagName(name):el.childNodes;var i=-1;var l=ns.length;
    while(++i<l){var n=ns[i];if(n.nodeName==name)rs.push(n);}return new __LIST(rs);
};var LO=__LIST.prototype;LO.items=function(){return this.els;};
LO.getItems=function(name,recurse){var rs=[];var els=this.els;var i=-1;var l=els.length;while(++i<l)
{getItems(els[i],name,recurse,rs);}return new __LIST(rs, this);};



CategoryManager = {
    selectedResult:-1,
    selectedCategory:-1,
    selectedSubCategories:[],
    selectedSubCategoriesName:[],
    selectedSubCategoriesMap:{},
    hasSubCategories:false,
    
    selectSection: function(categoryId) {
        if(categoryId == -1)
            return;
        
        try {
            selectedCategory = categoryId;        
            doc = new XML();
            
            doc.setAttribute("rootCategoryId", categoryId);
            doc.setAttribute("nocache", Math.round(Math.random()*10000));
            doc.addListener(CategoryManager.onCategoryListLoaded);
            doc.sendAndLoad("actions-getGuideSubCategory.do");
        } catch(e) {
            alert(e);
        }
    },    
    onCategoryListLoaded: function(response) {
        try {
            var doc = response.responseXML.documentElement;
            var divs = getItems(doc, "Category").items();
            
            var categoriesList = document.getElementById("categoriesList");
            while(categoriesList.hasChildNodes())
                categoriesList.removeChild(categoriesList.firstChild);
    
            
            var divsL = divs.length;
            for(var i1=0; i1<divsL; i1++){
                var cat = divs[i1];
                var option = document.createElement("option");
                option.setAttribute("value", cat.getAttribute("id"));
                option.innerHTML = cat.getAttribute("name");
                categoriesList.appendChild(option);
            }
        } catch(e) {
            alert(e);
        }
    },
    
    selectCategory: function(categoryId) {
        try {                         
            document.getElementById("categoriesList2").style.visibility="hidden";
            document.getElementById("subCategoriesList").style.visibility="hidden";
            document.getElementById("subCatTitle").style.visibility="hidden";
            document.getElementById("subSubCatTitle").style.visibility="hidden";
            document.getElementById("categoriesList2").style.display="none";
            document.getElementById("subCategoriesList").style.display="none";
            document.getElementById("subCatTitle").style.display="none";
            document.getElementById("subSubCatTitle").style.display="none";
            
            document.getElementById("namesubcathidden").value = "";            
            document.getElementById("idsubcathidden").value = "";  
            document.getElementById('subCategoriesList').innerHTML = "";            
            selectedCategory = categoryId;                 
            doc = new XML();
            doc.setAttribute("rootCategoryId", categoryId);
            doc.setAttribute("nocache", Math.round(Math.random()*10000));
            doc.addListener(CategoryManager.onSubCategoryListLoaded);
            doc.sendAndLoad("actions-getGuideSubCategory.do");            
        } catch(e) {
            alert(e);
        }
    },
    onSubCategoryListLoaded:function(response) {
        try {            
            var doc = response.responseXML.documentElement;                       
            var divs = getItems(doc, "Category").items();            
            var divsL = divs.length;     

            

            if (divsL.length > 1 && divs[1].getAttribute("count") != 0) {
                var categoriesList = document.getElementById("categoriesList2");
              document.getElementById("categoriesList2").style.visibility="visible";
              document.getElementById("subCatTitle").style.visibility="visible";
              document.getElementById("categoriesList2").style.display="block";
              document.getElementById("subCatTitle").style.display="block";
            }
            else {
                var categoriesList = document.getElementById("subCategoriesList");
                document.getElementById("subCategoriesList").style.visibility="visible";
                document.getElementById("subSubCatTitle").style.visibility="visible";
                document.getElementById("subCategoriesList").style.display="block";
                document.getElementById("subSubCatTitle").style.display="block";
            }
            
            while(categoriesList.hasChildNodes()){
                categoriesList.removeChild(categoriesList.firstChild);
            }      

            if (divsL.length <= 0) {
                return;
            }
            
            
            var options;
   
            
            for(var i1=1; i1<divsL; i1++){
                
                var cat = divs[i1];                                
                if(cat.getAttribute("count") == '0'){
                    options = document.createElement("option");
                    options.setAttribute("value" , cat.getAttribute("id"));
                    options.appendChild(document.createTextNode(cat.getAttribute("name")))
                    categoriesList.appendChild(options);      
                }
                else{    
                    options = document.createElement("option");
                    options.setAttribute("value" , cat.getAttribute("id"));
                    options.appendChild(document.createTextNode(cat.getAttribute("name")));
                    categoriesList.appendChild(options);   
                }
                
            }
            
        } catch(e) {
            alert(e);
        }
    },
    
    selectCategory2: function(categoryId) {
        try {                                     
            doc = new XML();
            doc.setAttribute("rootCategoryId", categoryId);
            doc.setAttribute("nocache", Math.round(Math.random()*10000));
            doc.addListener(CategoryManager.onSubCategoryListLoaded2);
            doc.sendAndLoad("actions-getGuideSubCategory.do");
        } catch(e) {
            alert(e.name+" "+e.message);
        }
    },

    onSubCategoryListLoaded2:function(response) {
        try {
            var doc = response.responseXML.documentElement;
            var buffer = "";
            var divs = getItems(doc, "Category").items();
            var divsL = divs.length;
            var categoriesList = document.getElementById("subCategoriesList");
            while(categoriesList.hasChildNodes())
                categoriesList.removeChild(categoriesList.firstChild);
            for(var i1=1; i1<divsL; i1++){
                var div = divs[i1];
                options = document.createElement("option");
                options.setAttribute("value" , div.getAttribute("id"));
                options.appendChild(document.createTextNode(div.getAttribute("name")))
                document.getElementById("subCategoriesList").appendChild(options);
                /*buffer += "<option value=\"";
                buffer += div.getAttribute("id");
                buffer += "\" ";
                buffer += ">";
                buffer += div.getAttribute("name");
                buffer += "</option>";*/
               
            }	
            //document.getElementById("subCategoriesList").innerHTML = buffer;
            document.getElementById("subCategoriesList").style.visibility="visible";
            document.getElementById("subSubCatTitle").style.visibility="visible";
            document.getElementById("subCategoriesList").style.display="block";
            document.getElementById("subSubCatTitle").style.display="block";
        } catch(e) {
            alert(e);
        }
    },
    
    selectSubCategory:function(chxBox, name){
        try {
            var newId = chxBox.value;

                var splitter = " -> ";                
                var categoriesList = document.getElementById("categoriesList");
                var categoriesList2 = document.getElementById("categoriesList2");
                var fullName = categoriesList.options[categoriesList.selectedIndex].text + splitter;        
                var parentCatName = document.getElementById("namesubcathidden").value;
                var catSelected = false;
                if( parentCatName != ""){
                    fullName +=  parentCatName + splitter;
                }
                fullName += name;                                
                for (var i=0; i<CategoryManager.selectedSubCategories.length; i++) {
                    if (CategoryManager.selectedSubCategories[i] == newId) {
                        catSelected = true;
                    }
                }
                if (catSelected == false) {
                    CategoryManager.selectedSubCategories.push(newId);
                    CategoryManager.selectedSubCategoriesName.push(fullName);
                    CategoryManager.selectedSubCategoriesMap[newId] = true;
                }
                /*else {
                var divs = CategoryManager.selectedSubCategories;
                for(var i=0; i<divs.length; i++){
                    if(divs[i] == newId){
                        divs.splice(i,1);
                        CategoryManager.selectedSubCategoriesName.splice(i,1);
                        break;
                    }
                }
                delete CategoryManager.selectedSubCategoriesMap[newId];
            }*/
            
            CategoryManager.updateSelectedSubCategoryUI();
        } catch(e) {
            alert(e);
        }
    },

    removeSubCategory:function() {
        try {
                CategoryManager.selectedSubCategories.splice(CategoryManager.selectedResult,1);
                CategoryManager.selectedSubCategoriesName.splice(CategoryManager.selectedResult,1);
                delete CategoryManager.selectedSubCategoriesMap[CategoryManager.selectedResult];
                CategoryManager.updateSelectedSubCategoryUI();
            } catch(e) {
                alert(e);
            }
    },
    
    setCategories:function(divs, divNames) {
        try {
            for(var i=0; i<divs.length; i++){
                CategoryManager.selectedSubCategories.push(divs[i]);
                CategoryManager.selectedSubCategoriesName.push(divNames[i]);
                CategoryManager.selectedSubCategoriesMap[divs[i]] = true;
            }
            
            CategoryManager.updateSelectedSubCategoryUI();
        } catch(e) {
            alert(e);
        }
    },
    
    selectResult:function(e) {
        e = e || window.event;
        elem = (e.target) ? e.target : e.srcElement;

        CategoryManager.selectedResult = elem.style.zIndex;
        CategoryManager.updateSelectedSubCategoryUI();
    },
        
    updateSelectedSubCategoryUI:function() {
        try {
            var buffer = "";
            var divs = CategoryManager.selectedSubCategories;
            
            var targetDiv = document.getElementById("selectedSubCategoryList");
            
            
            while(targetDiv.hasChildNodes())
                targetDiv.removeChild(targetDiv.firstChild);
            
            targetDiv.innerHTML = '';
            
            var contain = '';
            var newdiv = '';
            
            if (CategoryManager.selectedResult == -1) {
                    document.getElementById('deleteButton').style.visibility = 'hidden';
                    document.getElementById('upButton').style.visibility = 'hidden';
                    document.getElementById('downButton').style.visibility = 'hidden';
                }
            else {
                    document.getElementById('deleteButton').style.visibility = 'visible';
                    document.getElementById('upButton').style.visibility = 'visible';
                    document.getElementById('downButton').style.visibility = 'visible';
                }
            for(var i=0; i<divs.length; i++) {
                contain = CategoryManager.selectedSubCategoriesName[i];
                
                newdiv = document.createElement("div");  
                
                newdiv.style.width = '100%';
                newdiv.style.fontWeight= 'bold';
                newdiv.style.cursor = 'pointer';                
                newdiv.onclick = CategoryManager.selectResult;
                
                if(i == CategoryManager.selectedResult) {
                    newdiv.style.backgroundColor = '#cbe0eb';
                    newdiv.style.zIndex = -1;
                }
                else {                    
                    newdiv.style.zIndex = i;
                }
                
                newdiv.innerHTML = contain;
                targetDiv.appendChild(newdiv);    
            }
            
            document.getElementById("categories").value = CategoryManager.selectedSubCategories.join(",");                
            
        } catch(e) {
            alert(e);
        }
    },
    
    simulateSelectWithDiv:function(divOn, categoryId, categoryName){
        
        divOn.style.backgroundColor = '#09236a'; 
        divOn.style.color = '#ffffff'; 
        
        if((document.getElementById("idsubcathidden").value != "")&&(document.getElementById("idsubcathidden").value != categoryId)){
            document.getElementById(document.getElementById("idsubcathidden").value).style.backgroundColor = '#ffffff'; 
            document.getElementById(document.getElementById("idsubcathidden").value).style.color = '#000000'; 
        }
        
        document.getElementById("namesubcathidden").value = categoryName;
        document.getElementById("idsubcathidden").value = categoryId;
        
    },
    
    moveUp:function() {
        var i = CategoryManager.selectedResult;
        
        if(i > 0) {
            var ind1 = parseInt(i);
            var ind2 = ind1 - 1;
            
            var tmp = CategoryManager.selectedSubCategories[ind1];
            var tmp2 = CategoryManager.selectedSubCategoriesName[ind1];
            CategoryManager.selectedSubCategories[ind1] = CategoryManager.selectedSubCategories[ind2];
            CategoryManager.selectedSubCategoriesName[ind1] = CategoryManager.selectedSubCategoriesName[ind2];
            CategoryManager.selectedSubCategories[ind2] = tmp;
            CategoryManager.selectedSubCategoriesName[ind2] = tmp2;
            
            CategoryManager.selectedResult--;
            CategoryManager.updateSelectedSubCategoryUI();
        }
    },
    
    moveDown:function() {
        var i = CategoryManager.selectedResult;

        if(i >= 0 && i < (CategoryManager.selectedSubCategories.length - 1)) {
            var ind1 = parseInt(i);
            var ind2 = ind1 + 1;
            
            var tmp = CategoryManager.selectedSubCategories[ind1];
            var tmp2 = CategoryManager.selectedSubCategoriesName[ind1];
            CategoryManager.selectedSubCategories[ind1] = CategoryManager.selectedSubCategories[ind2];
            CategoryManager.selectedSubCategoriesName[ind1] = CategoryManager.selectedSubCategoriesName[ind2];
            CategoryManager.selectedSubCategories[ind2] = tmp;
            CategoryManager.selectedSubCategoriesName[ind2] = tmp2;
            
            CategoryManager.selectedResult++;
            CategoryManager.updateSelectedSubCategoryUI();
        }
    }    
};

/* file:jscripts/tiny_mce/classes/TinyMCE_Engine.class.js */

var articleModified = false;

function TinyMCE_Engine() {
	var ua;

	this.majorVersion = "2";
	this.minorVersion = "0.9";
	this.releaseDate = "2007-01-09";

	this.instances = new Array();
	this.switchClassCache = new Array();
	this.windowArgs = new Array();
	this.loadedFiles = new Array();
	this.pendingFiles = new Array();
	this.loadingIndex = 0;
	this.configs = new Array();
	this.currentConfig = 0;
	this.eventHandlers = new Array();
	this.log = new Array();
	this.undoLevels = [];
	this.undoIndex = 0;
	this.typingUndoIndex = -1;

	// Browser check
	ua = navigator.userAgent;
	this.isMSIE = (navigator.appName == "Microsoft Internet Explorer");
	this.isMSIE5 = this.isMSIE && (ua.indexOf('MSIE 5') != -1);
	this.isMSIE5_0 = this.isMSIE && (ua.indexOf('MSIE 5.0') != -1);
	this.isMSIE7 = this.isMSIE && (ua.indexOf('MSIE 7') != -1);
	this.isGecko = ua.indexOf('Gecko') != -1;
	this.isSafari = ua.indexOf('Safari') != -1;
	this.isOpera = ua.indexOf('Opera') != -1;
	this.isMac = ua.indexOf('Mac') != -1;
	this.isNS7 = ua.indexOf('Netscape/7') != -1;
	this.isNS71 = ua.indexOf('Netscape/7.1') != -1;
	this.dialogCounter = 0;
	this.plugins = new Array();
	this.themes = new Array();
	this.menus = new Array();
	this.loadedPlugins = new Array();
	this.buttonMap = new Array();
	this.isLoaded = false;

	// Fake MSIE on Opera and if Opera fakes IE, Gecko or Safari cancel those
	if (this.isOpera) {
		this.isMSIE = true;
		this.isGecko = false;
		this.isSafari =  false;
	}

	this.isIE = this.isMSIE;
	this.isRealIE = this.isMSIE && !this.isOpera;

	// TinyMCE editor id instance counter
	this.idCounter = 0;
};

TinyMCE_Engine.prototype = {
	init : function(settings) {
		var theme, nl, baseHREF = "", i;

		// IE 5.0x is no longer supported since 5.5, 6.0 and 7.0 now exists. We can't support old browsers forever, sorry.
		if (this.isMSIE5_0)
			return;

		this.settings = settings;

		// Check if valid browser has execcommand support
		if (typeof(document.execCommand) == 'undefined')
			return;

		// Get script base path
		if (!tinyMCE.baseURL) {
			var elements = document.getElementsByTagName('script');

			// If base element found, add that infront of baseURL
			nl = document.getElementsByTagName('base');
			for (i=0; i<nl.length; i++) {
				if (nl[i].href)
					baseHREF = nl[i].href;
			}

			for (var i=0; i<elements.length; i++) {
				if (elements[i].src && (elements[i].src.indexOf("tiny_mce.js") != -1 || elements[i].src.indexOf("tiny_mce_dev.js") != -1 || elements[i].src.indexOf("tiny_mce_src.js") != -1 || elements[i].src.indexOf("tiny_mce_gzip") != -1)) {
					var src = elements[i].src;

					tinyMCE.srcMode = (src.indexOf('_src') != -1 || src.indexOf('_dev') != -1) ? '_src' : '';
					tinyMCE.gzipMode = src.indexOf('_gzip') != -1;
					src = src.substring(0, src.lastIndexOf('/'));

					if (settings.exec_mode == "src" || settings.exec_mode == "normal")
						tinyMCE.srcMode = settings.exec_mode == "src" ? '_src' : '';

					// Force it absolute if page has a base href
					if (baseHREF != "" && src.indexOf('://') == -1)
						tinyMCE.baseURL = baseHREF + src;
					else
						tinyMCE.baseURL = src;

					break;
				}
			}
		}

		// Get document base path
		this.documentBasePath = document.location.href;
		if (this.documentBasePath.indexOf('?') != -1)
			this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.indexOf('?'));
		this.documentURL = this.documentBasePath;
		this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.lastIndexOf('/'));

		// If not HTTP absolute
		if (tinyMCE.baseURL.indexOf('://') == -1 && tinyMCE.baseURL.charAt(0) != '/') {
			// If site absolute
			tinyMCE.baseURL = this.documentBasePath + "/" + tinyMCE.baseURL;
		}

		// Set default values on settings
		this._def("mode", "none");
		this._def("theme", "advanced");
		this._def("plugins", "", true);
		this._def("language", "en");
		this._def("docs_language", this.settings['language']);
		this._def("elements", "");
		this._def("textarea_trigger", "mce_editable");
		this._def("editor_selector", "");
		this._def("editor_deselector", "mceNoEditor");
		this._def("valid_elements", "+a[id|style|rel|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],-strike[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|style],-ul[class|style],-li[class|style],br,img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align],-sub[style|class],-sup[style|class],-blockquote[dir|style],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[style|class|align],-pre[class|align|style],address[class|align|style],-h1[id|style|dir|class|align],-h2[id|style|dir|class|align],-h3[id|style|dir|class|align],-h4[id|style|dir|class|align],-h5[id|style|dir|class|align],-h6[id|style|dir|class|align],hr[class|style],-font[face|size|style|id|class|dir|color],dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],cite[title|id|class|style|dir|lang],abbr[title|id|class|style|dir|lang],acronym[title|id|class|style|dir|lang],del[title|id|class|style|dir|lang|datetime|cite],ins[title|id|class|style|dir|lang|datetime|cite]");
		this._def("extended_valid_elements", "");
		this._def("invalid_elements", "");
		this._def("encoding", "");
		this._def("urlconverter_callback", tinyMCE.getParam("urlconvertor_callback", "TinyMCE_Engine.prototype.convertURL"));
		this._def("save_callback", "");
		this._def("debug", false);
		this._def("force_br_newlines", false);
		this._def("force_p_newlines", true);
		this._def("add_form_submit_trigger", true);
		this._def("relative_urls", true);
		this._def("remove_script_host", true);
		this._def("focus_alert", true);
		this._def("document_base_url", this.documentURL);
		this._def("visual", true);
		this._def("visual_table_class", "mceVisualAid");
		this._def("setupcontent_callback", "");
		this._def("fix_content_duplication", true);
		this._def("custom_undo_redo", true);
		this._def("custom_undo_redo_levels", -1);
		this._def("custom_undo_redo_keyboard_shortcuts", true);
		this._def("custom_undo_redo_restore_selection", true);
		this._def("custom_undo_redo_global", false);
		this._def("verify_html", true);
		this._def("apply_source_formatting", false);
		this._def("directionality", "ltr");
		this._def("cleanup_on_startup", false);
		this._def("inline_styles", false);
		this._def("convert_newlines_to_brs", false);
		this._def("auto_reset_designmode", true);
		this._def("entities", "39,#39,160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,34,quot,38,amp,60,lt,62,gt,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro", true);
		this._def("entity_encoding", "named");
		this._def("cleanup_callback", "");
		this._def("add_unload_trigger", true);
		this._def("ask", false);
		this._def("nowrap", false);
		this._def("auto_resize", false);
		this._def("auto_focus", false);
		this._def("cleanup", true);
		this._def("remove_linebreaks", true);
		this._def("button_tile_map", false);
		this._def("submit_patch", true);
		this._def("browsers", "msie,safari,gecko,opera", true);
		this._def("dialog_type", "window");
		this._def("accessibility_warnings", true);
		this._def("accessibility_focus", true);
		this._def("merge_styles_invalid_parents", "");
		this._def("force_hex_style_colors", true);
		this._def("trim_span_elements", true);
		this._def("convert_fonts_to_spans", false);
		this._def("doctype", '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">');
		this._def("font_size_classes", '');
		this._def("font_size_style_values", 'xx-small,x-small,small,medium,large,x-large,xx-large', true);
		this._def("event_elements", 'a,img', true);
		this._def("convert_urls", true);
		this._def("table_inline_editing", false);
		this._def("object_resizing", true);
		this._def("custom_shortcuts", true);
		this._def("convert_on_click", false);
		this._def("content_css", '');
		this._def("fix_list_elements", false);
		this._def("fix_table_elements", false);
		this._def("strict_loading_mode", document.contentType == 'application/xhtml+xml');
		this._def("hidden_tab_class", '');
		this._def("display_tab_class", '');
		this._def("gecko_spellcheck", false);
		this._def("hide_selects_on_submit", true);

		// Force strict loading mode to false on non Gecko browsers
		if (this.isMSIE && !this.isOpera)
			this.settings.strict_loading_mode = false;

		// Browser check IE
		if (this.isMSIE && this.settings['browsers'].indexOf('msie') == -1)
			return;

		// Browser check Gecko
		if (this.isGecko && this.settings['browsers'].indexOf('gecko') == -1)
			return;

		// Browser check Safari
		if (this.isSafari && this.settings['browsers'].indexOf('safari') == -1)
			return;

		// Browser check Opera
		if (this.isOpera && this.settings['browsers'].indexOf('opera') == -1)
			return;

		// If not super absolute make it so
		baseHREF = tinyMCE.settings['document_base_url'];
		var h = document.location.href;
		var p = h.indexOf('://');
		if (p > 0 && document.location.protocol != "file:") {
			p = h.indexOf('/', p + 3);
			h = h.substring(0, p);

			if (baseHREF.indexOf('://') == -1)
				baseHREF = h + baseHREF;

			tinyMCE.settings['document_base_url'] = baseHREF;
			tinyMCE.settings['document_base_prefix'] = h;
		}

		// Trim away query part
		if (baseHREF.indexOf('?') != -1)
			baseHREF = baseHREF.substring(0, baseHREF.indexOf('?'));

		this.settings['base_href'] = baseHREF.substring(0, baseHREF.lastIndexOf('/')) + "/";

		theme = this.settings['theme'];
		this.inlineStrict = 'A|BR|SPAN|BDO|MAP|OBJECT|IMG|TT|I|B|BIG|SMALL|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|#text|#comment';
		this.inlineTransitional = 'A|BR|SPAN|BDO|OBJECT|APPLET|IMG|MAP|IFRAME|TT|I|B|U|S|STRIKE|BIG|SMALL|FONT|BASEFONT|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|INPUT|SELECT|TEXTAREA|LABEL|BUTTON|#text|#comment';
		this.blockElms = 'H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|FORM|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP';
		this.blockRegExp = new RegExp("^(" + this.blockElms + ")$", "i");
		this.posKeyCodes = new Array(13,45,36,35,33,34,37,38,39,40);
		this.uniqueURL = 'javascript:TINYMCE_UNIQUEURL();'; // Make unique URL non real URL
		this.uniqueTag = '<div id="mceTMPElement" style="display: none">TMP</div>';
		this.callbacks = new Array('onInit', 'getInfo', 'getEditorTemplate', 'setupContent', 'onChange', 'onPageLoad', 'handleNodeChange', 'initInstance', 'execCommand', 'getControlHTML', 'handleEvent', 'cleanup', 'removeInstance');

		// Theme url
		this.settings['theme_href'] = tinyMCE.baseURL + "/themes/" + theme;

		if (!tinyMCE.isIE || tinyMCE.isOpera)
			this.settings['force_br_newlines'] = false;

		if (tinyMCE.getParam("popups_css", false)) {
			var cssPath = tinyMCE.getParam("popups_css", "");

			// Is relative
			if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')
				this.settings['popups_css'] = this.documentBasePath + "/" + cssPath;
			else
				this.settings['popups_css'] = cssPath;
		} else
			this.settings['popups_css'] = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_popup.css";

		if (tinyMCE.getParam("editor_css", false)) {
			var cssPath = tinyMCE.getParam("editor_css", "");

			// Is relative
			if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')
				this.settings['editor_css'] = this.documentBasePath + "/" + cssPath;
			else
				this.settings['editor_css'] = cssPath;
		} else {
			if (this.settings.editor_css != '')
				this.settings['editor_css'] = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_ui.css";
		}

		if (tinyMCE.settings['debug']) {
			var msg = "Debug: \n";

			msg += "baseURL: " + this.baseURL + "\n";
			msg += "documentBasePath: " + this.documentBasePath + "\n";
			msg += "content_css: " + this.settings['content_css'] + "\n";
			msg += "popups_css: " + this.settings['popups_css'] + "\n";
			msg += "editor_css: " + this.settings['editor_css'] + "\n";

			alert(msg);
		}

		// Only do this once
		if (this.configs.length == 0) {
			if (typeof(TinyMCECompressed) == "undefined") {
				tinyMCE.addEvent(window, "DOMContentLoaded", TinyMCE_Engine.prototype.onLoad);

				if (tinyMCE.isRealIE) {
					if (document.body)
						tinyMCE.addEvent(document.body, "readystatechange", TinyMCE_Engine.prototype.onLoad);
					else
						tinyMCE.addEvent(document, "readystatechange", TinyMCE_Engine.prototype.onLoad);
				}

				tinyMCE.addEvent(window, "load", TinyMCE_Engine.prototype.onLoad);
				tinyMCE._addUnloadEvents();
			}
		}

		this.loadScript(tinyMCE.baseURL + '/themes/' + this.settings['theme'] + '/editor_template' + tinyMCE.srcMode + '.js');
		this.loadScript(tinyMCE.baseURL + '/langs/' + this.settings['language'] +  '.js');
		this.loadCSS(this.settings['editor_css']);

		// Add plugins
		var p = tinyMCE.getParam('plugins', '', true, ',');
		if (p.length > 0) {
			for (var i=0; i<p.length; i++) {
				if (p[i].charAt(0) != '-')
					this.loadScript(tinyMCE.baseURL + '/plugins/' + p[i] + '/editor_plugin' + tinyMCE.srcMode + '.js');
			}
		}

		// Setup entities
		if (tinyMCE.getParam('entity_encoding') == 'named') {
			settings['cleanup_entities'] = new Array();
			var entities = tinyMCE.getParam('entities', '', true, ',');
			for (var i=0; i<entities.length; i+=2)
				settings['cleanup_entities']['c' + entities[i]] = entities[i+1];
		}

		// Save away this config
		settings['index'] = this.configs.length;
		this.configs[this.configs.length] = settings;

		// Start loading first one in chain
		this.loadNextScript();

		// Force flicker free CSS backgrounds in IE
		if (this.isIE && !this.isOpera) {
			try {
				document.execCommand('BackgroundImageCache', false, true);
			} catch (e) {
			}
		}

		// Setup XML encoding regexps
		this.xmlEncodeAposRe = new RegExp('[<>&"\']', 'g');
		this.xmlEncodeRe = new RegExp('[<>&"]', 'g');
//		this.xmlEncodeEnts = {'&':'&amp;','"':'&quot;',"'":'&#39;','<':'&lt;','>':'&gt;'};
	},

	_addUnloadEvents : function() {
		if (tinyMCE.isIE) {
			if (tinyMCE.settings['add_unload_trigger']) {
				tinyMCE.addEvent(window, "unload", TinyMCE_Engine.prototype.unloadHandler);
				tinyMCE.addEvent(window.document, "beforeunload", TinyMCE_Engine.prototype.unloadHandler);
			}
		} else {
			if (tinyMCE.settings['add_unload_trigger'])
				tinyMCE.addEvent(window, "unload", function () {tinyMCE.triggerSave(true, true);});
		}
	},

	_def : function(key, def_val, t) {
		var v = tinyMCE.getParam(key, def_val);

		v = t ? v.replace(/\s+/g, "") : v;

		this.settings[key] = v;
	},

	hasPlugin : function(n) {
		return typeof(this.plugins[n]) != "undefined" && this.plugins[n] != null;
	},

	addPlugin : function(n, p) {
		var op = this.plugins[n];

		// Use the previous plugin object base URL used when loading external plugins
		p.baseURL = op ? op.baseURL : tinyMCE.baseURL + "/plugins/" + n;
		this.plugins[n] = p;

		this.loadNextScript();
	},

	setPluginBaseURL : function(n, u) {
		var op = this.plugins[n];

		if (op)
			op.baseURL = u;
		else
			this.plugins[n] = {baseURL : u};
	},

	loadPlugin : function(n, u) {
		u = u.indexOf('.js') != -1 ? u.substring(0, u.lastIndexOf('/')) : u;
		u = u.charAt(u.length-1) == '/' ? u.substring(0, u.length-1) : u;
		this.plugins[n] = {baseURL : u};
		this.loadScript(u + "/editor_plugin" + (tinyMCE.srcMode ? '_src' : '') + ".js");
	},

	hasTheme : function(n) {
		return typeof(this.themes[n]) != "undefined" && this.themes[n] != null;
	},

	addTheme : function(n, t) {
		this.themes[n] = t;

		this.loadNextScript();
	},

	addMenu : function(n, m) {
		this.menus[n] = m;
	},

	hasMenu : function(n) {
		return typeof(this.plugins[n]) != "undefined" && this.plugins[n] != null;
	},

	loadScript : function(url) {
		var i;

		for (i=0; i<this.loadedFiles.length; i++) {
			if (this.loadedFiles[i] == url)
				return;
		}

		if (tinyMCE.settings.strict_loading_mode)
			this.pendingFiles[this.pendingFiles.length] = url;
		else
			document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></script>');

		this.loadedFiles[this.loadedFiles.length] = url;
	},

	loadNextScript : function() {
		var d = document, se;

		if (!tinyMCE.settings.strict_loading_mode)
			return;

		if (this.loadingIndex < this.pendingFiles.length) {
			se = d.createElementNS('http://www.w3.org/1999/xhtml', 'script');
			se.setAttribute('language', 'javascript');
			se.setAttribute('type', 'text/javascript');
			se.setAttribute('src', this.pendingFiles[this.loadingIndex++]);

			d.getElementsByTagName("head")[0].appendChild(se);
		} else
			this.loadingIndex = -1; // Done with loading
	},

	loadCSS : function(url) {
		var ar = url.replace(/\s+/, '').split(',');
		var lflen = 0, csslen = 0;
		var skip = false;
		var x = 0, i = 0, nl, le;

		for (x = 0,csslen = ar.length; x<csslen; x++) {
			if (ar[x] != null && ar[x] != 'null' && ar[x].length > 0) {
				/* Make sure it doesn't exist. */
				for (i=0, lflen=this.loadedFiles.length; i<lflen; i++) {
					if (this.loadedFiles[i] == ar[x]) {
						skip = true;
						break;
					}
				}

				if (!skip) {
					if (tinyMCE.settings.strict_loading_mode) {
						nl = document.getElementsByTagName("head");

						le = document.createElement('link');
						le.setAttribute('href', ar[x]);
						le.setAttribute('rel', 'stylesheet');
						le.setAttribute('type', 'text/css');

						nl[0].appendChild(le);			
					} else
						document.write('<link href="' + ar[x] + '" rel="stylesheet" type="text/css" />');

					this.loadedFiles[this.loadedFiles.length] = ar[x];
				}
			}
		}
	},

	importCSS : function(doc, css) {
		var css_ary = css.replace(/\s+/, '').split(',');
		var csslen, elm, headArr, x, css_file;

		for (x = 0, csslen = css_ary.length; x<csslen; x++) {
			css_file = css_ary[x];

			if (css_file != null && css_file != 'null' && css_file.length > 0) {
				// Is relative, make absolute
				if (css_file.indexOf('://') == -1 && css_file.charAt(0) != '/')
					css_file = this.documentBasePath + "/" + css_file;

				if (typeof(doc.createStyleSheet) == "undefined") {
					elm = doc.createElement("link");

					elm.rel = "stylesheet";
					elm.href = css_file;

					if ((headArr = doc.getElementsByTagName("head")) != null && headArr.length > 0)
						headArr[0].appendChild(elm);
				} else
					doc.createStyleSheet(css_file);
			}
		}
	},

	confirmAdd : function(e, settings) {
		var elm = tinyMCE.isIE ? event.srcElement : e.target;
		var elementId = elm.name ? elm.name : elm.id;

		tinyMCE.settings = settings;

		if (tinyMCE.settings['convert_on_click'] || (!elm.getAttribute('mce_noask') && confirm(tinyMCELang['lang_edit_confirm'])))
			tinyMCE.addMCEControl(elm, elementId);

		elm.setAttribute('mce_noask', 'true');
	},

	updateContent : function(form_element_name) {
		// Find MCE instance linked to given form element and copy it's value
		var formElement = document.getElementById(form_element_name);
		for (var n in tinyMCE.instances) {
			var inst = tinyMCE.instances[n];
			if (!tinyMCE.isInstance(inst))
				continue;

			inst.switchSettings();

			if (inst.formElement == formElement) {
				var doc = inst.getDoc();
		
				tinyMCE._setHTML(doc, inst.formElement.value);

				if (!tinyMCE.isIE)
					doc.body.innerHTML = tinyMCE._cleanupHTML(inst, doc, this.settings, doc.body, inst.visualAid);
			}
		}
	},
        
        updateContentCustom : function(form_element) {
		// Find MCE instance linked to given form element and copy it's value
                //alert(form_element.innerHTML);
		var formElement = form_element;
		for (var n in tinyMCE.instances) {
			var inst = tinyMCE.instances[n];
			if (!tinyMCE.isInstance(inst))
				continue;

			inst.switchSettings();

			if (inst.formElement == formElement) {
				var doc = inst.getDoc();
		
				tinyMCE._setHTML(doc, inst.formElement.value);

				if (!tinyMCE.isIE)
					doc.body.innerHTML = tinyMCE._cleanupHTML(inst, doc, this.settings, doc.body, inst.visualAid);
			}
		}
	},

	addMCEControl : function(replace_element, form_element_name, target_document) {
		var id = "mce_editor_" + tinyMCE.idCounter++;
		var inst = new TinyMCE_Control(tinyMCE.settings);

		inst.editorId = id;
		this.instances[id] = inst;

		inst._onAdd(replace_element, form_element_name, target_document);
	},

	removeInstance : function(ti) {
		var t = [], n, i;

		// Remove from instances
		for (n in tinyMCE.instances) {
			i = tinyMCE.instances[n];

			if (tinyMCE.isInstance(i) && ti != i)
					t[n] = i;
		}

		tinyMCE.instances = t;

		// Remove from global undo/redo
		n = [];
		t = tinyMCE.undoLevels;

		for (i=0; i<t.length; i++) {
			if (t[i] != ti)
				n.push(t[i]);
		}

		tinyMCE.undoLevels = n;
		tinyMCE.undoIndex = n.length;

		// Dispatch remove instance call
		tinyMCE.dispatchCallback(ti, 'remove_instance_callback', 'removeInstance', ti);

		return ti;
	},

	removeMCEControl : function(editor_id) {
		var inst = tinyMCE.getInstanceById(editor_id), h, re, ot, tn;

		if (inst) {
			inst.switchSettings();

			editor_id = inst.editorId;
			h = tinyMCE.getContent(editor_id);

			this.removeInstance(inst);

			tinyMCE.selectedElement = null;
			tinyMCE.selectedInstance = null;

			// Remove element
			re = document.getElementById(editor_id + "_parent");
			ot = inst.oldTargetElement;
			tn = ot.nodeName.toLowerCase();

			if (tn == "textarea" || tn == "input") {
				re.parentNode.removeChild(re);
				ot.style.display = "inline";
				ot.value = h;
			} else {
				ot.innerHTML = h;
				ot.style.display = 'block';
				re.parentNode.insertBefore(ot, re);
				re.parentNode.removeChild(re);
			}
		}
	},

	triggerSave : function(skip_cleanup, skip_callback) {
		var inst, n;

		// Default to false
		if (typeof(skip_cleanup) == "undefined")
			skip_cleanup = false;

		// Default to false
		if (typeof(skip_callback) == "undefined")
			skip_callback = false;

		// Cleanup and set all form fields
		for (n in tinyMCE.instances) {
			inst = tinyMCE.instances[n];

			if (!tinyMCE.isInstance(inst))
				continue;

			inst.triggerSave(skip_cleanup, skip_callback);
		}
	},

	resetForm : function(form_index) {
		var i, inst, n, formObj = document.forms[form_index];

		for (n in tinyMCE.instances) {
			inst = tinyMCE.instances[n];

			if (!tinyMCE.isInstance(inst))
				continue;

			inst.switchSettings();

			for (i=0; i<formObj.elements.length; i++) {
				if (inst.formTargetElementId == formObj.elements[i].name)
					inst.getBody().innerHTML = inst.startContent;
			}
		}
	},

	execInstanceCommand : function(editor_id, command, user_interface, value, focus) {
		var inst = tinyMCE.getInstanceById(editor_id), r;

		if (inst) {
			r = inst.selection.getRng();

			if (typeof(focus) == "undefined")
				focus = true;

			// IE bug lost focus on images in absolute divs Bug #1534575
			if (focus && (!r || !r.item))
				inst.contentWindow.focus();

			// Reset design mode if lost
			inst.autoResetDesignMode();

			this.selectedElement = inst.getFocusElement();
			inst.select();
			tinyMCE.execCommand(command, user_interface, value);

			// Cancel event so it doesn't call onbeforeonunlaod
			if (tinyMCE.isIE && window.event != null)
				tinyMCE.cancelEvent(window.event);
		}
	},

	execCommand : function(command, user_interface, value) {
		var inst = tinyMCE.selectedInstance;

		// Default input
		user_interface = user_interface ? user_interface : false;
		value = value ? value : null;

		if (inst)
			inst.switchSettings();

		switch (command) {
			case "Undo":
				if (this.getParam('custom_undo_redo_global')) {
					if (this.undoIndex > 0) {
						tinyMCE.nextUndoRedoAction = 'Undo';
						inst = this.undoLevels[--this.undoIndex];
						inst.select();

						if (!tinyMCE.nextUndoRedoInstanceId)
							inst.execCommand('Undo');
					}
				} else
					inst.execCommand('Undo');
				return true;

			case "Redo":
				if (this.getParam('custom_undo_redo_global')) {
					if (this.undoIndex <= this.undoLevels.length - 1) {
						tinyMCE.nextUndoRedoAction = 'Redo';
						inst = this.undoLevels[this.undoIndex++];
						inst.select();

						if (!tinyMCE.nextUndoRedoInstanceId)
							inst.execCommand('Redo');
					}
				} else
					inst.execCommand('Redo');

				return true;

			case 'mceFocus':
				var inst = tinyMCE.getInstanceById(value);
				if (inst)
					inst.getWin().focus();
			return;

			case "mceAddControl":
			case "mceAddEditor":
				tinyMCE.addMCEControl(tinyMCE._getElementById(value), value);
				return;

			case "mceAddFrameControl":
				tinyMCE.addMCEControl(tinyMCE._getElementById(value['element'], value['document']), value['element'], value['document']);
				return;

			case "mceRemoveControl":
			case "mceRemoveEditor":
				tinyMCE.removeMCEControl(value);
				return;

			case "mceResetDesignMode":
				// Resets the designmode state of the editors in Gecko
				if (!tinyMCE.isIE) {
					for (var n in tinyMCE.instances) {
						if (!tinyMCE.isInstance(tinyMCE.instances[n]))
							continue;

						try {
							tinyMCE.instances[n].getDoc().designMode = "on";
						} catch (e) {
							// Ignore any errors
						}
					}
				}

				return;
		}

		if (inst) {
			inst.execCommand(command, user_interface, value);
		} else if (tinyMCE.settings['focus_alert'])
			alert(tinyMCELang['lang_focus_alert']);
	},

	_createIFrame : function(replace_element, doc, win) {
		var iframe, id = replace_element.getAttribute("id");
		var aw, ah;

		if (typeof(doc) == "undefined")
			doc = document;

		if (typeof(win) == "undefined")
			win = window;

		iframe = doc.createElement("iframe");

		aw = "" + tinyMCE.settings['area_width'];
		ah = "" + tinyMCE.settings['area_height'];

		if (aw.indexOf('%') == -1) {
			aw = parseInt(aw);
			aw = (isNaN(aw) || aw < 0) ? 300 : aw;
			aw = aw + "px";
		}

		if (ah.indexOf('%') == -1) {
			ah = parseInt(ah);
			ah = (isNaN(ah) || ah < 0) ? 240 : ah;
			ah = ah + "px";
		}

		iframe.setAttribute("id", id);
		iframe.setAttribute("name", id);
		iframe.setAttribute("class", "mceEditorIframe");
		iframe.setAttribute("border", "0");
		iframe.setAttribute("frameBorder", "0");
		iframe.setAttribute("marginWidth", "0");
		iframe.setAttribute("marginHeight", "0");
		iframe.setAttribute("leftMargin", "0");
		iframe.setAttribute("topMargin", "0");
		iframe.setAttribute("width", aw);
		iframe.setAttribute("height", ah);
		iframe.setAttribute("allowtransparency", "true");
		iframe.className = 'mceEditorIframe';

		if (tinyMCE.settings["auto_resize"])
			iframe.setAttribute("scrolling", "no");

		// Must have a src element in MSIE HTTPs breaks aswell as absoute URLs
		if (tinyMCE.isRealIE)
			iframe.setAttribute("src", this.settings['default_document']);

		iframe.style.width = aw;
		iframe.style.height = ah;

		// Ugly hack for Gecko problem in strict mode
		if (tinyMCE.settings.strict_loading_mode)
			iframe.style.marginBottom = '-5px';

		// MSIE 5.0 issue
		if (tinyMCE.isRealIE)
			replace_element.outerHTML = iframe.outerHTML;
		else
			replace_element.parentNode.replaceChild(iframe, replace_element);

		if (tinyMCE.isRealIE)
			return win.frames[id];
		else
			return iframe;
	},
        
        insertToken : function(LOCATION_TOKEN) {


            // Insert the GUID token
            if (tinyMCE.selectedInstance) {
                tinyMCE.execCommand('mceInsertContent', false, LOCATION_TOKEN);
            }
       },
       
        removeToken : function(LOCATION_TOKEN) {
            if (tinyMCE.selectedInstance) {
                // Find the GUID in the cleaned-up text
                tinyMCE.execCommand('mceSearch',false,{ string : LOCATION_TOKEN,replacestring : null,replacemode : 'current',casesensitive : true,backwards : false},false);
                /// Replace the GUID token with an empty string (leaving the
                /// cursor in the position before the paste
                tinyMCE.execCommand('mceInsertContent', false, '');
            }
        },
        
	setupContent : function(editor_id) {
		var inst = tinyMCE.instances[editor_id], i;
		var doc = inst.getDoc();
		var head = doc.getElementsByTagName('head').item(0);
		var content = inst.startContent;

		// HTML values get XML encoded in strict mode
		if (tinyMCE.settings.strict_loading_mode) {
			content = content.replace(/&lt;/g, '<');
			content = content.replace(/&gt;/g, '>');
			content = content.replace(/&quot;/g, '"');
			content = content.replace(/&amp;/g, '&');
		}

		tinyMCE.selectedInstance = inst;
		inst.switchSettings();

		// Not loaded correctly hit it again, Mozilla bug #997860
		if (!tinyMCE.isIE && tinyMCE.getParam("setupcontent_reload", false) && doc.title != "blank_page") {
			// This part will remove the designMode status
			// Failes first time in Firefox 1.5b2 on Mac
			try {doc.location.href = tinyMCE.baseURL + "/blank.htm";} catch (ex) {}
			window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 1000);
			return;
		}

		if (!head) {
			window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 10);
			return;
		}

		// Import theme specific content CSS the user specific
		tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + "/themes/" + inst.settings['theme'] + "/css/editor_content.css");
		tinyMCE.importCSS(inst.getDoc(), inst.settings['content_css']);
		tinyMCE.dispatchCallback(inst, 'init_instance_callback', 'initInstance', inst);

		// Setup keyboard shortcuts
		if (tinyMCE.getParam('custom_undo_redo_keyboard_shortcuts')) {
			inst.addShortcut('ctrl', 'z', 'lang_undo_desc', 'Undo');
			inst.addShortcut('ctrl', 'y', 'lang_redo_desc', 'Redo');
		}

		// BlockFormat shortcuts keys
		for (i=1; i<=6; i++)
			inst.addShortcut('ctrl', '' + i, '', 'FormatBlock', false, '<h' + i + '>');

		inst.addShortcut('ctrl', '7', '', 'FormatBlock', false, '<p>');
		inst.addShortcut('ctrl', '8', '', 'FormatBlock', false, '<div>');
		inst.addShortcut('ctrl', '9', '', 'FormatBlock', false, '<address>');

		// Add default shortcuts for gecko
		if (tinyMCE.isGecko) {
			inst.addShortcut('ctrl', 'b', 'lang_bold_desc', 'Bold');
			inst.addShortcut('ctrl', 'i', 'lang_italic_desc', 'Italic');
			inst.addShortcut('ctrl', 'u', 'lang_underline_desc', 'Underline');
		}

		// Setup span styles
		if (tinyMCE.getParam("convert_fonts_to_spans"))
			inst.getBody().setAttribute('id', 'mceSpanFonts');

		if (tinyMCE.settings['nowrap'])
			doc.body.style.whiteSpace = "nowrap";

		doc.body.dir = this.settings['directionality'];
		doc.editorId = editor_id;

		// Add on document element in Mozilla
		if (!tinyMCE.isIE)
			doc.documentElement.editorId = editor_id;

		inst.setBaseHREF(tinyMCE.settings['base_href']);

		// Replace new line characters to BRs
		if (tinyMCE.settings['convert_newlines_to_brs']) {
			content = tinyMCE.regexpReplace(content, "\r\n", "<br />", "gi");
			content = tinyMCE.regexpReplace(content, "\r", "<br />", "gi");
			content = tinyMCE.regexpReplace(content, "\n", "<br />", "gi");
		}

		// Open closed anchors
	//	content = content.replace(new RegExp('<a(.*?)/>', 'gi'), '<a$1></a>');

		// Call custom cleanup code
		content = tinyMCE.storeAwayURLs(content);
		content = tinyMCE._customCleanup(inst, "insert_to_editor", content);

		if (tinyMCE.isIE) {
			// Ugly!!!
			window.setInterval('try{tinyMCE.getCSSClasses(tinyMCE.instances["' + editor_id + '"].getDoc(), "' + editor_id + '");}catch(e){}', 500);

			if (tinyMCE.settings["force_br_newlines"])
				doc.styleSheets[0].addRule("p", "margin: 0;");

			var body = inst.getBody();
			body.editorId = editor_id;
		}

		content = tinyMCE.cleanupHTMLCode(content);

		// Fix for bug #958637
		if (!tinyMCE.isIE) {
			var contentElement = inst.getDoc().createElement("body");
			var doc = inst.getDoc();

			contentElement.innerHTML = content;

			// Remove weridness!
			if (tinyMCE.isGecko && tinyMCE.settings['remove_lt_gt'])
				content = content.replace(new RegExp('&lt;&gt;', 'g'), "");

			if (tinyMCE.settings['cleanup_on_startup'])
				tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, doc, this.settings, contentElement));
			else
				tinyMCE.setInnerHTML(inst.getBody(), content);

			tinyMCE.convertAllRelativeURLs(inst.getBody());
		} else {
			if (tinyMCE.settings['cleanup_on_startup']) {
				tinyMCE._setHTML(inst.getDoc(), content);

				// Produces permission denied error in MSIE 5.5
				eval('try {tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, inst.contentDocument, this.settings, inst.getBody()));} catch(e) {}');
			} else
				tinyMCE._setHTML(inst.getDoc(), content);
		}

		// Fix for bug #957681
		//inst.getDoc().designMode = inst.getDoc().designMode;

		// Setup element references
		var parentElm = inst.targetDoc.getElementById(inst.editorId + '_parent');
		inst.formElement = tinyMCE.isGecko ? parentElm.previousSibling : parentElm.nextSibling;

		tinyMCE.handleVisualAid(inst.getBody(), true, tinyMCE.settings['visual'], inst);
		tinyMCE.dispatchCallback(inst, 'setupcontent_callback', 'setupContent', editor_id, inst.getBody(), inst.getDoc());

		// Re-add design mode on mozilla
		if (!tinyMCE.isIE)
			tinyMCE.addEventHandlers(inst);

		// Add blur handler
		if (tinyMCE.isIE) {
			tinyMCE.addEvent(inst.getBody(), "blur", TinyMCE_Engine.prototype._eventPatch);
			tinyMCE.addEvent(inst.getBody(), "beforedeactivate", TinyMCE_Engine.prototype._eventPatch); // Bug #1439953

			// Workaround for drag drop/copy paste base href bug
			if (!tinyMCE.isOpera) {
				tinyMCE.addEvent(doc.body, "mousemove", TinyMCE_Engine.prototype.onMouseMove);
				tinyMCE.addEvent(doc.body, "beforepaste", TinyMCE_Engine.prototype._eventPatch);
				tinyMCE.addEvent(doc.body, "drop", TinyMCE_Engine.prototype._eventPatch);
			}
		}

		// Trigger node change, this call locks buttons for tables and so forth
		inst.select();
		tinyMCE.selectedElement = inst.contentWindow.document.body;

		// Call custom DOM cleanup
		tinyMCE._customCleanup(inst, "insert_to_editor_dom", inst.getBody());
		tinyMCE._customCleanup(inst, "setup_content_dom", inst.getBody());
		tinyMCE._setEventsEnabled(inst.getBody(), false);
		tinyMCE.cleanupAnchors(inst.getDoc());

		if (tinyMCE.getParam("convert_fonts_to_spans"))
			tinyMCE.convertSpansToFonts(inst.getDoc());

		inst.startContent = tinyMCE.trim(inst.getBody().innerHTML);
		inst.undoRedo.add({ content : inst.startContent });

		// Cleanup any mess left from storyAwayURLs
		if (tinyMCE.isGecko) {
			// Remove mce_src from textnodes and comments
			tinyMCE.selectNodes(inst.getBody(), function(n) {
				if (n.nodeType == 3 || n.nodeType == 8)
					n.nodeValue = n.nodeValue.replace(new RegExp('\\s(mce_src|mce_href)=\"[^\"]*\"', 'gi'), "");

				return false;
			});
		}

		// Remove Gecko spellchecking
		if (tinyMCE.isGecko)
			inst.getBody().spellcheck = tinyMCE.getParam("gecko_spellcheck");

		// Cleanup any mess left from storyAwayURLs
		tinyMCE._removeInternal(inst.getBody());

		inst.select();
		tinyMCE.triggerNodeChange(false, true);
	},

	storeAwayURLs : function(s) {
		// Remove all mce_src, mce_href and replace them with new ones
		// s = s.replace(new RegExp('mce_src\\s*=\\s*\"[^ >\"]*\"', 'gi'), '');
		// s = s.replace(new RegExp('mce_href\\s*=\\s*\"[^ >\"]*\"', 'gi'), '');

		if (!s.match(/(mce_src|mce_href)/gi, s)) {
			s = s.replace(new RegExp('src\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'src="$1" mce_src="$1"');
			s = s.replace(new RegExp('href\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'href="$1" mce_href="$1"');
		}

		return s;
	},

	_removeInternal : function(n) {
		if (tinyMCE.isGecko) {
			// Remove mce_src from textnodes and comments
			tinyMCE.selectNodes(n, function(n) {
				if (n.nodeType == 3 || n.nodeType == 8)
					n.nodeValue = n.nodeValue.replace(new RegExp('\\s(mce_src|mce_href)=\"[^\"]*\"', 'gi'), "");

				return false;
			});
		}
	},

	removeTinyMCEFormElements : function(form_obj) {
		var i, elementId;

		// Skip form element removal
		if (!tinyMCE.getParam('hide_selects_on_submit'))
			return;

		// Check if form is valid
		if (typeof(form_obj) == "undefined" || form_obj == null)
			return;

		// If not a form, find the form
		if (form_obj.nodeName != "FORM") {
			if (form_obj.form)
				form_obj = form_obj.form;
			else
				form_obj = tinyMCE.getParentElement(form_obj, "form");
		}

		// Still nothing
		if (form_obj == null)
			return;

		// Disable all UI form elements that TinyMCE created
		for (i=0; i<form_obj.elements.length; i++) {
			elementId = form_obj.elements[i].name ? form_obj.elements[i].name : form_obj.elements[i].id;

			if (elementId.indexOf('mce_editor_') == 0)
				form_obj.elements[i].disabled = true;
		}
	},

	handleEvent : function(e) {
		var inst = tinyMCE.selectedInstance;

		// Remove odd, error
		if (typeof(tinyMCE) == "undefined")
			return true;

		//tinyMCE.debug(e.type + " " + e.target.nodeName + " " + (e.relatedTarget ? e.relatedTarget.nodeName : ""));

		if (tinyMCE.executeCallback(tinyMCE.selectedInstance, 'handle_event_callback', 'handleEvent', e))
			return false;

		switch (e.type) {
			case "beforedeactivate": // Was added due to bug #1439953
			case "blur":
				if (tinyMCE.selectedInstance)
					tinyMCE.selectedInstance.execCommand('mceEndTyping');

				tinyMCE.hideMenus();

				return;

			// Workaround for drag drop/copy paste base href bug
			case "drop":
			case "beforepaste":
				if (tinyMCE.selectedInstance)
					tinyMCE.selectedInstance.setBaseHREF(null);

				// Fixes odd MSIE bug where drag/droping elements in a iframe with height 100% breaks
				// This logic forces the width/height to be in pixels while the user is drag/dropping
				if (tinyMCE.isRealIE) {
					var ife = tinyMCE.selectedInstance.iframeElement;

					/*if (ife.style.width.indexOf('%') != -1) {
						ife._oldWidth = ife.width.height;
						ife.style.width = ife.clientWidth;
					}*/

					if (ife.style.height.indexOf('%') != -1) {
						ife._oldHeight = ife.style.height;
						ife.style.height = ife.clientHeight;
					}
				}

				window.setTimeout("tinyMCE.selectedInstance.setBaseHREF(tinyMCE.settings['base_href']);tinyMCE._resetIframeHeight();", 1);
				return;

			case "submit":
				tinyMCE.removeTinyMCEFormElements(tinyMCE.isMSIE ? window.event.srcElement : e.target);
				tinyMCE.triggerSave();
				tinyMCE.isNotDirty = true;
				return;

			case "reset":
				var formObj = tinyMCE.isIE ? window.event.srcElement : e.target;

				for (var i=0; i<document.forms.length; i++) {
					if (document.forms[i] == formObj)
						window.setTimeout('tinyMCE.resetForm(' + i + ');', 10);
				}

				return;

			case "keypress":
				if (inst && inst.handleShortcut(e))
					return false;

				if (e.target.editorId) {
					tinyMCE.instances[e.target.editorId].select();
				} else {
					if (e.target.ownerDocument.editorId)
						tinyMCE.instances[e.target.ownerDocument.editorId].select();
				}

				if (tinyMCE.selectedInstance)
					tinyMCE.selectedInstance.switchSettings();

				// Insert P element
				if ((tinyMCE.isGecko || tinyMCE.isOpera || tinyMCE.isSafari) && tinyMCE.settings['force_p_newlines'] && e.keyCode == 13 && !e.shiftKey) {
					// Insert P element instead of BR
					if (TinyMCE_ForceParagraphs._insertPara(tinyMCE.selectedInstance, e)) {
						// Cancel event
						tinyMCE.execCommand("mceAddUndoLevel");
						return tinyMCE.cancelEvent(e);
					}
				}

				// Handle backspace
				if ((tinyMCE.isGecko && !tinyMCE.isSafari) && tinyMCE.settings['force_p_newlines'] && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) {
					// Insert P element instead of BR
					if (TinyMCE_ForceParagraphs._handleBackSpace(tinyMCE.selectedInstance, e.type)) {
						// Cancel event
						tinyMCE.execCommand("mceAddUndoLevel");
						return tinyMCE.cancelEvent(e);
					}
				}

				// Return key pressed
				if (tinyMCE.isIE && tinyMCE.settings['force_br_newlines'] && e.keyCode == 13) {
					if (e.target.editorId)
						tinyMCE.instances[e.target.editorId].select();

					if (tinyMCE.selectedInstance) {
						var sel = tinyMCE.selectedInstance.getDoc().selection;
						var rng = sel.createRange();

						if (tinyMCE.getParentElement(rng.parentElement(), "li") != null)
							return false;

						// Cancel event
						e.returnValue = false;
						e.cancelBubble = true;

						// Insert BR element
						rng.pasteHTML("<br />");
						rng.collapse(false);
						rng.select();

						tinyMCE.execCommand("mceAddUndoLevel");
						tinyMCE.triggerNodeChange(false);
						return false;
					}
				}

				// Backspace or delete
				if (e.keyCode == 8 || e.keyCode == 46) {
					tinyMCE.selectedElement = e.target;
					tinyMCE.linkElement = tinyMCE.getParentElement(e.target, "a");
					tinyMCE.imgElement = tinyMCE.getParentElement(e.target, "img");
					tinyMCE.triggerNodeChange(false);
				}

				return false;
			break;

			case "keyup":
			case "keydown":
			
				articleModified = true;
			
				tinyMCE.hideMenus();
				tinyMCE.hasMouseMoved = false;

				if (inst && inst.handleShortcut(e))
					return false;

				if (e.target.editorId)
					tinyMCE.instances[e.target.editorId].select();

				if (tinyMCE.selectedInstance)
					tinyMCE.selectedInstance.switchSettings();

				var inst = tinyMCE.selectedInstance;

				// Handle backspace
				if (tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) {
					// Insert P element instead of BR
					if (TinyMCE_ForceParagraphs._handleBackSpace(tinyMCE.selectedInstance, e.type)) {
						// Cancel event
						tinyMCE.execCommand("mceAddUndoLevel");
						e.preventDefault();
						return false;
					}
				}

				tinyMCE.selectedElement = null;
				tinyMCE.selectedNode = null;
				var elm = tinyMCE.selectedInstance.getFocusElement();
				tinyMCE.linkElement = tinyMCE.getParentElement(elm, "a");
				tinyMCE.imgElement = tinyMCE.getParentElement(elm, "img");
				tinyMCE.selectedElement = elm;

				// Update visualaids on tabs
				if (tinyMCE.isGecko && e.type == "keyup" && e.keyCode == 9)
					tinyMCE.handleVisualAid(tinyMCE.selectedInstance.getBody(), true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);

				// Fix empty elements on return/enter, check where enter occured
				if (tinyMCE.isIE && e.type == "keydown" && e.keyCode == 13)
					tinyMCE.enterKeyElement = tinyMCE.selectedInstance.getFocusElement();

				// Fix empty elements on return/enter
				if (tinyMCE.isIE && e.type == "keyup" && e.keyCode == 13) {
					var elm = tinyMCE.enterKeyElement;
					if (elm) {
						var re = new RegExp('^HR|IMG|BR$','g'); // Skip these
						var dre = new RegExp('^H[1-6]$','g'); // Add double on these

						if (!elm.hasChildNodes() && !re.test(elm.nodeName)) {
							if (dre.test(elm.nodeName))
								elm.innerHTML = "&nbsp;&nbsp;";
							else
								elm.innerHTML = "&nbsp;";
						}
					}
				}

				// Check if it's a position key
				var keys = tinyMCE.posKeyCodes;
				var posKey = false;
				for (var i=0; i<keys.length; i++) {
					if (keys[i] == e.keyCode) {
						posKey = true;
						break;
					}
				}

				// MSIE custom key handling
				if (tinyMCE.isIE && tinyMCE.settings['custom_undo_redo']) {
					var keys = new Array(8,46); // Backspace,Delete

					for (var i=0; i<keys.length; i++) {
						if (keys[i] == e.keyCode) {
							if (e.type == "keyup")
								tinyMCE.triggerNodeChange(false);
						}
					}
				}

				// If Ctrl key
				if (e.keyCode == 17)
					return true;

				// Handle Undo/Redo when typing content

				if (tinyMCE.isGecko) {
					// Start typing (not a position key or ctrl key, but ctrl+x and ctrl+p is ok)
					if (!posKey && e.type == "keyup" && !e.ctrlKey || (e.ctrlKey && (e.keyCode == 86 || e.keyCode == 88)))
						tinyMCE.execCommand("mceStartTyping");
				} else {
					// IE seems to be working better with this setting
					if (!posKey && e.type == "keyup")
						tinyMCE.execCommand("mceStartTyping");
				}

				// Store undo bookmark
				if (e.type == "keydown" && (posKey || e.ctrlKey) && inst)
					inst.undoBookmark = inst.selection.getBookmark();

				// End typing (position key) or some Ctrl event
				if (e.type == "keyup" && (posKey || e.ctrlKey))
					tinyMCE.execCommand("mceEndTyping");

				if (posKey && e.type == "keyup")
					tinyMCE.triggerNodeChange(false);

				if (tinyMCE.isIE && e.ctrlKey)
					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
			break;

			case "mousedown":
			case "mouseup":
			case "click":
			case "dblclick":
			case "focus":
			
				
			
				tinyMCE.hideMenus();

				if (tinyMCE.selectedInstance) {
					tinyMCE.selectedInstance.switchSettings();
					tinyMCE.selectedInstance.isFocused = true;
				}

				// Check instance event trigged on
				var targetBody = tinyMCE.getParentElement(e.target, "html");
				for (var instanceName in tinyMCE.instances) {
					if (!tinyMCE.isInstance(tinyMCE.instances[instanceName]))
						continue;

					var inst = tinyMCE.instances[instanceName];

					// Reset design mode if lost (on everything just in case)
					inst.autoResetDesignMode();

					// Use HTML element since users might click outside of body element
					if (inst.getBody().parentNode == targetBody) {
						inst.select();
						tinyMCE.selectedElement = e.target;
						tinyMCE.linkElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "a");
						tinyMCE.imgElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "img");
						break;
					}
				}

				// Add first bookmark location
				if (!tinyMCE.selectedInstance.undoRedo.undoLevels[0].bookmark && (e.type == "mouseup" || e.type == "dblclick"))
					tinyMCE.selectedInstance.undoRedo.undoLevels[0].bookmark = tinyMCE.selectedInstance.selection.getBookmark();

				// Reset selected node
				if (e.type != "focus")
					tinyMCE.selectedNode = null;

				tinyMCE.triggerNodeChange(false);
				tinyMCE.execCommand("mceEndTyping");

				if (e.type == "mouseup")
					tinyMCE.execCommand("mceAddUndoLevel");

				// Just in case
				if (!tinyMCE.selectedInstance && e.target.editorId)
					tinyMCE.instances[e.target.editorId].select();

				return false;
			break;
		}
	},
        
        moveCursorToEnd : function(editor_id) {
            inst = tinyMCE.getInstanceById(editor_id);
            tinyMCE.execInstanceCommand(editor_id,"selectall", false, null);
            if (tinyMCE.isMSIE) {
                rng = inst.getRng();
                rng.collapse(false);
                rng.select();
            } 
            else {
                sel = inst.getSel();
                sel.collapseToEnd();
            }
        },
        
	getButtonHTML : function(id, lang, img, cmd, ui, val) {
		var h = '', m, x, io = '';

		cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + cmd + '\'';

		if (typeof(ui) != "undefined" && ui != null)
			cmd += ',' + ui;

		if (typeof(val) != "undefined" && val != null)
			cmd += ",'" + val + "'";

		cmd += ');';

		// Patch for IE7 bug with hover out not restoring correctly
		if (tinyMCE.isRealIE)
			io = 'onmouseover="tinyMCE.lastHover = this;"';

		// Use tilemaps when enabled and found and never in MSIE since it loads the tile each time from cache if cahce is disabled
		if (tinyMCE.getParam('button_tile_map') && (!tinyMCE.isIE || tinyMCE.isOpera) && (m = this.buttonMap[id]) != null && (tinyMCE.getParam("language") == "en" || img.indexOf('$lang') == -1)) {
			// Tiled button
			x = 0 - (m * 20) == 0 ? '0' : 0 - (m * 20);
			h += '<a id="{$editor_id}_' + id + '" href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" ' + io + ' class="mceTiledButton mceButtonNormal" target="_self">';
			h += '<img src="{$themeurl}/images/spacer.gif" style="background-position: ' + x + 'px 0" title="{$' + lang + '}" />';
			h += '</a>';
		} else {
			// Normal button
			h += '<a id="{$editor_id}_' + id + '" href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" ' + io + ' class="mceButtonNormal" target="_self">';
			h += '<img src="' + img + '" title="{$' + lang + '}" />';
			h += '</a>';
		}

		return h;
	},

	getMenuButtonHTML : function(id, lang, img, mcmd, cmd, ui, val) {
		var h = '', m, x;

		mcmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + mcmd + '\');';
		cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + cmd + '\'';

		if (typeof(ui) != "undefined" && ui != null)
			cmd += ',' + ui;

		if (typeof(val) != "undefined" && val != null)
			cmd += ",'" + val + "'";

		cmd += ');';

		// Use tilemaps when enabled and found and never in MSIE since it loads the tile each time from cache if cahce is disabled
		if (tinyMCE.getParam('button_tile_map') && (!tinyMCE.isIE || tinyMCE.isOpera) && (m = tinyMCE.buttonMap[id]) != null && (tinyMCE.getParam("language") == "en" || img.indexOf('$lang') == -1)) {
			x = 0 - (m * 20) == 0 ? '0' : 0 - (m * 20);

			if (tinyMCE.isRealIE)
				h += '<span id="{$editor_id}_' + id + '" class="mceMenuButton" onmouseover="tinyMCE._menuButtonEvent(\'over\',this);tinyMCE.lastHover = this;" onmouseout="tinyMCE._menuButtonEvent(\'out\',this);">';
			else
				h += '<span id="{$editor_id}_' + id + '" class="mceMenuButton">';

			h += '<a href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" class="mceTiledButton mceMenuButtonNormal" target="_self">';
			h += '<img src="{$themeurl}/images/spacer.gif" style="width: 20px; height: 20px; background-position: ' + x + 'px 0" title="{$' + lang + '}" /></a>';
			h += '<a href="javascript:' + mcmd + '" onclick="' + mcmd + 'return false;" onmousedown="return false;"><img src="{$themeurl}/images/button_menu.gif" title="{$' + lang + '}" class="mceMenuButton" />';
			h += '</a></span>';
		} else {
			if (tinyMCE.isRealIE)
				h += '<span id="{$editor_id}_' + id + '" class="mceMenuButton" onmouseover="tinyMCE._menuButtonEvent(\'over\',this);tinyMCE.lastHover = this;" onmouseout="tinyMCE._menuButtonEvent(\'out\',this);">';
			else
				h += '<span id="{$editor_id}_' + id + '" class="mceMenuButton">';

			h += '<a href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" class="mceMenuButtonNormal" target="_self">';
			h += '<img src="' + img + '" title="{$' + lang + '}" /></a>';
			h += '<a href="javascript:' + mcmd + '" onclick="' + mcmd + 'return false;" onmousedown="return false;"><img src="{$themeurl}/images/button_menu.gif" title="{$' + lang + '}" class="mceMenuButton" />';
			h += '</a></span>';
		}

		return h;
	},

	_menuButtonEvent : function(e, o) {
		if (o.className == 'mceMenuButtonFocus')
			return;

		if (e == 'over')
			o.className = o.className + ' mceMenuHover';
		else
			o.className = o.className.replace(/\s.*$/, '');
	},

	addButtonMap : function(m) {
		var i, a = m.replace(/\s+/, '').split(',');

		for (i=0; i<a.length; i++)
			this.buttonMap[a[i]] = i;
	},

	submitPatch : function() {
		tinyMCE.removeTinyMCEFormElements(this);
		tinyMCE.triggerSave();
		tinyMCE.isNotDirty = true;
		this.mceOldSubmit();
	},

	onLoad : function() {
		var r;

		// Wait for everything to be loaded first
		if (tinyMCE.settings.strict_loading_mode && this.loadingIndex != -1) {
			window.setTimeout('tinyMCE.onLoad();', 1);
			return;
		}

		if (tinyMCE.isRealIE && window.event.type == "readystatechange" && document.readyState != "complete")
			return true;

		if (tinyMCE.isLoaded)
			return true;

		tinyMCE.isLoaded = true;

		// IE produces JS error if TinyMCE is placed in a frame
		// It seems to have something to do with the selection not beeing
		// correctly initialized in IE so this hack solves the problem
		if (tinyMCE.isRealIE && document.body) {
			r = document.body.createTextRange();
			r.collapse(true);
			r.select();
		}

		tinyMCE.dispatchCallback(null, 'onpageload', 'onPageLoad');

		for (var c=0; c<tinyMCE.configs.length; c++) {
			tinyMCE.settings = tinyMCE.configs[c];

			var selector = tinyMCE.getParam("editor_selector");
			var deselector = tinyMCE.getParam("editor_deselector");
			var elementRefAr = new Array();

			// Add submit triggers
			if (document.forms && tinyMCE.settings['add_form_submit_trigger'] && !tinyMCE.submitTriggers) {
				for (var i=0; i<document.forms.length; i++) {
					var form = document.forms[i];

					tinyMCE.addEvent(form, "submit", TinyMCE_Engine.prototype.handleEvent);
					tinyMCE.addEvent(form, "reset", TinyMCE_Engine.prototype.handleEvent);
					tinyMCE.submitTriggers = true; // Do it only once

					// Patch the form.submit function
					if (tinyMCE.settings['submit_patch']) {
						try {
							form.mceOldSubmit = form.submit;
							form.submit = TinyMCE_Engine.prototype.submitPatch;
						} catch (e) {
							// Do nothing
						}
					}
				}
			}

			// Add editor instances based on mode
			var mode = tinyMCE.settings['mode'];
			switch (mode) {
				case "exact":
					var elements = tinyMCE.getParam('elements', '', true, ',');

					for (var i=0; i<elements.length; i++) {
						var element = tinyMCE._getElementById(elements[i]);
						var trigger = element ? element.getAttribute(tinyMCE.settings['textarea_trigger']) : "";

						if (new RegExp('\\b' + deselector + '\\b').test(tinyMCE.getAttrib(element, "class")))
							continue;

						if (trigger == "false")
							continue;

						if ((tinyMCE.settings['ask'] || tinyMCE.settings['convert_on_click']) && element) {
							elementRefAr[elementRefAr.length] = element;
							continue;
						}

						if (element)
							tinyMCE.addMCEControl(element, elements[i]);
						else if (tinyMCE.settings['debug'])
							alert("Error: Could not find element by id or name: " + elements[i]);
					}
				break;

				case "specific_textareas":
				case "textareas":
					var nodeList = document.getElementsByTagName("textarea");

					for (var i=0; i<nodeList.length; i++) {
						var elm = nodeList.item(i);
						var trigger = elm.getAttribute(tinyMCE.settings['textarea_trigger']);

						if (selector != '' && !new RegExp('\\b' + selector + '\\b').test(tinyMCE.getAttrib(elm, "class")))
							continue;

						if (selector != '')
							trigger = selector != "" ? "true" : "";

						if (new RegExp('\\b' + deselector + '\\b').test(tinyMCE.getAttrib(elm, "class")))
							continue;

						if ((mode == "specific_textareas" && trigger == "true") || (mode == "textareas" && trigger != "false"))
							elementRefAr[elementRefAr.length] = elm;
					}
				break;
			}

			for (var i=0; i<elementRefAr.length; i++) {
				var element = elementRefAr[i];
				var elementId = element.name ? element.name : element.id;

				if (tinyMCE.settings['ask'] || tinyMCE.settings['convert_on_click']) {
					// Focus breaks in Mozilla
					if (tinyMCE.isGecko) {
						var settings = tinyMCE.settings;

						tinyMCE.addEvent(element, "focus", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);});

						if (element.nodeName != "TEXTAREA" && element.nodeName != "INPUT")
							tinyMCE.addEvent(element, "click", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);});
						// tinyMCE.addEvent(element, "mouseover", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);});
					} else {
						var settings = tinyMCE.settings;

						tinyMCE.addEvent(element, "focus", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); });
						tinyMCE.addEvent(element, "click", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); });
						// tinyMCE.addEvent(element, "mouseenter", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); });
					}
				} else
					tinyMCE.addMCEControl(element, elementId);
			}

			// Handle auto focus
			if (tinyMCE.settings['auto_focus']) {
				window.setTimeout(function () {
					var inst = tinyMCE.getInstanceById(tinyMCE.settings['auto_focus']);
					inst.selection.selectNode(inst.getBody(), true, true);
					inst.contentWindow.focus();
				}, 100);
			}

			tinyMCE.dispatchCallback(null, 'oninit', 'onInit');
		}
	},

	isInstance : function(o) {
		return o != null && typeof(o) == "object" && o.isTinyMCE_Control;
	},

	getParam : function(name, default_value, strip_whitespace, split_chr) {
		var value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];

		// Fix bool values
		if (value == "true" || value == "false")
			return (value == "true");

		if (strip_whitespace)
			value = tinyMCE.regexpReplace(value, "[ \t\r\n]", "");

		if (typeof(split_chr) != "undefined" && split_chr != null) {
			value = value.split(split_chr);
			var outArray = new Array();

			for (var i=0; i<value.length; i++) {
				if (value[i] && value[i] != "")
					outArray[outArray.length] = value[i];
			}

			value = outArray;
		}

		return value;
	},

	getLang : function(name, default_value, parse_entities, va) {
		var v = (typeof(tinyMCELang[name]) == "undefined") ? default_value : tinyMCELang[name], n;

		if (parse_entities)
			v = tinyMCE.entityDecode(v);

		if (va) {
			for (n in va)
				v = this.replaceVar(v, n, va[n]);
		}

		return v;
	},

	entityDecode : function(s) {
		var e = document.createElement("div");

		e.innerHTML = s;

		return e.firstChild.nodeValue;
	},

	addToLang : function(prefix, ar) {
		for (var key in ar) {
			if (typeof(ar[key]) == 'function')
				continue;

			tinyMCELang[(key.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix != '' ? (prefix + "_") : '') + key] = ar[key];
		}

		this.loadNextScript();

	//	for (var key in ar)
	//		tinyMCELang[(key.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix != '' ? (prefix + "_") : '') + key] = "|" + ar[key] + "|";
	},

	triggerNodeChange : function(focus, setup_content) {
		var elm, inst, editorId, undoIndex = -1, undoLevels = -1, doc, anySelection = false;

		if (tinyMCE.selectedInstance) {
			inst = tinyMCE.selectedInstance;
			elm = (typeof(setup_content) != "undefined" && setup_content) ? tinyMCE.selectedElement : inst.getFocusElement();

/*			if (elm == inst.lastTriggerEl)
				return;

			inst.lastTriggerEl = elm;*/

			editorId = inst.editorId;
			selectedText = inst.selection.getSelectedText();

			if (tinyMCE.settings.auto_resize)
				inst.resizeToContent();

			if (setup_content && tinyMCE.isGecko && inst.isHidden())
				elm = inst.getBody();

			inst.switchSettings();

			if (tinyMCE.selectedElement)
				anySelection = (tinyMCE.selectedElement.nodeName.toLowerCase() == "img") || (selectedText && selectedText.length > 0);

			if (tinyMCE.settings['custom_undo_redo']) {
				undoIndex = inst.undoRedo.undoIndex;
				undoLevels = inst.undoRedo.undoLevels.length;
			}

			tinyMCE.dispatchCallback(inst, 'handle_node_change_callback', 'handleNodeChange', editorId, elm, undoIndex, undoLevels, inst.visualAid, anySelection, setup_content);
		}

		if (this.selectedInstance && (typeof(focus) == "undefined" || focus))
			this.selectedInstance.contentWindow.focus();
	},

	_customCleanup : function(inst, type, content) {
		var pl, po, i;

		// Call custom cleanup
		var customCleanup = tinyMCE.settings['cleanup_callback'];
		if (customCleanup != "" && eval("typeof(" + customCleanup + ")") != "undefined")
			content = eval(customCleanup + "(type, content, inst);");

		// Trigger theme cleanup
		po = tinyMCE.themes[tinyMCE.settings['theme']];
		if (po && po.cleanup)
			content = po.cleanup(type, content, inst);

		// Trigger plugin cleanups
		pl = inst.plugins;
		for (i=0; i<pl.length; i++) {
			po = tinyMCE.plugins[pl[i]];

			if (po && po.cleanup)
				content = po.cleanup(type, content, inst);
		}

		return content;
	},

	setContent : function(h) {
		if (tinyMCE.selectedInstance) {
			tinyMCE.selectedInstance.execCommand('mceSetContent', false, h);
			tinyMCE.selectedInstance.repaint();
		}
	},

	importThemeLanguagePack : function(name) {
		if (typeof(name) == "undefined")
			name = tinyMCE.settings['theme'];

		tinyMCE.loadScript(tinyMCE.baseURL + '/themes/' + name + '/langs/' + tinyMCE.settings['language'] + '.js');
	},

	importPluginLanguagePack : function(name) {
		var b = tinyMCE.baseURL + '/plugins/' + name;

		if (this.plugins[name])
			b = this.plugins[name].baseURL;

		tinyMCE.loadScript(b + '/langs/' + tinyMCE.settings['language'] +  '.js');
	},

	applyTemplate : function(h, as) {
		return h.replace(new RegExp('\\{\\$([a-z0-9_]+)\\}', 'gi'), function(m, s) {
			if (s.indexOf('lang_') == 0 && tinyMCELang[s])
				return tinyMCELang[s];

			if (as && as[s])
				return as[s];

			if (tinyMCE.settings[s])
				return tinyMCE.settings[s];

			if (m == 'themeurl')
				return tinyMCE.themeURL;

			return m;
		});
	},

	replaceVar : function(h, r, v) {
		return h.replace(new RegExp('{\\\$' + r + '}', 'g'), v);
	},

	openWindow : function(template, args) {
		var html, width, height, x, y, resizable, scrollbars, url;

		args = !args ? {} : args;

		args['mce_template_file'] = template['file'];
		args['mce_width'] = template['width'];
		args['mce_height'] = template['height'];
		tinyMCE.windowArgs = args;

		html = template['html'];
		if (!(width = parseInt(template['width'])))
			width = 320;

		if (!(height = parseInt(template['height'])))
			height = 200;

		// Add to height in M$ due to SP2 WHY DON'T YOU GUYS IMPLEMENT innerWidth of windows!!
		if (tinyMCE.isIE)
			height += 40;
		else
			height += 20;

		x = parseInt(screen.width / 2.0) - (width / 2.0);
		y = parseInt(screen.height / 2.0) - (height / 2.0);

		resizable = (args && args['resizable']) ? args['resizable'] : "no";
		scrollbars = (args && args['scrollbars']) ? args['scrollbars'] : "no";

		if (template['file'].charAt(0) != '/' && template['file'].indexOf('://') == -1)
			url = tinyMCE.baseURL + "/themes/" + tinyMCE.getParam("theme") + "/" + template['file'];
		else
			url = template['file'];

		// Replace all args as variables in URL
		for (var name in args) {
			if (typeof(args[name]) == 'function')
				continue;

			url = tinyMCE.replaceVar(url, name, escape(args[name]));
		}

		if (html) {
			html = tinyMCE.replaceVar(html, "css", this.settings['popups_css']);
			html = tinyMCE.applyTemplate(html, args);

			var win = window.open("", "mcePopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=yes,minimizable=" + resizable + ",modal=yes,width=" + width + ",height=" + height + ",resizable=" + resizable);
			if (win == null) {
				alert(tinyMCELang['lang_popup_blocked']);
				return;
			}

			win.document.write(html);
			win.document.close();
			win.resizeTo(width, height);
			win.focus();
		} else {
			if ((tinyMCE.isRealIE) && resizable != 'yes' && tinyMCE.settings["dialog_type"] == "modal") {
				height += 10;

				var features = "resizable:" + resizable 
					+ ";scroll:"
					+ scrollbars + ";status:yes;center:yes;help:no;dialogWidth:"
					+ width + "px;dialogHeight:" + height + "px;";

				window.showModalDialog(url, window, features);
			} else {
				var modal = (resizable == "yes") ? "no" : "yes";

				if (tinyMCE.isGecko && tinyMCE.isMac)
					modal = "no";

				if (template['close_previous'] != "no")
					try {tinyMCE.lastWindow.close();} catch (ex) {}

				var win = window.open(url, "mcePopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=" + modal + ",minimizable=" + resizable + ",modal=" + modal + ",width=" + width + ",height=" + height + ",resizable=" + resizable);
				if (win == null) {
					alert(tinyMCELang['lang_popup_blocked']);
					return;
				}

				if (template['close_previous'] != "no")
					tinyMCE.lastWindow = win;

				eval('try { win.resizeTo(width, height); } catch(e) { }');

				// Make it bigger if statusbar is forced
				if (tinyMCE.isGecko) {
					if (win.document.defaultView.statusbar.visible)
						win.resizeBy(0, tinyMCE.isMac ? 10 : 24);
				}

				win.focus();
			}
		}
	},

	closeWindow : function(win) {
		win.close();
	},

	getVisualAidClass : function(class_name, state) {
		var aidClass = tinyMCE.settings['visual_table_class'];

		if (typeof(state) == "undefined")
			state = tinyMCE.settings['visual'];

		// Split
		var classNames = new Array();
		var ar = class_name.split(' ');
		for (var i=0; i<ar.length; i++) {
			if (ar[i] == aidClass)
				ar[i] = "";

			if (ar[i] != "")
				classNames[classNames.length] = ar[i];
		}

		if (state)
			classNames[classNames.length] = aidClass;

		// Glue
		var className = "";
		for (var i=0; i<classNames.length; i++) {
			if (i > 0)
				className += " ";

			className += classNames[i];
		}

		return className;
	},

	handleVisualAid : function(el, deep, state, inst, skip_dispatch) {
		if (!el)
			return;

		if (!skip_dispatch)
			tinyMCE.dispatchCallback(inst, 'handle_visual_aid_callback', 'handleVisualAid', el, deep, state, inst);

		var tableElement = null;

		switch (el.nodeName) {
			case "TABLE":
				var oldW = el.style.width;
				var oldH = el.style.height;
				var bo = tinyMCE.getAttrib(el, "border");

				bo = bo == "" || bo == "0" ? true : false;

				tinyMCE.setAttrib(el, "class", tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el, "class"), state && bo));

				el.style.width = oldW;
				el.style.height = oldH;

				for (var y=0; y<el.rows.length; y++) {
					for (var x=0; x<el.rows[y].cells.length; x++) {
						var cn = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el.rows[y].cells[x], "class"), state && bo);
						tinyMCE.setAttrib(el.rows[y].cells[x], "class", cn);
					}
				}

				break;

			case "A":
				var anchorName = tinyMCE.getAttrib(el, "name");

				if (anchorName != '' && state) {
					el.title = anchorName;
					tinyMCE.addCSSClass(el, 'mceItemAnchor');
				} else if (anchorName != '' && !state)
					el.className = '';

				break;
		}

		if (deep && el.hasChildNodes()) {
			for (var i=0; i<el.childNodes.length; i++)
				tinyMCE.handleVisualAid(el.childNodes[i], deep, state, inst, true);
		}
	},

	/*
	applyClassesToFonts : function(doc, size) {
		var f = doc.getElementsByTagName("font");
		for (var i=0; i<f.length; i++) {
			var s = tinyMCE.getAttrib(f[i], "size");

			if (s != "")
				tinyMCE.setAttrib(f[i], 'class', "mceItemFont" + s);
		}

		if (typeof(size) != "undefined") {
			var css = "";

			for (var x=0; x<doc.styleSheets.length; x++) {
				for (var i=0; i<doc.styleSheets[x].rules.length; i++) {
					if (doc.styleSheets[x].rules[i].selectorText == '#mceSpanFonts .mceItemFont' + size) {
						css = doc.styleSheets[x].rules[i].style.cssText;
						break;
					}
				}

				if (css != "")
					break;
			}

			if (doc.styleSheets[0].rules[0].selectorText == "FONT")
				doc.styleSheets[0].removeRule(0);

			doc.styleSheets[0].addRule("FONT", css, 0);
		}
	},
	*/

	fixGeckoBaseHREFBug : function(m, e, h) {
		var xsrc, xhref;

		if (tinyMCE.isGecko) {
			if (m == 1) {
				h = h.replace(/\ssrc=/gi, " mce_tsrc=");
				h = h.replace(/\shref=/gi, " mce_thref=");

				return h;
			} else {
				// Why bother if there is no src or href broken
				if (!new RegExp('(src|href)=', 'g').test(h))
					return h;

				// Restore src and href that gets messed up by Gecko
				tinyMCE.selectElements(e, 'A,IMG,SELECT,AREA,IFRAME,BASE,INPUT,SCRIPT,EMBED,OBJECT,LINK', function (n) {
					xsrc = tinyMCE.getAttrib(n, "mce_tsrc");
					xhref = tinyMCE.getAttrib(n, "mce_thref");

					if (xsrc != "") {
						try {
							n.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xsrc);
						} catch (e) {
							// Ignore, Firefox cast exception if local file wasn't found
						}

						n.removeAttribute("mce_tsrc");
					}

					if (xhref != "") {
						try {
							n.href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xhref);
						} catch (e) {
							// Ignore, Firefox cast exception if local file wasn't found
						}

						n.removeAttribute("mce_thref");
					}

					return false;
				});

				// Restore text/comment nodes
				tinyMCE.selectNodes(e, function(n) {
					if (n.nodeType == 3 || n.nodeType == 8) {
						n.nodeValue = n.nodeValue.replace(/\smce_tsrc=/gi, " src=");
						n.nodeValue = n.nodeValue.replace(/\smce_thref=/gi, " href=");
					}

					return false;
				});
			}
		}

		return h;
	},

	_setHTML : function(doc, html_content) {
		// Force closed anchors open
		//html_content = html_content.replace(new RegExp('<a(.*?)/>', 'gi'), '<a$1></a>');

		html_content = tinyMCE.cleanupHTMLCode(html_content);

		// Try innerHTML if it fails use pasteHTML in MSIE
		try {
			tinyMCE.setInnerHTML(doc.body, html_content);
		} catch (e) {
			if (this.isMSIE)
				doc.body.createTextRange().pasteHTML(html_content);
		}

		// Content duplication bug fix
		if (tinyMCE.isIE && tinyMCE.settings['fix_content_duplication']) {
			// Remove P elements in P elements
			var paras = doc.getElementsByTagName("P");
			for (var i=0; i<paras.length; i++) {
				var node = paras[i];
				while ((node = node.parentNode) != null) {
					if (node.nodeName == "P")
						node.outerHTML = node.innerHTML;
				}
			}

			// Content duplication bug fix (Seems to be word crap)
			var html = doc.body.innerHTML;
/*
			if (html.indexOf('="mso') != -1) {
				for (var i=0; i<doc.body.all.length; i++) {
					var el = doc.body.all[i];
					el.removeAttribute("className","",0);
					el.removeAttribute("style","",0);
				}

				html = doc.body.innerHTML;
				html = tinyMCE.regexpReplace(html, "<o:p><\/o:p>", "<br />");
				html = tinyMCE.regexpReplace(html, "<o:p>&nbsp;<\/o:p>", "");
				html = tinyMCE.regexpReplace(html, "<st1:.*?>", "");
				html = tinyMCE.regexpReplace(html, "<p><\/p>", "");
				html = tinyMCE.regexpReplace(html, "<p><\/p>\r\n<p><\/p>", "");
				html = tinyMCE.regexpReplace(html, "<p>&nbsp;<\/p>", "<br />");
				html = tinyMCE.regexpReplace(html, "<p>\s*(<p>\s*)?", "<p>");
				html = tinyMCE.regexpReplace(html, "<\/p>\s*(<\/p>\s*)?", "</p>");
			}*/

			// Always set the htmlText output
			tinyMCE.setInnerHTML(doc.body, html);
		}

		tinyMCE.cleanupAnchors(doc);

		if (tinyMCE.getParam("convert_fonts_to_spans"))
			tinyMCE.convertSpansToFonts(doc);
	},

	getEditorId : function(form_element) {
		var inst = this.getInstanceById(form_element);
		if (!inst)
			return null;

		return inst.editorId;
	},

	getInstanceById : function(editor_id) {
		var inst = this.instances[editor_id];
		if (!inst) {
			for (var n in tinyMCE.instances) {
				var instance = tinyMCE.instances[n];
				if (!tinyMCE.isInstance(instance))
					continue;

				if (instance.formTargetElementId == editor_id) {
					inst = instance;
					break;
				}
			}
		}

		return inst;
	},

	queryInstanceCommandValue : function(editor_id, command) {
		var inst = tinyMCE.getInstanceById(editor_id);
		if (inst)
			return inst.queryCommandValue(command);

		return false;
	},

	queryInstanceCommandState : function(editor_id, command) {
		var inst = tinyMCE.getInstanceById(editor_id);
		if (inst)
			return inst.queryCommandState(command);

		return null;
	},

	setWindowArg : function(n, v) {
		this.windowArgs[n] = v;
	},

	getWindowArg : function(n, d) {
		return (typeof(this.windowArgs[n]) == "undefined") ? d : this.windowArgs[n];
	},

	getCSSClasses : function(editor_id, doc) {
		var output = new Array();

		// Is cached, use that
		if (typeof(tinyMCE.cssClasses) != "undefined")
			return tinyMCE.cssClasses;

		if (typeof(editor_id) == "undefined" && typeof(doc) == "undefined") {
			var instance;

			for (var instanceName in tinyMCE.instances) {
				instance = tinyMCE.instances[instanceName];
				if (!tinyMCE.isInstance(instance))
					continue;

				break;
			}

			doc = instance.getDoc();
		}

		if (typeof(doc) == "undefined") {
			var instance = tinyMCE.getInstanceById(editor_id);
			doc = instance.getDoc();
		}

		if (doc) {
			var styles = doc.styleSheets;

			if (styles && styles.length > 0) {
				for (var x=0; x<styles.length; x++) {
					var csses = null;

					// Just ignore any errors
					eval("try {var csses = tinyMCE.isIE ? doc.styleSheets(" + x + ").rules : styles[" + x + "].cssRules;} catch(e) {}");
					if (!csses)
						return new Array();

					for (var i=0; i<csses.length; i++) {
						var selectorText = csses[i].selectorText;

						// Can be multiple rules per selector
						if (selectorText) {
							var rules = selectorText.split(',');
							for (var c=0; c<rules.length; c++) {
								var rule = rules[c];

								// Strip spaces between selectors
								while (rule.indexOf(' ') == 0)
									rule = rule.substring(1);

								// Invalid rule
								if (rule.indexOf(' ') != -1 || rule.indexOf(':') != -1 || rule.indexOf('mceItem') != -1)
									continue;

								if (rule.indexOf(tinyMCE.settings['visual_table_class']) != -1 || rule.indexOf('mceEditable') != -1 || rule.indexOf('mceNonEditable') != -1)
									continue;

								// Is class rule
								if (rule.indexOf('.') != -1) {
									var cssClass = rule.substring(rule.indexOf('.') + 1);
									var addClass = true;

									for (var p=0; p<output.length && addClass; p++) {
										if (output[p] == cssClass)
											addClass = false;
									}

									if (addClass)
										output[output.length] = cssClass;
								}
							}
						}
					}
				}
			}
		}

		// Cache em
		if (output.length > 0)
			tinyMCE.cssClasses = output;

		return output;
	},

	regexpReplace : function(in_str, reg_exp, replace_str, opts) {
		if (in_str == null)
			return in_str;

		if (typeof(opts) == "undefined")
			opts = 'g';

		var re = new RegExp(reg_exp, opts);
		return in_str.replace(re, replace_str);
	},

	trim : function(s) {
		return s.replace(/^\s*|\s*$/g, "");
	},

	cleanupEventStr : function(s) {
		s = "" + s;
		s = s.replace('function anonymous()\n{\n', '');
		s = s.replace('\n}', '');
		s = s.replace(/^return true;/gi, ''); // Remove event blocker

		return s;
	},

	getControlHTML : function(c) {
		var i, l, n, o, v;

		l = tinyMCE.plugins;
		for (n in l) {
			o = l[n];

			if (o.getControlHTML && (v = o.getControlHTML(c)) != '')
				return tinyMCE.replaceVar(v, "pluginurl", o.baseURL);
		}

		o = tinyMCE.themes[tinyMCE.settings['theme']];
		if (o.getControlHTML && (v = o.getControlHTML(c)) != '')
			return v;

		return '';
	},

	evalFunc : function(f, idx, a, o) {
		o = !o ? window : o;
		f = typeof(f) == 'function' ? f : o[f];

		return f.apply(o, Array.prototype.slice.call(a, idx));
	},

	dispatchCallback : function(i, p, n) {
		return this.callFunc(i, p, n, 0, this.dispatchCallback.arguments);
	},

	executeCallback : function(i, p, n) {
		return this.callFunc(i, p, n, 1, this.executeCallback.arguments);
	},

	execCommandCallback : function(i, p, n) {
		return this.callFunc(i, p, n, 2, this.execCommandCallback.arguments);
	},

	callFunc : function(ins, p, n, m, a) {
		var l, i, on, o, s, v;

		s = m == 2;

		l = tinyMCE.getParam(p, '');

		if (l != '' && (v = tinyMCE.evalFunc(l, 3, a)) == s && m > 0)
			return true;

		if (ins != null) {
			for (i=0, l = ins.plugins; i<l.length; i++) {
				o = tinyMCE.plugins[l[i]];

				if (o[n] && (v = tinyMCE.evalFunc(n, 3, a, o)) == s && m > 0)
					return true;
			}
		}

		l = tinyMCE.themes;
		for (on in l) {
			o = l[on];

			if (o[n] && (v = tinyMCE.evalFunc(n, 3, a, o)) == s && m > 0)
				return true;
		}

		return false;
	},

	xmlEncode : function(s, skip_apos) {
		return s ? ('' + s).replace(!skip_apos ? this.xmlEncodeAposRe : this.xmlEncodeRe, function (c, b) {
			switch (c) {
				case '&':
					return '&amp;';

				case '"':
					return '&quot;';

				case '\'':
					return '&#39;'; // &apos; is not working in MSIE

				case '<':
					return '&lt;';

				case '>':
					return '&gt;';
			}

			return c;
		}) : s;
	},

	extend : function(p, np) {
		var o = {};

		o.parent = p;

		for (n in p)
			o[n] = p[n];

		for (n in np)
			o[n] = np[n];

		return o;
	},

	hideMenus : function() {
		var e = tinyMCE.lastSelectedMenuBtn;

		if (tinyMCE.lastMenu) {
			tinyMCE.lastMenu.hide();
			tinyMCE.lastMenu = null;
		}

		if (e) {
			tinyMCE.switchClass(e, tinyMCE.lastMenuBtnClass);
			tinyMCE.lastSelectedMenuBtn = null;
		}
	}

	};

// Global instances
var TinyMCE = TinyMCE_Engine; // Compatiblity with gzip compressors
var tinyMCE = new TinyMCE_Engine();
var tinyMCELang = {};

/* file:jscripts/tiny_mce/classes/TinyMCE_Control.class.js */

function TinyMCE_Control(settings) {
	var t, i, to, fu, p, x, fn, fu, pn, s = settings;

	this.undoRedoLevel = true;
	this.isTinyMCE_Control = true;

	// Default settings
	this.settings = s;
	this.settings['theme'] = tinyMCE.getParam("theme", "default");
	this.settings['width'] = tinyMCE.getParam("width", -1);
	this.settings['height'] = tinyMCE.getParam("height", -1);
	this.selection = new TinyMCE_Selection(this);
	this.undoRedo = new TinyMCE_UndoRedo(this);
	this.cleanup = new TinyMCE_Cleanup();
	this.shortcuts = new Array();
	this.hasMouseMoved = false;
	this.foreColor = this.backColor = "#999999";
	this.data = {};

	this.cleanup.init({
		valid_elements : s.valid_elements,
		extended_valid_elements : s.extended_valid_elements,
		valid_child_elements : s.valid_child_elements,
		entities : s.entities,
		entity_encoding : s.entity_encoding,
		debug : s.cleanup_debug,
		indent : s.apply_source_formatting,
		invalid_elements : s.invalid_elements,
		verify_html : s.verify_html,
		fix_content_duplication : s.fix_content_duplication,
		convert_fonts_to_spans : s.convert_fonts_to_spans
	});

	// Wrap old theme
	t = this.settings['theme'];
	if (!tinyMCE.hasTheme(t)) {
		fn = tinyMCE.callbacks;
		to = {};

		for (i=0; i<fn.length; i++) {
			if ((fu = window['TinyMCE_' + t + "_" + fn[i]]))
				to[fn[i]] = fu;
		}

		tinyMCE.addTheme(t, to);
	}

	// Wrap old plugins
	this.plugins = new Array();
	p = tinyMCE.getParam('plugins', '', true, ',');
	if (p.length > 0) {
		for (i=0; i<p.length; i++) {
			pn = p[i];

			if (pn.charAt(0) == '-')
				pn = pn.substring(1);

			if (!tinyMCE.hasPlugin(pn)) {
				fn = tinyMCE.callbacks;
				to = {};

				for (x=0; x<fn.length; x++) {
					if ((fu = window['TinyMCE_' + pn + "_" + fn[x]]))
						to[fn[x]] = fu;
				}

				tinyMCE.addPlugin(pn, to);
			}

			this.plugins[this.plugins.length] = pn; 
		}
	}
};

TinyMCE_Control.prototype = {
	selection : null,

	settings : null,

	cleanup : null,

	getData : function(na) {
		var o = this.data[na];

		if (!o)
			o = this.data[na] = {};

		return o;
	},

	hasPlugin : function(n) {
		var i;

		for (i=0; i<this.plugins.length; i++) {
			if (this.plugins[i] == n)
				return true;
		}

		return false;
	},

	addPlugin : function(n, p) {
		if (!this.hasPlugin(n)) {
			tinyMCE.addPlugin(n, p);
			this.plugins[this.plugins.length] = n;
		}
	},

	repaint : function() {
		var s, b, ex;

		if (tinyMCE.isRealIE)
			return;

		try {
			s = this.selection;
			b = s.getBookmark(true);
			this.getBody().style.display = 'none';
			this.getDoc().execCommand('selectall', false, null);
			this.getSel().collapseToStart();
			this.getBody().style.display = 'block';
			s.moveToBookmark(b);
		} catch (ex) {
			// Ignore
		}
	},

	switchSettings : function() {
		if (tinyMCE.configs.length > 1 && tinyMCE.currentConfig != this.settings['index']) {
			tinyMCE.settings = this.settings;
			tinyMCE.currentConfig = this.settings['index'];
		}
	},

	select : function() {
		var oldInst = tinyMCE.selectedInstance;

		if (oldInst != this) {
			if (oldInst)
				oldInst.execCommand('mceEndTyping');

			tinyMCE.dispatchCallback(this, 'select_instance_callback', 'selectInstance', this, oldInst);
			tinyMCE.selectedInstance = this;
		}
	},

	getBody : function() {
		return this.contentBody ? this.contentBody : this.getDoc().body;
	},

	getDoc : function() {
//		return this.contentDocument ? this.contentDocument : this.contentWindow.document; // Removed due to IE 5.5 ?
		return this.contentWindow.document;
	},

	getWin : function() {
		return this.contentWindow;
	},

	getContainerWin : function() {
		return this.containerWindow ? this.containerWindow : window;
	},

	getViewPort : function() {
		return tinyMCE.getViewPort(this.getWin());
	},

	getParentNode : function(n, f) {
		return tinyMCE.getParentNode(n, f, this.getBody());
	},

	getParentElement : function(n, na, f) {
		return tinyMCE.getParentElement(n, na, f, this.getBody());
	},

	getParentBlockElement : function(n) {
		return tinyMCE.getParentBlockElement(n, this.getBody());
	},

	resizeToContent : function() {
		var d = this.getDoc(), b = d.body, de = d.documentElement;

		this.iframeElement.style.height = (tinyMCE.isRealIE) ? b.scrollHeight : de.offsetHeight + 'px';
	},

	addShortcut : function(m, k, d, cmd, ui, va) {
		var n = typeof(k) == "number", ie = tinyMCE.isIE, c, sc, i, scl = this.shortcuts;

		if (!tinyMCE.getParam('custom_shortcuts'))
			return false;

		m = m.toLowerCase();
		k = ie && !n ? k.toUpperCase() : k;
		c = n ? null : k.charCodeAt(0);
		d = d && d.indexOf('lang_') == 0 ? tinyMCE.getLang(d) : d;

		sc = {
			alt : m.indexOf('alt') != -1,
			ctrl : m.indexOf('ctrl') != -1,
			shift : m.indexOf('shift') != -1,
			charCode : c,
			keyCode : n ? k : (ie ? c : null),
			desc : d,
			cmd : cmd,
			ui : ui,
			val : va
		};

		for (i=0; i<scl.length; i++) {
			if (sc.alt == scl[i].alt && sc.ctrl == scl[i].ctrl && sc.shift == scl[i].shift
				&& sc.charCode == scl[i].charCode && sc.keyCode == scl[i].keyCode) {
				return false;
			}
		}

		scl[scl.length] = sc;

		return true;
	},

	handleShortcut : function(e) {
		var i, s, o;

		// Normal key press, then ignore it
		if (!e.altKey && !e.ctrlKey)
			return false;

		s = this.shortcuts;

		for (i=0; i<s.length; i++) {
			o = s[i];

			if (o.alt == e.altKey && o.ctrl == e.ctrlKey && (o.keyCode == e.keyCode || o.charCode == e.charCode)) {
				if (o.cmd && (e.type == "keydown" || (e.type == "keypress" && !tinyMCE.isOpera)))
					tinyMCE.execCommand(o.cmd, o.ui, o.val);

				tinyMCE.cancelEvent(e);
				return true;
			}
		}

		return false;
	},

	autoResetDesignMode : function() {
		// Add fix for tab/style.display none/block problems in Gecko
		if (!tinyMCE.isIE && this.isHidden() && tinyMCE.getParam('auto_reset_designmode'))
			eval('try { this.getDoc().designMode = "On"; this.useCSS = false; } catch(e) {}');
	},

	isHidden : function() {
		var s;

		if (tinyMCE.isIE)
			return false;

		s = this.getSel();

		// Weird, wheres that cursor selection?
		return (!s || !s.rangeCount || s.rangeCount == 0);
	},

	isDirty : function() {
		// Is content modified and not in a submit procedure
		return tinyMCE.trim(this.startContent) != tinyMCE.trim(this.getBody().innerHTML) && !tinyMCE.isNotDirty;
	},

	_mergeElements : function(scmd, pa, ch, override) {
		if (scmd == "removeformat") {
			pa.className = "";
			pa.style.cssText = "";
			ch.className = "";
			ch.style.cssText = "";
			return;
		}

		var st = tinyMCE.parseStyle(tinyMCE.getAttrib(pa, "style"));
		var stc = tinyMCE.parseStyle(tinyMCE.getAttrib(ch, "style"));
		var className = tinyMCE.getAttrib(pa, "class");

		// Removed class adding due to bug #1478272
		className = tinyMCE.getAttrib(ch, "class");

		if (override) {
			for (var n in st) {
				if (typeof(st[n]) == 'function')
					continue;

				stc[n] = st[n];
			}
		} else {
			for (var n in stc) {
				if (typeof(stc[n]) == 'function')
					continue;

				st[n] = stc[n];
			}
		}

		tinyMCE.setAttrib(pa, "style", tinyMCE.serializeStyle(st));
		tinyMCE.setAttrib(pa, "class", tinyMCE.trim(className));
		ch.className = "";
		ch.style.cssText = "";
		ch.removeAttribute("class");
		ch.removeAttribute("style");
	},

	_setUseCSS : function(b) {
		var d = this.getDoc();

		try {d.execCommand("useCSS", false, !b);} catch (ex) {}
		try {d.execCommand("styleWithCSS", false, b);} catch (ex) {}

		if (!tinyMCE.getParam("table_inline_editing"))
			try {d.execCommand('enableInlineTableEditing', false, "false");} catch (ex) {}

		if (!tinyMCE.getParam("object_resizing"))
			try {d.execCommand('enableObjectResizing', false, "false");} catch (ex) {}
	},

	execCommand : function(command, user_interface, value) {
		var doc = this.getDoc(), win = this.getWin(), focusElm = this.getFocusElement();

		// Is not a undo specific command
		if (!new RegExp('mceStartTyping|mceEndTyping|mceBeginUndoLevel|mceEndUndoLevel|mceAddUndoLevel', 'gi').test(command))
			this.undoBookmark = null;

		// Mozilla issue
		if (!tinyMCE.isIE && !this.useCSS) {
			this._setUseCSS(false);
			this.useCSS = true;
		}

		//debug("command: " + command + ", user_interface: " + user_interface + ", value: " + value);
		this.contentDocument = doc; // <-- Strange, unless this is applied Mozilla 1.3 breaks

		// Don't dispatch key commands
		if (!/mceStartTyping|mceEndTyping/.test(command)) {
			if (tinyMCE.execCommandCallback(this, 'execcommand_callback', 'execCommand', this.editorId, this.getBody(), command, user_interface, value))
				return;
		}

		// Fix align on images
		if (focusElm && focusElm.nodeName == "IMG") {
			var align = focusElm.getAttribute('align');
			var img = command == "JustifyCenter" ? focusElm.cloneNode(false) : focusElm;

			switch (command) {
				case "JustifyLeft":
					if (align == 'left')
						img.removeAttribute('align');
					else
						img.setAttribute('align', 'left');

					// Remove the div
					var div = focusElm.parentNode;
					if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
						div.parentNode.replaceChild(img, div);

					this.selection.selectNode(img);
					this.repaint();
					tinyMCE.triggerNodeChange();
					return;

				case "JustifyCenter":
					img.removeAttribute('align');

					// Is centered
					var div = tinyMCE.getParentElement(focusElm, "div");
					if (div && div.style.textAlign == "center") {
						// Remove div
						if (div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
							div.parentNode.replaceChild(img, div);
					} else {
						// Add div
						var div = this.getDoc().createElement("div");
						div.style.textAlign = 'center';
						div.appendChild(img);
						focusElm.parentNode.replaceChild(div, focusElm);
					}

					this.selection.selectNode(img);
					this.repaint();
					tinyMCE.triggerNodeChange();
					return;

				case "JustifyRight":
					if (align == 'right')
						img.removeAttribute('align');
					else
						img.setAttribute('align', 'right');

					// Remove the div
					var div = focusElm.parentNode;
					if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
						div.parentNode.replaceChild(img, div);

					this.selection.selectNode(img);
					this.repaint();
					tinyMCE.triggerNodeChange();
					return;
			}
		}

		if (tinyMCE.settings['force_br_newlines']) {
			var alignValue = "";

			if (doc.selection.type != "Control") {
				switch (command) {
						case "JustifyLeft":
							alignValue = "left";
							break;

						case "JustifyCenter":
							alignValue = "center";
							break;

						case "JustifyFull":
							alignValue = "justify";
							break;

						case "JustifyRight":
							alignValue = "right";
							break;
				}

				if (alignValue != "") {
					var rng = doc.selection.createRange();

					if ((divElm = tinyMCE.getParentElement(rng.parentElement(), "div")) != null)
						divElm.setAttribute("align", alignValue);
					else if (rng.pasteHTML && rng.htmlText.length > 0)
						rng.pasteHTML('<div align="' + alignValue + '">' + rng.htmlText + "</div>");

					tinyMCE.triggerNodeChange();
					return;
				}
			}
		}

		switch (command) {
			case "mceRepaint":
				this.repaint();
				return true;

			case "unlink":
				// Unlink if caret is inside link
				if (tinyMCE.isGecko && this.getSel().isCollapsed) {
					focusElm = tinyMCE.getParentElement(focusElm, 'A');

					if (focusElm)
						this.selection.selectNode(focusElm, false);
				}

				this.getDoc().execCommand(command, user_interface, value);

				tinyMCE.isGecko && this.getSel().collapseToEnd();

				tinyMCE.triggerNodeChange();

				return true;

			case "InsertUnorderedList":
			case "InsertOrderedList":
				this.getDoc().execCommand(command, user_interface, value);
				tinyMCE.triggerNodeChange();
				break;

			case "Strikethrough":
				this.getDoc().execCommand(command, user_interface, value);
				tinyMCE.triggerNodeChange();
				break;

			case "mceSelectNode":
				this.selection.selectNode(value);
				tinyMCE.triggerNodeChange();
				tinyMCE.selectedNode = value;
				break;

			case "FormatBlock":
				if (value == null || value == "") {
					var elm = tinyMCE.getParentElement(this.getFocusElement(), "p,div,h1,h2,h3,h4,h5,h6,pre,address,blockquote,dt,dl,dd,samp");

					if (elm)
						this.execCommand("mceRemoveNode", false, elm);
				} else {
					if (!this.cleanup.isValid(value))
						return true;

					if (tinyMCE.isGecko && new RegExp('<(div|blockquote|code|dt|dd|dl|samp)>', 'gi').test(value))
						value = value.replace(/[^a-z]/gi, '');

					if (tinyMCE.isIE && new RegExp('blockquote|code|samp', 'gi').test(value)) {
						var b = this.selection.getBookmark();
						this.getDoc().execCommand("FormatBlock", false, '<p>');
						tinyMCE.renameElement(tinyMCE.getParentBlockElement(this.getFocusElement()), value);
						this.selection.moveToBookmark(b);
					} else
						this.getDoc().execCommand("FormatBlock", false, value);
				}

				tinyMCE.triggerNodeChange();

				break;

			case "mceRemoveNode":
				if (!value)
					value = tinyMCE.getParentElement(this.getFocusElement());

				if (tinyMCE.isIE) {
					value.outerHTML = value.innerHTML;
				} else {
					var rng = value.ownerDocument.createRange();
					rng.setStartBefore(value);
					rng.setEndAfter(value);
					rng.deleteContents();
					rng.insertNode(rng.createContextualFragment(value.innerHTML));
				}

				tinyMCE.triggerNodeChange();

				break;

			case "mceSelectNodeDepth":
				var parentNode = this.getFocusElement();
				for (var i=0; parentNode; i++) {
					if (parentNode.nodeName.toLowerCase() == "body")
						break;

					if (parentNode.nodeName.toLowerCase() == "#text") {
						i--;
						parentNode = parentNode.parentNode;
						continue;
					}

					if (i == value) {
						this.selection.selectNode(parentNode, false);
						tinyMCE.triggerNodeChange();
						tinyMCE.selectedNode = parentNode;
						return;
					}

					parentNode = parentNode.parentNode;
				}

				break;

			case "mceSetStyleInfo":
			case "SetStyleInfo":
				var rng = this.getRng();
				var sel = this.getSel();
				var scmd = value['command'];
				var sname = value['name'];
				var svalue = value['value'] == null ? '' : value['value'];
				//var svalue = value['value'] == null ? '' : value['value'];
				var wrapper = value['wrapper'] ? value['wrapper'] : "span";
				var parentElm = null;
				var invalidRe = new RegExp("^BODY|HTML$", "g");
				var invalidParentsRe = tinyMCE.settings['merge_styles_invalid_parents'] != '' ? new RegExp(tinyMCE.settings['merge_styles_invalid_parents'], "gi") : null;

				// Whole element selected check
				if (tinyMCE.isIE) {
					// Control range
					if (rng.item)
						parentElm = rng.item(0);
					else {
						var pelm = rng.parentElement();
						var prng = doc.selection.createRange();
						prng.moveToElementText(pelm);

						if (rng.htmlText == prng.htmlText || rng.boundingWidth == 0) {
							if (invalidParentsRe == null || !invalidParentsRe.test(pelm.nodeName))
								parentElm = pelm;
						}
					}
				} else {
					var felm = this.getFocusElement();
					if (sel.isCollapsed || (new RegExp('td|tr|tbody|table', 'gi').test(felm.nodeName) && sel.anchorNode == felm.parentNode))
						parentElm = felm;
				}

				// Whole element selected
				if (parentElm && !invalidRe.test(parentElm.nodeName)) {
					if (scmd == "setstyle")
						tinyMCE.setStyleAttrib(parentElm, sname, svalue);

					if (scmd == "setattrib")
						tinyMCE.setAttrib(parentElm, sname, svalue);

					if (scmd == "removeformat") {
						parentElm.style.cssText = '';
						tinyMCE.setAttrib(parentElm, 'class', '');
					}

					// Remove style/attribs from all children
					var ch = tinyMCE.getNodeTree(parentElm, new Array(), 1);
					for (var z=0; z<ch.length; z++) {
						if (ch[z] == parentElm)
							continue;

						if (scmd == "setstyle")
							tinyMCE.setStyleAttrib(ch[z], sname, '');

						if (scmd == "setattrib")
							tinyMCE.setAttrib(ch[z], sname, '');

						if (scmd == "removeformat") {
							ch[z].style.cssText = '';
							tinyMCE.setAttrib(ch[z], 'class', '');
						}
					}
				} else {
					this._setUseCSS(false); // Bug in FF when running in fullscreen
					doc.execCommand("FontName", false, "#mce_temp_font#");
					var elementArray = tinyMCE.getElementsByAttributeValue(this.getBody(), "font", "face", "#mce_temp_font#");

					// Change them all
					for (var x=0; x<elementArray.length; x++) {
						elm = elementArray[x];
						if (elm) {
							var spanElm = doc.createElement(wrapper);

							if (scmd == "setstyle")
								tinyMCE.setStyleAttrib(spanElm, sname, svalue);

							if (scmd == "setattrib")
								tinyMCE.setAttrib(spanElm, sname, svalue);

							if (scmd == "removeformat") {
								spanElm.style.cssText = '';
								tinyMCE.setAttrib(spanElm, 'class', '');
							}

							if (elm.hasChildNodes()) {
								for (var i=0; i<elm.childNodes.length; i++)
									spanElm.appendChild(elm.childNodes[i].cloneNode(true));
							}

							spanElm.setAttribute("mce_new", "true");
							elm.parentNode.replaceChild(spanElm, elm);

							// Remove style/attribs from all children
							var ch = tinyMCE.getNodeTree(spanElm, new Array(), 1);
							for (var z=0; z<ch.length; z++) {
								if (ch[z] == spanElm)
									continue;

								if (scmd == "setstyle")
									tinyMCE.setStyleAttrib(ch[z], sname, '');

								if (scmd == "setattrib")
									tinyMCE.setAttrib(ch[z], sname, '');

								if (scmd == "removeformat") {
									ch[z].style.cssText = '';
									tinyMCE.setAttrib(ch[z], 'class', '');
								}
							}
						}
					}
				}

				// Cleaup wrappers
				var nodes = doc.getElementsByTagName(wrapper);
				for (var i=nodes.length-1; i>=0; i--) {
					var elm = nodes[i];
					var isNew = tinyMCE.getAttrib(elm, "mce_new") == "true";

					elm.removeAttribute("mce_new");

					// Is only child a element
					if (elm.childNodes && elm.childNodes.length == 1 && elm.childNodes[0].nodeType == 1) {
						//tinyMCE.debug("merge1" + isNew);
						this._mergeElements(scmd, elm, elm.childNodes[0], isNew);
						continue;
					}

					// Is I the only child
					if (elm.parentNode.childNodes.length == 1 && !invalidRe.test(elm.nodeName) && !invalidRe.test(elm.parentNode.nodeName)) {
						//tinyMCE.debug("merge2" + isNew + "," + elm.nodeName + "," + elm.parentNode.nodeName);
						if (invalidParentsRe == null || !invalidParentsRe.test(elm.parentNode.nodeName))
							this._mergeElements(scmd, elm.parentNode, elm, false);
					}
				}

				// Remove empty wrappers
				var nodes = doc.getElementsByTagName(wrapper);
				for (var i=nodes.length-1; i>=0; i--) {
					var elm = nodes[i];
					var isEmpty = true;

					// Check if it has any attribs
					var tmp = doc.createElement("body");
					tmp.appendChild(elm.cloneNode(false));

					// Is empty span, remove it
					tmp.innerHTML = tmp.innerHTML.replace(new RegExp('style=""|class=""', 'gi'), '');
					//tinyMCE.debug(tmp.innerHTML);
					if (new RegExp('<span>', 'gi').test(tmp.innerHTML)) {
						for (var x=0; x<elm.childNodes.length; x++) {
							if (elm.parentNode != null)
								elm.parentNode.insertBefore(elm.childNodes[x].cloneNode(true), elm);
						}

						elm.parentNode.removeChild(elm);
					}
				}

				// Re add the visual aids
				if (scmd == "removeformat")
					tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);

				tinyMCE.triggerNodeChange();

				break;

			case "FontName":
				if (value == null) {
					var s = this.getSel();

					// Find font and select it
					if (tinyMCE.isGecko && s.isCollapsed) {
						var f = tinyMCE.getParentElement(this.getFocusElement(), "font");

						if (f != null)
							this.selection.selectNode(f, false);
					}

					// Remove format
					this.getDoc().execCommand("RemoveFormat", false, null);

					// Collapse range if font was found
					if (f != null && tinyMCE.isGecko) {
						var r = this.getRng().cloneRange();
						r.collapse(true);
						s.removeAllRanges();
						s.addRange(r);
					}
				} else
					this.getDoc().execCommand('FontName', false, value);

				if (tinyMCE.isGecko)
					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);

				return;

			case "FontSize":
				this.getDoc().execCommand('FontSize', false, value);

				if (tinyMCE.isGecko)
					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);

				return;

			case "forecolor":
				value = value == null ? this.foreColor : value;
				value = tinyMCE.trim(value);
				value = value.charAt(0) != '#' ? (isNaN('0x' + value) ? value : '#' + value) : value;

				this.foreColor = value;
				this.getDoc().execCommand('forecolor', false, value);
				break;

			case "HiliteColor":
				value = value == null ? this.backColor : value;
				value = tinyMCE.trim(value);
				value = value.charAt(0) != '#' ? (isNaN('0x' + value) ? value : '#' + value) : value;
				this.backColor = value;

				if (tinyMCE.isGecko) {
					this._setUseCSS(true);
					this.getDoc().execCommand('hilitecolor', false, value);
					this._setUseCSS(false);
				} else
					this.getDoc().execCommand('BackColor', false, value);
				break;

			case "Cut":
			case "Copy":
			case "Paste":
				var cmdFailed = false;

				// Try executing command
				eval('try {this.getDoc().execCommand(command, user_interface, value);} catch (e) {cmdFailed = true;}');

				if (tinyMCE.isOpera && cmdFailed)
					alert('Currently not supported by your browser, use keyboard shortcuts instead.');

				// Alert error in gecko if command failed
				if (tinyMCE.isGecko && cmdFailed) {
					// Confirm more info
					if (confirm(tinyMCE.entityDecode(tinyMCE.getLang('lang_clipboard_msg'))))
						window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', 'mceExternal');

					return;
				} else
					tinyMCE.triggerNodeChange();
			break;

			case "mceSetContent":
				if (!value)
					value = "";

				// Call custom cleanup code
				value = tinyMCE.storeAwayURLs(value);
				value = tinyMCE._customCleanup(this, "insert_to_editor", value);

				if (this.getBody().nodeName == 'BODY')
					tinyMCE._setHTML(doc, value);
				else
					this.getBody().innerHTML = value;

				tinyMCE.setInnerHTML(this.getBody(), tinyMCE._cleanupHTML(this, doc, this.settings, this.getBody(), false, false, false, true));
				tinyMCE.convertAllRelativeURLs(this.getBody());

				// Cleanup any mess left from storyAwayURLs
				tinyMCE._removeInternal(this.getBody());

				// When editing always use fonts internaly
				if (tinyMCE.getParam("convert_fonts_to_spans"))
					tinyMCE.convertSpansToFonts(doc);

				tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
				tinyMCE._setEventsEnabled(this.getBody(), false);
				return true;

			case "mceCleanup":
				var b = this.selection.getBookmark();
				tinyMCE._setHTML(this.contentDocument, this.getBody().innerHTML);
				tinyMCE.setInnerHTML(this.getBody(), tinyMCE._cleanupHTML(this, this.contentDocument, this.settings, this.getBody(), this.visualAid));
				tinyMCE.convertAllRelativeURLs(doc.body);

				// When editing always use fonts internaly
				if (tinyMCE.getParam("convert_fonts_to_spans"))
					tinyMCE.convertSpansToFonts(doc);

				tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
				tinyMCE._setEventsEnabled(this.getBody(), false);
				this.repaint();
				this.selection.moveToBookmark(b);
				tinyMCE.triggerNodeChange();
			break;

			case "mceReplaceContent":
				// Force empty string
				if (!value)
					value = '';

				this.getWin().focus();

				var selectedText = "";

				if (tinyMCE.isIE) {
					var rng = doc.selection.createRange();
					selectedText = rng.text;
				} else
					selectedText = this.getSel().toString();

				if (selectedText.length > 0) {
					value = tinyMCE.replaceVar(value, "selection", selectedText);
					tinyMCE.execCommand('mceInsertContent', false, value);
				}

				tinyMCE.triggerNodeChange();
			break;

			case "mceSetAttribute":
				if (typeof(value) == 'object') {
					var targetElms = (typeof(value['targets']) == "undefined") ? "p,img,span,div,td,h1,h2,h3,h4,h5,h6,pre,address" : value['targets'];
					var targetNode = tinyMCE.getParentElement(this.getFocusElement(), targetElms);

					if (targetNode) {
						targetNode.setAttribute(value['name'], value['value']);
						tinyMCE.triggerNodeChange();
					}
				}
			break;

			case "mceSetCSSClass":
				this.execCommand("mceSetStyleInfo", false, {command : "setattrib", name : "class", value : value});
			break;

			case "mceInsertRawHTML":
				var key = 'tiny_mce_marker';

				this.execCommand('mceBeginUndoLevel');

				// Insert marker key
				this.execCommand('mceInsertContent', false, key);

				// Store away scroll pos
				var scrollX = this.getBody().scrollLeft + this.getDoc().documentElement.scrollLeft;
				var scrollY = this.getBody().scrollTop + this.getDoc().documentElement.scrollTop;

				// Find marker and replace with RAW HTML
				var html = this.getBody().innerHTML;
				if ((pos = html.indexOf(key)) != -1)
					tinyMCE.setInnerHTML(this.getBody(), html.substring(0, pos) + value + html.substring(pos + key.length));

				// Restore scoll pos
				this.contentWindow.scrollTo(scrollX, scrollY);

				this.execCommand('mceEndUndoLevel');

				break;

			case "mceInsertContent":
				// Force empty string
				if (!value)
					value = '';

				var insertHTMLFailed = false;

				// Removed since it produced problems in IE
				// this.getWin().focus();

				if (tinyMCE.isGecko || tinyMCE.isOpera) {
					try {
						// Is plain text or HTML, &amp;, &nbsp; etc will be encoded wrong in FF
						if (value.indexOf('<') == -1 && !value.match(/(&#38;|&#160;|&#60;|&#62;)/g)) {
							var r = this.getRng();
							var n = this.getDoc().createTextNode(tinyMCE.entityDecode(value));
							var s = this.getSel();
							var r2 = r.cloneRange();

							// Insert text at cursor position
							s.removeAllRanges();
							r.deleteContents();
							r.insertNode(n);

							// Move the cursor to the end of text
							r2.selectNode(n);
							r2.collapse(false);
							s.removeAllRanges();
							s.addRange(r2);
						} else {
							value = tinyMCE.fixGeckoBaseHREFBug(1, this.getDoc(), value);
							this.getDoc().execCommand('inserthtml', false, value);
							tinyMCE.fixGeckoBaseHREFBug(2, this.getDoc(), value);
						}
					} catch (ex) {
						insertHTMLFailed = true;
					}

					if (!insertHTMLFailed) {
						tinyMCE.triggerNodeChange();
						return;
					}
				}

				if (!tinyMCE.isIE) {
					var isHTML = value.indexOf('<') != -1;
					var sel = this.getSel();
					var rng = this.getRng();

					if (isHTML) {
						if (tinyMCE.isSafari) {
							var tmpRng = this.getDoc().createRange();

							tmpRng.setStart(this.getBody(), 0);
							tmpRng.setEnd(this.getBody(), 0);

							value = tmpRng.createContextualFragment(value);
						} else
							value = rng.createContextualFragment(value);
					} else {
						// Setup text node
						var el = document.createElement("div");
						el.innerHTML = value;
						value = el.firstChild.nodeValue;
						value = doc.createTextNode(value);
					}

					// Insert plain text in Safari
					if (tinyMCE.isSafari && !isHTML) {
						this.execCommand('InsertText', false, value.nodeValue);
						tinyMCE.triggerNodeChange();
						return true;
					} else if (tinyMCE.isSafari && isHTML) {
						rng.deleteContents();
						rng.insertNode(value);
						tinyMCE.triggerNodeChange();
						return true;
					}

					rng.deleteContents();

					// If target node is text do special treatment, (Mozilla 1.3 fix)
					if (rng.startContainer.nodeType == 3) {
						var node = rng.startContainer.splitText(rng.startOffset);
						node.parentNode.insertBefore(value, node); 
					} else
						rng.insertNode(value);

					if (!isHTML) {
						// Removes weird selection trails
						sel.selectAllChildren(doc.body);
						sel.removeAllRanges();

						// Move cursor to end of content
						var rng = doc.createRange();

						rng.selectNode(value);
						rng.collapse(false);

						sel.addRange(rng);
					} else
						rng.collapse(false);

					tinyMCE.fixGeckoBaseHREFBug(2, this.getDoc(), value);
				} else {
					var rng = doc.selection.createRange(), tmpRng = null;
					var c = value.indexOf('<!--') != -1;

					// Fix comment bug, add tag before comments
					if (c)
						value = tinyMCE.uniqueTag + value;

					//	tmpRng = rng.duplicate(); // Store away range (Fixes Undo bookmark bug in IE)

					if (rng.item)
						rng.item(0).outerHTML = value;
					else
						rng.pasteHTML(value);

					//if (tmpRng)
					//	tmpRng.select(); // Restore range  (Fixes Undo bookmark bug in IE)

					// Remove unique tag
					if (c) {
						var e = this.getDoc().getElementById('mceTMPElement');
						e.parentNode.removeChild(e);
					}
				}

				tinyMCE.execCommand("mceAddUndoLevel");
				tinyMCE.triggerNodeChange();
			break;

			case "mceStartTyping":
				if (tinyMCE.settings['custom_undo_redo'] && this.undoRedo.typingUndoIndex == -1) {
					this.undoRedo.typingUndoIndex = this.undoRedo.undoIndex;
					tinyMCE.typingUndoIndex = tinyMCE.undoIndex;
					this.execCommand('mceAddUndoLevel');
				}
				break;

			case "mceEndTyping":
				if (tinyMCE.settings['custom_undo_redo'] && this.undoRedo.typingUndoIndex != -1) {
					this.execCommand('mceAddUndoLevel');
					this.undoRedo.typingUndoIndex = -1;
				}

				tinyMCE.typingUndoIndex = -1;
				break;

			case "mceBeginUndoLevel":
				this.undoRedoLevel = false;
				break;

			case "mceEndUndoLevel":
				this.undoRedoLevel = true;
				this.execCommand('mceAddUndoLevel');
				break;

			case "mceAddUndoLevel":
				if (tinyMCE.settings['custom_undo_redo'] && this.undoRedoLevel) {
					if (this.undoRedo.add())
						tinyMCE.triggerNodeChange(false);
				}
				break;

			case "Undo":
				if (tinyMCE.settings['custom_undo_redo']) {
					tinyMCE.execCommand("mceEndTyping");
					this.undoRedo.undo();
					tinyMCE.triggerNodeChange();
				} else
					this.getDoc().execCommand(command, user_interface, value);
				break;

			case "Redo":
				if (tinyMCE.settings['custom_undo_redo']) {
					tinyMCE.execCommand("mceEndTyping");
					this.undoRedo.redo();
					tinyMCE.triggerNodeChange();
				} else
					this.getDoc().execCommand(command, user_interface, value);
				break;

			case "mceToggleVisualAid":
				this.visualAid = !this.visualAid;
				tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
				tinyMCE.triggerNodeChange();
				break;

			case "Indent":
				this.getDoc().execCommand(command, user_interface, value);
				tinyMCE.triggerNodeChange();

				if (tinyMCE.isIE) {
					var n = tinyMCE.getParentElement(this.getFocusElement(), "blockquote");
					do {
						if (n && n.nodeName == "BLOCKQUOTE") {
							n.removeAttribute("dir");
							n.removeAttribute("style");
						}
					} while (n != null && (n = n.parentNode) != null);
				}
				break;

			case "RemoveFormat":
			case "removeformat":
				var text = this.selection.getSelectedText();

				if (tinyMCE.isOpera) {
					this.getDoc().execCommand("RemoveFormat", false, null);
					return;
				}

				if (tinyMCE.isIE) {
					try {
						var rng = doc.selection.createRange();
						rng.execCommand("RemoveFormat", false, null);
					} catch (e) {
						// Do nothing
					}

					this.execCommand("mceSetStyleInfo", false, {command : "removeformat"});
				} else {
					this.getDoc().execCommand(command, user_interface, value);

					this.execCommand("mceSetStyleInfo", false, {command : "removeformat"});
				}

				// Remove class
				if (text.length == 0)
					this.execCommand("mceSetCSSClass", false, "");

				tinyMCE.triggerNodeChange();
				break;
                                   
			default:
				this.getDoc().execCommand(command, user_interface, value);

				if (tinyMCE.isGecko)
					window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
				else
					tinyMCE.triggerNodeChange();
		}

		// Add undo level after modification
		if (command != "mceAddUndoLevel" && command != "Undo" && command != "Redo" && command != "mceStartTyping" && command != "mceEndTyping")
			tinyMCE.execCommand("mceAddUndoLevel");
	},

	queryCommandValue : function(c) {
		try {
			return this.getDoc().queryCommandValue(c);
		} catch (e) {
			return null;
		}
	},

	queryCommandState : function(c) {
		return this.getDoc().queryCommandState(c);
	},

	_onAdd : function(replace_element, form_element_name, target_document) {
		var hc, th, to, editorTemplate;

		th = this.settings['theme'];
		to = tinyMCE.themes[th];

		var targetDoc = target_document ? target_document : document;

		this.targetDoc = targetDoc;

		tinyMCE.themeURL = tinyMCE.baseURL + "/themes/" + this.settings['theme'];
		this.settings['themeurl'] = tinyMCE.themeURL;

		if (!replace_element) {
			alert("Error: Could not find the target element.");
			return false;
		}

		if (to.getEditorTemplate)
			editorTemplate = to.getEditorTemplate(this.settings, this.editorId);

		var deltaWidth = editorTemplate['delta_width'] ? editorTemplate['delta_width'] : 0;
		var deltaHeight = editorTemplate['delta_height'] ? editorTemplate['delta_height'] : 0;
		var html = '<span id="' + this.editorId + '_parent" class="mceEditorContainer">' + editorTemplate['html'];

		html = tinyMCE.replaceVar(html, "editor_id", this.editorId);
		this.settings['default_document'] = tinyMCE.baseURL + "/blank.htm";

		this.settings['old_width'] = this.settings['width'];
		this.settings['old_height'] = this.settings['height'];

		// Set default width, height
		if (this.settings['width'] == -1)
			this.settings['width'] = replace_element.offsetWidth;

		if (this.settings['height'] == -1)
			this.settings['height'] = replace_element.offsetHeight;

		// Try the style width
		if (this.settings['width'] == 0)
			this.settings['width'] = replace_element.style.width;

		// Try the style height
		if (this.settings['height'] == 0)
			this.settings['height'] = replace_element.style.height; 

		// If no width/height then default to 320x240, better than nothing
		if (this.settings['width'] == 0)
			this.settings['width'] = 320;

		if (this.settings['height'] == 0)
			this.settings['height'] = 240;

		this.settings['area_width'] = parseInt(this.settings['width']);
		this.settings['area_height'] = parseInt(this.settings['height']);
		this.settings['area_width'] += deltaWidth;
		this.settings['area_height'] += deltaHeight;

		this.settings['width_style'] = "" + this.settings['width'];
		this.settings['height_style'] = "" + this.settings['height'];

		// Special % handling
		if (("" + this.settings['width']).indexOf('%') != -1)
			this.settings['area_width'] = "100%";
		else
			this.settings['width_style'] += 'px';

		if (("" + this.settings['height']).indexOf('%') != -1)
			this.settings['area_height'] = "100%";
		else
			this.settings['height_style'] += 'px';

		if (("" + replace_element.style.width).indexOf('%') != -1) {
			this.settings['width'] = replace_element.style.width;
			this.settings['area_width'] = "100%";
			this.settings['width_style'] = "100%";
		}

		if (("" + replace_element.style.height).indexOf('%') != -1) {
			this.settings['height'] = replace_element.style.height;
			this.settings['area_height'] = "100%";
			this.settings['height_style'] = "100%";
		}

		html = tinyMCE.applyTemplate(html);

		this.settings['width'] = this.settings['old_width'];
		this.settings['height'] = this.settings['old_height'];

		this.visualAid = this.settings['visual'];
		this.formTargetElementId = form_element_name;

		// Get replace_element contents
		if (replace_element.nodeName == "TEXTAREA" || replace_element.nodeName == "INPUT")
			this.startContent = replace_element.value;
		else
			this.startContent = replace_element.innerHTML;

		// If not text area or input
		if (replace_element.nodeName != "TEXTAREA" && replace_element.nodeName != "INPUT") {
			this.oldTargetElement = replace_element;

			// Debug mode
			if (tinyMCE.settings['debug']) {
				hc = '<textarea wrap="off" id="' + form_element_name + '" name="' + form_element_name + '" cols="100" rows="15"></textarea>';
			} else {
				hc = '<input type="hidden" id="' + form_element_name + '" name="' + form_element_name + '" />';
				this.oldTargetElement.style.display = "none";
			}

			html += '</span>';

			if (tinyMCE.isGecko)
				html = hc + html;
			else
				html += hc;

			// Output HTML and set editable
			if (tinyMCE.isGecko) {
				var rng = replace_element.ownerDocument.createRange();
				rng.setStartBefore(replace_element);

				var fragment = rng.createContextualFragment(html);
				tinyMCE.insertAfter(fragment, replace_element);
			} else
				replace_element.insertAdjacentHTML("beforeBegin", html);
		} else {
			html += '</span>';

			// Just hide the textarea element
			this.oldTargetElement = replace_element;

			if (!tinyMCE.settings['debug'])
				this.oldTargetElement.style.display = "none";

			// Output HTML and set editable
			if (tinyMCE.isGecko) {
				var rng = replace_element.ownerDocument.createRange();
				rng.setStartBefore(replace_element);

				var fragment = rng.createContextualFragment(html);
				tinyMCE.insertAfter(fragment, replace_element);
			} else
				replace_element.insertAdjacentHTML("beforeBegin", html);
		}

		// Setup iframe
		var dynamicIFrame = false;
		var tElm = targetDoc.getElementById(this.editorId);

		if (!tinyMCE.isIE) {
			// Node case is preserved in XML strict mode
			if (tElm && (tElm.nodeName == "SPAN" || tElm.nodeName == "span")) {
				tElm = tinyMCE._createIFrame(tElm, targetDoc);
				dynamicIFrame = true;
			}

			this.targetElement = tElm;
			this.iframeElement = tElm;
			this.contentDocument = tElm.contentDocument;
			this.contentWindow = tElm.contentWindow;

			//this.getDoc().designMode = "on";
		} else {
			if (tElm && tElm.nodeName == "SPAN")
				tElm = tinyMCE._createIFrame(tElm, targetDoc, targetDoc.parentWindow);
			else
				tElm = targetDoc.frames[this.editorId];

			this.targetElement = tElm;
			this.iframeElement = targetDoc.getElementById(this.editorId);

			if (tinyMCE.isOpera) {
				this.contentDocument = this.iframeElement.contentDocument;
				this.contentWindow = this.iframeElement.contentWindow;
				dynamicIFrame = true;
			} else {
				this.contentDocument = tElm.window.document;
				this.contentWindow = tElm.window;
			}

			this.getDoc().designMode = "on";
		}

		// Setup base HTML
		var doc = this.contentDocument;
		if (dynamicIFrame) {
			var html = tinyMCE.getParam('doctype') + '<html><head xmlns="http://www.w3.org/1999/xhtml"><base href="' + tinyMCE.settings['base_href'] + '" /><title>blank_page</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body class="mceContentBody"></body></html>';

			try {
				if (!this.isHidden())
					this.getDoc().designMode = "on";

				doc.open();
				doc.write(html);
				doc.close();
			} catch (e) {
				// Failed Mozilla 1.3
				this.getDoc().location.href = tinyMCE.baseURL + "/blank.htm";
			}
		}

		// This timeout is needed in MSIE 5.5 for some odd reason
		// it seems that the document.frames isn't initialized yet?
		if (tinyMCE.isIE)
			window.setTimeout("tinyMCE.addEventHandlers(tinyMCE.instances[\"" + this.editorId + "\"]);", 1);

		tinyMCE.setupContent(this.editorId, true);

		return true;
	},

	setBaseHREF : function(u) {
		var h, b, d, nl;

		d = this.getDoc();
		nl = d.getElementsByTagName("base");
		b = nl.length > 0 ? nl[0] : null;

		if (!b) {
			nl = d.getElementsByTagName("head");
			h = nl.length > 0 ? nl[0] : null;

			b = d.createElement("base");
			b.setAttribute('href', u);
			h.appendChild(b);
		} else {
			if (u == "" || u == null)
				b.parentNode.removeChild(b);
			else
				b.setAttribute('href', u);
		}
	},

	getHTML : function(r) {
		var h, d = this.getDoc(), b = this.getBody();

		if (r)
			return b.innerHTML;

		h = tinyMCE._cleanupHTML(this, d, this.settings, b, false, true, false, true);

		if (tinyMCE.getParam("convert_fonts_to_spans"))
			tinyMCE.convertSpansToFonts(d);

		return h;
	},

	setHTML : function(h) {
		this.execCommand('mceSetContent', false, h);
		this.repaint();
	},

	getFocusElement : function() {
		return this.selection.getFocusElement();
	},

	getSel : function() {
		return this.selection.getSel();
	},

	getRng : function() {
		return this.selection.getRng();
	},

	triggerSave : function(skip_cleanup, skip_callback) {
		var e, nl = [], i, s;

		this.switchSettings();
		s = tinyMCE.settings;

		// Force hidden tabs visible while serializing
		if (tinyMCE.isRealIE) {
			e = this.iframeElement;

			do {
				if (e.style && e.style.display == 'none') {
					e.style.display = 'block';
					nl[nl.length] = {elm : e, type : 'style'};
				}

				if (e.style && s.hidden_tab_class.length > 0 && e.className.indexOf(s.hidden_tab_class) != -1) {
					e.className = s.display_tab_class;
					nl[nl.length] = {elm : e, type : 'class'};
				}
			} while ((e = e.parentNode) != null)
		}

		tinyMCE.settings['preformatted'] = false;

		// Default to false
		if (typeof(skip_cleanup) == "undefined")
			skip_cleanup = false;

		// Default to false
		if (typeof(skip_callback) == "undefined")
			skip_callback = false;

		tinyMCE._setHTML(this.getDoc(), this.getBody().innerHTML);

		// Remove visual aids when cleanup is disabled
		if (this.settings['cleanup'] == false) {
			tinyMCE.handleVisualAid(this.getBody(), true, false, this);
			tinyMCE._setEventsEnabled(this.getBody(), true);
		}

		tinyMCE._customCleanup(this, "submit_content_dom", this.contentWindow.document.body);
		var htm = skip_cleanup ? this.getBody().innerHTML : tinyMCE._cleanupHTML(this, this.getDoc(), this.settings, this.getBody(), tinyMCE.visualAid, true, true);
		htm = tinyMCE._customCleanup(this, "submit_content", htm);

		if (!skip_callback && tinyMCE.settings['save_callback'] != "")
			var content = eval(tinyMCE.settings['save_callback'] + "(this.formTargetElementId,htm,this.getBody());");

		// Use callback content if available
		if ((typeof(content) != "undefined") && content != null)
			htm = content;

		// Replace some weird entities (Bug: #1056343)
		htm = tinyMCE.regexpReplace(htm, "&#40;", "(", "gi");
		htm = tinyMCE.regexpReplace(htm, "&#41;", ")", "gi");
		htm = tinyMCE.regexpReplace(htm, "&#59;", ";", "gi");
		htm = tinyMCE.regexpReplace(htm, "&#34;", "&quot;", "gi");
		htm = tinyMCE.regexpReplace(htm, "&#94;", "^", "gi");

		if (this.formElement)
			this.formElement.value = htm;

		if (tinyMCE.isSafari && this.formElement)
			this.formElement.innerText = htm;

		// Hide them again (tabs in MSIE)
		for (i=0; i<nl.length; i++) {
			if (nl[i].type == 'style')
				nl[i].elm.style.display = 'none';
			else
				nl[i].elm.className = s.hidden_tab_class;
		}
	}

	};

/* file:jscripts/tiny_mce/classes/TinyMCE_Cleanup.class.js */

TinyMCE_Engine.prototype.cleanupHTMLCode = function(s) {
	s = s.replace(new RegExp('<p \\/>', 'gi'), '<p>&nbsp;</p>');
	s = s.replace(new RegExp('<p>\\s*<\\/p>', 'gi'), '<p>&nbsp;</p>');

	// Fix close BR elements
	s = s.replace(new RegExp('<br>\\s*<\\/br>', 'gi'), '<br />');

	// Open closed tags like <b/> to <b></b>
	s = s.replace(new RegExp('<(h[1-6]|p|div|address|pre|form|table|li|ol|ul|td|b|font|em|strong|i|strike|u|span|a|ul|ol|li|blockquote)([a-z]*)([^\\\\|>]*)\\/>', 'gi'), '<$1$2$3></$1$2>');

	// Remove trailing space <b > to <b>
	s = s.replace(new RegExp('\\s+></', 'gi'), '></');

	// Close tags <img></img> to <img/>
	s = s.replace(new RegExp('<(img|br|hr)([^>]*)><\\/(img|br|hr)>', 'gi'), '<$1$2 />');

	// Weird MSIE bug, <p><hr /></p> breaks runtime?
	if (tinyMCE.isIE)
		s = s.replace(new RegExp('<p><hr \\/><\\/p>', 'gi'), "<hr>");

	// Weird tags will make IE error #bug: 1538495
	if (tinyMCE.isIE)
		s = s.replace(/<!(\s*)\/>/g, '');

	// Convert relative anchors to absolute URLs ex: #something to file.htm#something
	// Removed: Since local document anchors should never be forced absolute example edit.php?id=something
	//if (tinyMCE.getParam('convert_urls'))
	//	s = s.replace(new RegExp('(href=\"{0,1})(\\s*#)', 'gi'), '$1' + tinyMCE.settings['document_base_url'] + "#");

	return s;
};

TinyMCE_Engine.prototype.parseStyle = function(str) {
	var ar = new Array();

	if (str == null)
		return ar;

	var st = str.split(';');

	tinyMCE.clearArray(ar);

	for (var i=0; i<st.length; i++) {
		if (st[i] == '')
			continue;

		var re = new RegExp('^\\s*([^:]*):\\s*(.*)\\s*$');
		var pa = st[i].replace(re, '$1||$2').split('||');
//tinyMCE.debug(str, pa[0] + "=" + pa[1], st[i].replace(re, '$1||$2'));
		if (pa.length == 2)
			ar[pa[0].toLowerCase()] = pa[1];
	}

	return ar;
};

TinyMCE_Engine.prototype.compressStyle = function(ar, pr, sf, res) {
	var box = new Array();

	box[0] = ar[pr + '-top' + sf];
	box[1] = ar[pr + '-left' + sf];
	box[2] = ar[pr + '-right' + sf];
	box[3] = ar[pr + '-bottom' + sf];

	for (var i=0; i<box.length; i++) {
		if (box[i] == null)
			return;

		for (var a=0; a<box.length; a++) {
			if (box[a] != box[i])
				return;
		}
	}

	// They are all the same
	ar[res] = box[0];
	ar[pr + '-top' + sf] = null;
	ar[pr + '-left' + sf] = null;
	ar[pr + '-right' + sf] = null;
	ar[pr + '-bottom' + sf] = null;
};

TinyMCE_Engine.prototype.serializeStyle = function(ar) {
	var str = "";

	// Compress box
	tinyMCE.compressStyle(ar, "border", "", "border");
	tinyMCE.compressStyle(ar, "border", "-width", "border-width");
	tinyMCE.compressStyle(ar, "border", "-color", "border-color");
	tinyMCE.compressStyle(ar, "border", "-style", "border-style");
	tinyMCE.compressStyle(ar, "padding", "", "padding");
	tinyMCE.compressStyle(ar, "margin", "", "margin");

	for (var key in ar) {
		var val = ar[key];

		if (typeof(val) == 'function')
			continue;

		if (key.indexOf('mso-') == 0)
			continue;

		if (val != null && val != '') {
			val = '' + val; // Force string

			// Fix style URL
			val = val.replace(new RegExp("url\\(\\'?([^\\']*)\\'?\\)", 'gi'), "url('$1')");

			// Convert URL
			if (val.indexOf('url(') != -1 && tinyMCE.getParam('convert_urls')) {
				var m = new RegExp("url\\('(.*?)'\\)").exec(val);

				if (m.length > 1)
					val = "url('" + eval(tinyMCE.getParam('urlconverter_callback') + "(m[1], null, true);") + "')";
			}

			// Force HEX colors
			if (tinyMCE.getParam("force_hex_style_colors"))
				val = tinyMCE.convertRGBToHex(val, true);

			val = val.replace(/\"/g, '\'');

			if (val != "url('')")
				str += key.toLowerCase() + ": " + val + "; ";
		}
	}

	if (new RegExp('; $').test(str))
		str = str.substring(0, str.length - 2);

	return str;
};

TinyMCE_Engine.prototype.convertRGBToHex = function(s, k) {
	if (s.toLowerCase().indexOf('rgb') != -1) {
		var re = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi");
		var rgb = s.replace(re, "$1,$2,$3,$4,$5").split(',');
		if (rgb.length == 5) {
			r = parseInt(rgb[1]).toString(16);
			g = parseInt(rgb[2]).toString(16);
			b = parseInt(rgb[3]).toString(16);

			r = r.length == 1 ? '0' + r : r;
			g = g.length == 1 ? '0' + g : g;
			b = b.length == 1 ? '0' + b : b;

			s = "#" + r + g + b;

			if (k)
				s = rgb[0] + s + rgb[4];
		}
	}

	return s;
};

TinyMCE_Engine.prototype.convertHexToRGB = function(s) {
	if (s.indexOf('#') != -1) {
		s = s.replace(new RegExp('[^0-9A-F]', 'gi'), '');
		return "rgb(" + parseInt(s.substring(0, 2), 16) + "," + parseInt(s.substring(2, 4), 16) + "," + parseInt(s.substring(4, 6), 16) + ")";
	}

	return s;
};

TinyMCE_Engine.prototype.convertSpansToFonts = function(doc) {
	var sizes = tinyMCE.getParam('font_size_style_values').replace(/\s+/, '').split(',');

	/*var h = doc.body.innerHTML;
	h = h.replace(/<span/gi, '<font');
	h = h.replace(/<\/span/gi, '</font');
	tinyMCE.setInnerHTML(doc.body, h);*/

	var s = tinyMCE.selectElements(doc, 'span,font');
	for (var i=0; i<s.length; i++) {
		var size = tinyMCE.trim(s[i].style.fontSize).toLowerCase();
		var fSize = 0;

		for (var x=0; x<sizes.length; x++) {
			if (sizes[x] == size) {
				fSize = x + 1;
				break;
			}
		}

		if (fSize > 0) {
			tinyMCE.setAttrib(s[i], 'size', fSize);
			s[i].style.fontSize = '';
		}

		var fFace = s[i].style.fontFamily;
		if (fFace != null && fFace != "") {
			tinyMCE.setAttrib(s[i], 'face', fFace);
			s[i].style.fontFamily = '';
		}

		var fColor = s[i].style.color;
		if (fColor != null && fColor != "") {
			tinyMCE.setAttrib(s[i], 'color', tinyMCE.convertRGBToHex(fColor));
			s[i].style.color = '';
		}
	}
};

TinyMCE_Engine.prototype.convertFontsToSpans = function(doc) {
	var sizes = tinyMCE.getParam('font_size_style_values').replace(/\s+/, '').split(',');

/*	var h = doc.body.innerHTML;
	h = h.replace(/<font/gi, '<span');
	h = h.replace(/<\/font/gi, '</span');
	tinyMCE.setInnerHTML(doc.body, h);*/

	var fsClasses = tinyMCE.getParam('font_size_classes');
	if (fsClasses != '')
		fsClasses = fsClasses.replace(/\s+/, '').split(',');
	else
		fsClasses = null;

	var s = tinyMCE.selectElements(doc, 'span,font');
	for (var i=0; i<s.length; i++) {
		var fSize, fFace, fColor;

		fSize = tinyMCE.getAttrib(s[i], 'size');
		fFace = tinyMCE.getAttrib(s[i], 'face');
		fColor = tinyMCE.getAttrib(s[i], 'color');

		if (fSize != "") {
			fSize = parseInt(fSize);

			if (fSize > 0 && fSize < 8) {
				if (fsClasses != null)
					tinyMCE.setAttrib(s[i], 'class', fsClasses[fSize-1]);
				else
					s[i].style.fontSize = sizes[fSize-1];
			}

			s[i].removeAttribute('size');
		}

		if (fFace != "") {
			s[i].style.fontFamily = fFace;
			s[i].removeAttribute('face');
		}

		if (fColor != "") {
			s[i].style.color = fColor;
			s[i].removeAttribute('color');
		}
	}
};

TinyMCE_Engine.prototype.cleanupAnchors = function(doc) {
	var i, cn, x, an = doc.getElementsByTagName("a");

	// Loops backwards due to bug #1467987
	for (i=an.length-1; i>=0; i--) {
		if (tinyMCE.getAttrib(an[i], "name") != "" && tinyMCE.getAttrib(an[i], "href") == "") {
			cn = an[i].childNodes;

			for (x=cn.length-1; x>=0; x--)
				tinyMCE.insertAfter(cn[x], an[i]);
		}
	}
};

TinyMCE_Engine.prototype.getContent = function(editor_id) {
	if (typeof(editor_id) != "undefined")
		 tinyMCE.getInstanceById(editor_id).select();

	if (tinyMCE.selectedInstance)
		return tinyMCE.selectedInstance.getHTML();

	return null;
};

TinyMCE_Engine.prototype._fixListElements = function(d) {
	var nl, x, a = ['ol', 'ul'], i, n, p, r = new RegExp('^(OL|UL)$'), np;

	for (x=0; x<a.length; x++) {
		nl = d.getElementsByTagName(a[x]);

		for (i=0; i<nl.length; i++) {
			n = nl[i];
			p = n.parentNode;

			if (r.test(p.nodeName)) {
				np = tinyMCE.prevNode(n, 'LI');

				if (!np) {
					np = d.createElement('li');
					np.innerHTML = '&nbsp;';
					np.appendChild(n);
					p.insertBefore(np, p.firstChild);
				} else
					np.appendChild(n);
			}
		}
	}
};

TinyMCE_Engine.prototype._fixTables = function(d) {
	var nl, i, n, p, np, x, t;

	nl = d.getElementsByTagName('table');
	for (i=0; i<nl.length; i++) {
		n = nl[i];

		if ((p = tinyMCE.getParentElement(n, 'p,h1,h2,h3,h4,h5,h6')) != null) {
			np = p.cloneNode(false);
			np.removeAttribute('id');

			t = n;

			while ((n = n.nextSibling))
				np.appendChild(n);

			tinyMCE.insertAfter(np, p);
			tinyMCE.insertAfter(t, p);
		}
	}
};

TinyMCE_Engine.prototype._cleanupHTML = function(inst, doc, config, elm, visual, on_save, on_submit, inn) {
	var h, d, t1, t2, t3, t4, t5, c, s, nb;

	if (!tinyMCE.getParam('cleanup'))
		return elm.innerHTML;

	on_save = typeof(on_save) == 'undefined' ? false : on_save;

	c = inst.cleanup;
	s = inst.settings;
	d = c.settings.debug;

	if (d)
		t1 = new Date().getTime();

	if (tinyMCE.getParam("convert_fonts_to_spans"))
		tinyMCE.convertFontsToSpans(doc);

	if (tinyMCE.getParam("fix_list_elements"))
		tinyMCE._fixListElements(doc);

	if (tinyMCE.getParam("fix_table_elements"))
		tinyMCE._fixTables(doc);

	// Call custom cleanup code
	tinyMCE._customCleanup(inst, on_save ? "get_from_editor_dom" : "insert_to_editor_dom", doc.body);

	if (d)
		t2 = new Date().getTime();

	c.settings.on_save = on_save;
	//for (var i=0; i<100; i++)

	c.idCount = 0;
	c.serializationId++;
	c.serializedNodes = new Array();
	c.sourceIndex = -1;

	if (s.cleanup_serializer == "xml")
		h = c.serializeNodeAsXML(elm, inn);
	else
		h = c.serializeNodeAsHTML(elm, inn);

	if (d)
		t3 = new Date().getTime();

	// Post processing
	nb = tinyMCE.getParam('entity_encoding') == 'numeric' ? '&#160;' : '&nbsp;';
	h = h.replace(/<\/?(body|head|html)[^>]*>/gi, '');
	h = h.replace(new RegExp(' (rowspan="1"|colspan="1")', 'g'), '');
	h = h.replace(/<p><hr \/><\/p>/g, '<hr />');
	h = h.replace(/<p>(&nbsp;|&#160;)<\/p><hr \/><p>(&nbsp;|&#160;)<\/p>/g, '<hr />');
	h = h.replace(/<td>\s*<br \/>\s*<\/td>/g, '<td>' + nb + '</td>');
	h = h.replace(/<p>\s*<br \/>\s*<\/p>/g, '<p>' + nb + '</p>');
	h = h.replace(/<br \/>$/, ''); // Remove last BR for Gecko
	h = h.replace(/<br \/><\/p>/g, '</p>'); // Remove last BR in P tags for Gecko
	h = h.replace(/<p>\s*(&nbsp;|&#160;)\s*<br \/>\s*(&nbsp;|&#160;)\s*<\/p>/g, '<p>' + nb + '</p>');
	h = h.replace(/<p>\s*(&nbsp;|&#160;)\s*<br \/>\s*<\/p>/g, '<p>' + nb + '</p>');
	h = h.replace(/<p>\s*<br \/>\s*&nbsp;\s*<\/p>/g, '<p>' + nb + '</p>');
	h = h.replace(new RegExp('<a>(.*?)<\\/a>', 'g'), '$1');
	h = h.replace(/<p([^>]*)>\s*<\/p>/g, '<p$1>' + nb + '</p>');

	// Clean body
	if (/^\s*(<br \/>|<p>&nbsp;<\/p>|<p>&#160;<\/p>|<p><\/p>)\s*$/.test(h))
		h = '';

	// If preformatted
	if (s.preformatted) {
		h = h.replace(/^<pre>/, '');
		h = h.replace(/<\/pre>$/, '');
		h = '<pre>' + h + '</pre>';
	}

	// Gecko specific processing
	if (tinyMCE.isGecko) {
		h = h.replace(/<o:p _moz-userdefined="" \/>/g, '');
		h = h.replace(/<td([^>]*)>\s*<br \/>\s*<\/td>/g, '<td$1>' + nb + '</td>');
	}

	if (s.force_br_newlines)
		h = h.replace(/<p>(&nbsp;|&#160;)<\/p>/g, '<br />');

	// Call custom cleanup code
	h = tinyMCE._customCleanup(inst, on_save ? "get_from_editor" : "insert_to_editor", h);

	// Remove internal classes
	if (on_save) {
		h = h.replace(new RegExp(' ?(mceItem[a-zA-Z0-9]*|' + s.visual_table_class + ')', 'g'), '');
		h = h.replace(new RegExp(' ?class=""', 'g'), '');
	}

	if (s.remove_linebreaks && !c.settings.indent)
		h = h.replace(/\n|\r/g, ' ');

	if (d)
		t4 = new Date().getTime();

	if (on_save && c.settings.indent)
		h = c.formatHTML(h);

	// If encoding (not recommended option)
	if (on_submit && (s.encoding == "xml" || s.encoding == "html"))
		h = c.xmlEncode(h);

	if (d)
		t5 = new Date().getTime();

	if (c.settings.debug)
		tinyMCE.debug("Cleanup in ms: Pre=" + (t2-t1) + ", Serialize: " + (t3-t2) + ", Post: " + (t4-t3) + ", Format: " + (t5-t4) + ", Sum: " + (t5-t1) + ".");

	return h;
};

function TinyMCE_Cleanup() {
	this.isIE = (navigator.appName == "Microsoft Internet Explorer");
	this.rules = tinyMCE.clearArray(new Array());

	// Default config
	this.settings = {
		indent_elements : 'head,table,tbody,thead,tfoot,form,tr,ul,ol,blockquote,object',
		newline_before_elements : 'h1,h2,h3,h4,h5,h6,pre,address,div,ul,ol,li,meta,option,area,title,link,base,script,td',
		newline_after_elements : 'br,hr,p,pre,address,div,ul,ol,meta,option,area,link,base,script',
		newline_before_after_elements : 'html,head,body,table,thead,tbody,tfoot,tr,form,ul,ol,blockquote,p,object,param,hr,div',
		indent_char : '\t',
		indent_levels : 1,
		entity_encoding : 'raw',
		valid_elements : '*[*]',
		entities : '',
		url_converter : '',
		invalid_elements : '',
		verify_html : false
	};

	this.vElements = tinyMCE.clearArray(new Array());
	this.vElementsRe = '';
	this.closeElementsRe = /^(IMG|BR|HR|LINK|META|BASE|INPUT|AREA)$/;
	this.codeElementsRe = /^(SCRIPT|STYLE)$/;
	this.serializationId = 0;
	this.mceAttribs = {
		href : 'mce_href',
		src : 'mce_src',
		type : 'mce_type'
	};
}

TinyMCE_Cleanup.prototype = {
	init : function(s) {
		var n, a, i, ir, or, st;

		for (n in s)
			this.settings[n] = s[n];

		// Setup code formating
		s = this.settings;

		// Setup regexps
		this.inRe = this._arrayToRe(s.indent_elements.split(','), '', '^<(', ')[^>]*');
		this.ouRe = this._arrayToRe(s.indent_elements.split(','), '', '^<\\/(', ')[^>]*');
		this.nlBeforeRe = this._arrayToRe(s.newline_before_elements.split(','), 'gi', '<(',  ')([^>]*)>');
		this.nlAfterRe = this._arrayToRe(s.newline_after_elements.split(','), 'gi', '<(',  ')([^>]*)>');
		this.nlBeforeAfterRe = this._arrayToRe(s.newline_before_after_elements.split(','), 'gi', '<(\\/?)(', ')([^>]*)>');
		this.serializedNodes = [];

		if (s.invalid_elements != '')
			this.iveRe = this._arrayToRe(s.invalid_elements.toUpperCase().split(','), 'g', '^(', ')$');
		else
			this.iveRe = null;

		// Setup separator
		st = '';
		for (i=0; i<s.indent_levels; i++)
			st += s.indent_char;

		this.inStr = st;

		// If verify_html if false force *[*]
		if (!s.verify_html) {
			s.valid_elements = '*[*]';
			s.extended_valid_elements = '';
		}

		this.fillStr = s.entity_encoding == "named" ? "&nbsp;" : "&#160;";
		this.idCount = 0;
		this.xmlEncodeRe = new RegExp('[\u007F-\uFFFF<>&"]', 'g');
		this.xmlEncodeAposRe = new RegExp('[\u007F-\uFFFF<>&"\']', 'g');
	},

	addRuleStr : function(s) {
		var r = this.parseRuleStr(s);
		var n;

		for (n in r) {
			if (r[n])
				this.rules[n] = r[n];
		}

		this.vElements = tinyMCE.clearArray(new Array());

		for (n in this.rules) {
			if (this.rules[n])
				this.vElements[this.vElements.length] = this.rules[n].tag;
		}

		this.vElementsRe = this._arrayToRe(this.vElements, '');
	},

	isValid : function(n) {
		this._setupRules(); // Will initialize cleanup rules

		// Empty is true since it removes formatting
		if (!n)
			return true;

		// Clean the name up a bit
		n = n.replace(/[^a-z0-9]+/gi, '').toUpperCase();

		return !tinyMCE.getParam('cleanup') || this.vElementsRe.test(n);
	},

	addChildRemoveRuleStr : function(s) {
		var x, y, p, i, t, tn, ta, cl, r;

		if (!s)
			return;

		ta = s.split(',');
		for (x=0; x<ta.length; x++) {
			s = ta[x];

			// Split tag/children
			p = this.split(/\[|\]/, s);
			if (p == null || p.length < 1)
				t = s.toUpperCase();
			else
				t = p[0].toUpperCase();

			// Handle all tag names
			tn = this.split('/', t);
			for (y=0; y<tn.length; y++) {
				r = "^(";

				// Build regex
				cl = this.split(/\|/, p[1]);
				for (i=0; i<cl.length; i++) {
					if (cl[i] == '%istrict')
						r += tinyMCE.inlineStrict;
					else if (cl[i] == '%itrans')
						r += tinyMCE.inlineTransitional;
					else if (cl[i] == '%istrict_na')
						r += tinyMCE.inlineStrict.substring(2);
					else if (cl[i] == '%itrans_na')
						r += tinyMCE.inlineTransitional.substring(2);
					else if (cl[i] == '%btrans')
						r += tinyMCE.blockElms;
					else if (cl[i] == '%strict')
						r += tinyMCE.blockStrict;
					else
						r += (cl[i].charAt(0) != '#' ? cl[i].toUpperCase() : cl[i]);

					r += (i != cl.length - 1 ? '|' : '');
				}

				r += ')$';
//tinyMCE.debug(t + "=" + r);
				if (this.childRules == null)
					this.childRules = tinyMCE.clearArray(new Array());

				this.childRules[tn[y]] = new RegExp(r);

				if (p.length > 1)
					this.childRules[tn[y]].wrapTag = p[2];
			}
		}
	},

	parseRuleStr : function(s) {
		var ta, p, r, a, i, x, px, t, tn, y, av, or = tinyMCE.clearArray(new Array()), dv;

		if (s == null || s.length == 0)
			return or;

		ta = s.split(',');
		for (x=0; x<ta.length; x++) {
			s = ta[x];
			if (s.length == 0)
				continue;

			// Split tag/attrs
			p = this.split(/\[|\]/, s);
			if (p == null || p.length < 1)
				t = s.toUpperCase();
			else
				t = p[0].toUpperCase();

			// Handle all tag names
			tn = this.split('/', t);
			for (y=0; y<tn.length; y++) {
				r = {};

				r.tag = tn[y];
				r.forceAttribs = null;
				r.defaultAttribs = null;
				r.validAttribValues = null;

				// Handle prefixes
				px = r.tag.charAt(0);
				r.forceOpen = px == '+';
				r.removeEmpty = px == '-';
				r.fill = px == '#';
				r.tag = r.tag.replace(/\+|-|#/g, '');
				r.oTagName = tn[0].replace(/\+|-|#/g, '').toLowerCase();
				r.isWild = new RegExp('\\*|\\?|\\+', 'g').test(r.tag);
				r.validRe = new RegExp(this._wildcardToRe('^' + r.tag + '$'));

				// Setup valid attributes
				if (p.length > 1) {
					r.vAttribsRe = '^(';
					a = this.split(/\|/, p[1]);

					for (i=0; i<a.length; i++) {
						t = a[i];

						if (t.charAt(0) == '!') {
							a[i] = t = t.substring(1);

							if (!r.reqAttribsRe)
								r.reqAttribsRe = '\\s+(' + t;
							else
								r.reqAttribsRe += '|' + t;
						}

						av = new RegExp('(=|:|<)(.*?)$').exec(t);
						t = t.replace(new RegExp('(=|:|<).*?$'), '');
						if (av && av.length > 0) {
							if (av[0].charAt(0) == ':') {
								if (!r.forceAttribs)
									r.forceAttribs = tinyMCE.clearArray(new Array());

								r.forceAttribs[t.toLowerCase()] = av[0].substring(1);
							} else if (av[0].charAt(0) == '=') {
								if (!r.defaultAttribs)
									r.defaultAttribs = tinyMCE.clearArray(new Array());

								dv = av[0].substring(1);

								r.defaultAttribs[t.toLowerCase()] = dv == "" ? "mce_empty" : dv;
							} else if (av[0].charAt(0) == '<') {
								if (!r.validAttribValues)
									r.validAttribValues = tinyMCE.clearArray(new Array());

								r.validAttribValues[t.toLowerCase()] = this._arrayToRe(this.split('?', av[0].substring(1)), 'i');
							}
						}

						r.vAttribsRe += '' + t.toLowerCase() + (i != a.length - 1 ? '|' : '');

						a[i] = t.toLowerCase();
					}

					if (r.reqAttribsRe)
						r.reqAttribsRe = new RegExp(r.reqAttribsRe + ')=\"', 'g');

					r.vAttribsRe += ')$';
					r.vAttribsRe = this._wildcardToRe(r.vAttribsRe);
					r.vAttribsReIsWild = new RegExp('\\*|\\?|\\+', 'g').test(r.vAttribsRe);
					r.vAttribsRe = new RegExp(r.vAttribsRe);
					r.vAttribs = a.reverse();

					//tinyMCE.debug(r.tag, r.oTagName, r.vAttribsRe, r.vAttribsReWC);
				} else {
					r.vAttribsRe = '';
					r.vAttribs = tinyMCE.clearArray(new Array());
					r.vAttribsReIsWild = false;
				}

				or[r.tag] = r;
			}
		}

		return or;
	},

	serializeNodeAsXML : function(n) {
		var s, b;

		if (!this.xmlDoc) {
			if (this.isIE) {
				try {this.xmlDoc = new ActiveXObject('MSXML2.DOMDocument');} catch (e) {}

				if (!this.xmlDoc)
					try {this.xmlDoc = new ActiveXObject('Microsoft.XmlDom');} catch (e) {}
			} else
				this.xmlDoc = document.implementation.createDocument('', '', null);

			if (!this.xmlDoc)
				alert("Error XML Parser could not be found.");
		}

		if (this.xmlDoc.firstChild)
			this.xmlDoc.removeChild(this.xmlDoc.firstChild);

		b = this.xmlDoc.createElement("html");
		b = this.xmlDoc.appendChild(b);

		this._convertToXML(n, b);

		if (this.isIE)
			return this.xmlDoc.xml;
		else
			return new XMLSerializer().serializeToString(this.xmlDoc);
	},

	_convertToXML : function(n, xn) {
		var xd, el, i, l, cn, at, no, hc = false;

		if (tinyMCE.isRealIE && this._isDuplicate(n))
			return;

		xd = this.xmlDoc;

		switch (n.nodeType) {
			case 1: // Element
				hc = n.hasChildNodes();

				el = xd.createElement(n.nodeName.toLowerCase());

				at = n.attributes;
				for (i=at.length-1; i>-1; i--) {
					no = at[i];

					if (no.specified && no.nodeValue)
						el.setAttribute(no.nodeName.toLowerCase(), no.nodeValue);
				}

				if (!hc && !this.closeElementsRe.test(n.nodeName))
					el.appendChild(xd.createTextNode(""));

				xn = xn.appendChild(el);
				break;

			case 3: // Text
				xn.appendChild(xd.createTextNode(n.nodeValue));
				return;

			case 8: // Comment
				xn.appendChild(xd.createComment(n.nodeValue));
				return;
		}

		if (hc) {
			cn = n.childNodes;

			for (i=0, l=cn.length; i<l; i++)
				this._convertToXML(cn[i], xn);
		}
	},

	serializeNodeAsHTML : function(n, inn) {
		var en, no, h = '', i, l, t, st, r, cn, va = false, f = false, at, hc, cr, nn;

		this._setupRules(); // Will initialize cleanup rules

		if (tinyMCE.isRealIE && this._isDuplicate(n))
			return '';

		// Skip non valid child elements
		if (n.parentNode && this.childRules != null) {
			cr = this.childRules[n.parentNode.nodeName];

			if (typeof(cr) != "undefined" && !cr.test(n.nodeName)) {
				st = true;
				t = null;
			}
		}

		switch (n.nodeType) {
			case 1: // Element
				hc = n.hasChildNodes();

				if (st)
					break;

				// MSIE sometimes produces <//tag>
				if ((tinyMCE.isRealIE) && n.nodeName.indexOf('/') != -1)
					break;

				nn = n.nodeName;

				// Convert fonts to spans
				if (this.settings.convert_fonts_to_spans) {
					// On get content FONT -> SPAN
					if (this.settings.on_save && nn == 'FONT')
						nn = 'SPAN';

					// On insert content SPAN -> FONT
					if (!this.settings.on_save && nn == 'SPAN')
						nn = 'FONT';
				}

				if (this.vElementsRe.test(nn) && (!this.iveRe || !this.iveRe.test(nn)) && !inn) {
					va = true;

					r = this.rules[nn];
					if (!r) {
						at = this.rules;
						for (no in at) {
							if (at[no] && at[no].validRe.test(nn)) {
								r = at[no];
								break;
							}
						}
					}

					en = r.isWild ? nn.toLowerCase() : r.oTagName;
					f = r.fill;

					if (r.removeEmpty && !hc)
						return "";

					t = '<' + en;

					if (r.vAttribsReIsWild) {
						// Serialize wildcard attributes
						at = n.attributes;
						for (i=at.length-1; i>-1; i--) {
							no = at[i];
							if (no.specified && r.vAttribsRe.test(no.nodeName))
								t += this._serializeAttribute(n, r, no.nodeName);
						}
					} else {
						// Serialize specific attributes
						for (i=r.vAttribs.length-1; i>-1; i--)
							t += this._serializeAttribute(n, r, r.vAttribs[i]);
					}

					// Serialize mce_ atts
					if (!this.settings.on_save) {
						at = this.mceAttribs;

						for (no in at) {
							if (at[no])
								t += this._serializeAttribute(n, r, at[no]);
						}
					}

					// Check for required attribs
					if (r.reqAttribsRe && !t.match(r.reqAttribsRe))
						t = null;

					// Close these
					if (t != null && this.closeElementsRe.test(nn))
						return t + ' />';

					if (t != null)
						h += t + '>';

					if (this.isIE && this.codeElementsRe.test(nn))
						h += n.innerHTML;
				}
			break;

			case 3: // Text
				if (st)
					break;

				if (n.parentNode && this.codeElementsRe.test(n.parentNode.nodeName))
					return this.isIE ? '' : n.nodeValue;

				return this.xmlEncode(n.nodeValue);

			case 8: // Comment
				if (st)
					break;

				return "<!--" + this._trimComment(n.nodeValue) + "-->";
		}

		if (hc) {
			cn = n.childNodes;

			for (i=0, l=cn.length; i<l; i++)
				h += this.serializeNodeAsHTML(cn[i]);
		}

		// Fill empty nodes
		if (f && !hc)
			h += this.fillStr;

		// End element
		if (t != null && va)
			h += '</' + en + '>';

		return h;
	},

	_serializeAttribute : function(n, r, an) {
		var av = '', t, os = this.settings.on_save;

		if (os && (an.indexOf('mce_') == 0 || an.indexOf('_moz') == 0))
			return '';

		if (os && this.mceAttribs[an])
			av = this._getAttrib(n, this.mceAttribs[an]);

		if (av.length == 0)
			av = this._getAttrib(n, an);

		if (av.length == 0 && r.defaultAttribs && (t = r.defaultAttribs[an])) {
			av = t;

			if (av == "mce_empty")
				return " " + an + '=""';
		}

		if (r.forceAttribs && (t = r.forceAttribs[an]))
			av = t;

		if (os && av.length != 0 && this.settings.url_converter.length != 0 && /^(src|href|longdesc)$/.test(an))
			av = this._urlConverter(this, n, av);

		if (av.length != 0 && r.validAttribValues && r.validAttribValues[an] && !r.validAttribValues[an].test(av))
			return "";

		if (av.length != 0 && av == "{$uid}")
			av = "uid_" + (this.idCount++);

		if (av.length != 0) {
			if (an.indexOf('on') != 0)
				av = this.xmlEncode(av, 1);

			return " " + an + "=" + '"' + av + '"';
		}

		return "";
	},

	formatHTML : function(h) {
		var s = this.settings, p = '', i = 0, li = 0, o = '', l;

		// Replace BR in pre elements to \n
		h = h.replace(/<pre([^>]*)>(.*?)<\/pre>/gi, function (a, b, c) {
			c = c.replace(/<br\s*\/>/gi, '\n');
			return '<pre' + b + '>' + c + '</pre>';
		});

		h = h.replace(/\r/g, ''); // Windows sux, isn't carriage return a thing of the past :)
		h = '\n' + h;
		h = h.replace(new RegExp('\\n\\s+', 'gi'), '\n'); // Remove previous formatting
		h = h.replace(this.nlBeforeRe, '\n<$1$2>');
		h = h.replace(this.nlAfterRe, '<$1$2>\n');
		h = h.replace(this.nlBeforeAfterRe, '\n<$1$2$3>\n');
		h += '\n';

		//tinyMCE.debug(h);

		while ((i = h.indexOf('\n', i + 1)) != -1) {
			if ((l = h.substring(li + 1, i)).length != 0) {
				if (this.ouRe.test(l) && p.length >= s.indent_levels)
					p = p.substring(s.indent_levels);

				o += p + l + '\n';
	
				if (this.inRe.test(l))
					p += this.inStr;
			}

			li = i;
		}

		//tinyMCE.debug(h);

		return o;
	},

	xmlEncode : function(s, skip_apos) {
		var cl = this, re = !skip_apos ? this.xmlEncodeAposRe : this.xmlEncodeRe;

		this._setupEntities(); // Will intialize lookup table

		switch (this.settings.entity_encoding) {
			case "raw":
				return tinyMCE.xmlEncode(s, skip_apos);

			case "named":
				return s.replace(re, function (c, b) {
					b = cl.entities[c.charCodeAt(0)];

					return b ? '&' + b + ';' : c;
				});

			case "numeric":
				return s.replace(re, function (c, b) {
					return b ? '&#' + c.charCodeAt(0) + ';' : c;
				});
		}

		return s;
	},

	split : function(re, s) {
		var c = s.split(re);
		var i, l, o = new Array();

		for (i=0, l=c.length; i<l; i++) {
			if (c[i] != '')
				o[i] = c[i];
		}

		return o;
	},

	_trimComment : function(s) {
		// Remove mce_src, mce_href
		s = s.replace(new RegExp('\\smce_src=\"[^\"]*\"', 'gi'), "");
		s = s.replace(new RegExp('\\smce_href=\"[^\"]*\"', 'gi'), "");

		return s;
	},

	_getAttrib : function(e, n, d) {
		var v, ex, nn;

		if (typeof(d) == "undefined")
			d = "";

		if (!e || e.nodeType != 1)
			return d;

		try {
			v = e.getAttribute(n, 0);
		} catch (ex) {
			// IE 7 may cast exception on invalid attributes
			v = e.getAttribute(n, 2);
		}

		if (n == "class" && !v)
			v = e.className;

		if (this.isIE) {
			if (n == "http-equiv")
				v = e.httpEquiv;

			nn = e.nodeName;

			// Skip the default values that IE returns
			if (nn == "FORM" && n == "enctype" && v == "application/x-www-form-urlencoded")
				v = "";

			if (nn == "INPUT" && n == "size" && v == "20")
				v = "";

			if (nn == "INPUT" && n == "maxlength" && v == "2147483647")
				v = "";
		}

		if (n == 'style' && v) {
			if (!tinyMCE.isOpera)
				v = e.style.cssText;

			v = tinyMCE.serializeStyle(tinyMCE.parseStyle(v));
		}

		if (this.settings.on_save && n.indexOf('on') != -1 && this.settings.on_save && v && v != "")
			v = tinyMCE.cleanupEventStr(v);

		return (v && v != "") ? '' + v : d;
	},

	_urlConverter : function(c, n, v) {
		if (!c.settings.on_save)
			return tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings.base_href, v);
		else if (tinyMCE.getParam('convert_urls')) {
			if (!this.urlConverter)
				this.urlConverter = eval(tinyMCE.settings.urlconverter_callback);

			return this.urlConverter(v, n, true);
		}

		return v;
	},

	_arrayToRe : function(a, op, be, af) {
		var i, r;

		op = typeof(op) == "undefined" ? "gi" : op;
		be = typeof(be) == "undefined" ? "^(" : be;
		af = typeof(af) == "undefined" ? ")$" : af;

		r = be;

		for (i=0; i<a.length; i++)
			r += this._wildcardToRe(a[i]) + (i != a.length-1 ? "|" : "");

		r += af;

		return new RegExp(r, op);
	},

	_wildcardToRe : function(s) {
		s = s.replace(/\?/g, '(\\S?)');
		s = s.replace(/\+/g, '(\\S+)');
		s = s.replace(/\*/g, '(\\S*)');

		return s;
	},

	_setupEntities : function() {
		var n, a, i, s = this.settings;

		// Setup entities
		if (!this.entitiesDone) {
			if (s.entity_encoding == "named") {
				n = tinyMCE.clearArray(new Array());
				a = this.split(',', s.entities);
				for (i=0; i<a.length; i+=2)
					n[a[i]] = a[i+1];

				this.entities = n;
			}

			this.entitiesDone = true;
		}
	},

	_setupRules : function() {
		var s = this.settings;

		// Setup default rule
		if (!this.rulesDone) {
			this.addRuleStr(s.valid_elements);
			this.addRuleStr(s.extended_valid_elements);
			this.addChildRemoveRuleStr(s.valid_child_elements);

			this.rulesDone = true;
		}
	},

	_isDuplicate : function(n) {
		var i;

		if (!this.settings.fix_content_duplication)
			return false;

		if (tinyMCE.isRealIE && n.nodeType == 1) {
			// Mark elements
			if (n.mce_serialized == this.serializationId)
				return true;

			n.setAttribute('mce_serialized', this.serializationId);
		} else {
			// Search lookup table for text nodes  and comments
			for (i=0; i<this.serializedNodes.length; i++) {
				if (this.serializedNodes[i] == n)
					return true;
			}

			this.serializedNodes[this.serializedNodes.length] = n;
		}

		return false;
	}

	};

/* file:jscripts/tiny_mce/classes/TinyMCE_DOMUtils.class.js */

TinyMCE_Engine.prototype.createTagHTML = function(tn, a, h) {
	var o = '', f = tinyMCE.xmlEncode;

	o = '<' + tn;

	if (a) {
		for (n in a) {
			if (typeof(a[n]) != 'function' && a[n] != null)
				o += ' ' + f(n) + '="' + f('' + a[n]) + '"';
		}
	}

	o += !h ? ' />' : '>' + h + '</' + tn + '>';

	return o;
};

TinyMCE_Engine.prototype.createTag = function(d, tn, a, h) {
	var o = d.createElement(tn);

	if (a) {
		for (n in a) {
			if (typeof(a[n]) != 'function' && a[n] != null)
				tinyMCE.setAttrib(o, n, a[n]);
		}
	}

	if (h)
		o.innerHTML = h;

	return o;
};

TinyMCE_Engine.prototype.getElementByAttributeValue = function(n, e, a, v) {
	return (n = this.getElementsByAttributeValue(n, e, a, v)).length == 0 ? null : n[0];
};

TinyMCE_Engine.prototype.getElementsByAttributeValue = function(n, e, a, v) {
	var i, nl = n.getElementsByTagName(e), o = new Array();

	for (i=0; i<nl.length; i++) {
		if (tinyMCE.getAttrib(nl[i], a).indexOf(v) != -1)
			o[o.length] = nl[i];
	}

	return o;
};

TinyMCE_Engine.prototype.isBlockElement = function(n) {
	return n != null && n.nodeType == 1 && this.blockRegExp.test(n.nodeName);
};

TinyMCE_Engine.prototype.getParentBlockElement = function(n, r) {
	return this.getParentNode(n, function(n) {
		return tinyMCE.isBlockElement(n);
	}, r);

	return null;
};

TinyMCE_Engine.prototype.insertAfter = function(n, r){
	if (r.nextSibling)
		r.parentNode.insertBefore(n, r.nextSibling);
	else
		r.parentNode.appendChild(n);
};

TinyMCE_Engine.prototype.setInnerHTML = function(e, h) {
	var i, nl, n;

	// Convert all strong/em to b/i in Gecko
	if (tinyMCE.isGecko) {
		h = h.replace(/<strong/gi, '<b');
		h = h.replace(/<em(\/?)/gi, '<i');
		h = h.replace(/<em /gi, '<i');
		h = h.replace(/<\/strong>/gi, '</b>');
		h = h.replace(/<\/em>/gi, '</i>');
	}

	if (tinyMCE.isRealIE) {
		// Since MSIE handles invalid HTML better that valid XHTML we
		// need to make some things invalid. <hr /> gets converted to <hr>.
		h = h.replace(/\s\/>/g, '>');

		// Since MSIE auto generated emtpy P tags some times we must tell it to keep the real ones
		h = h.replace(/<p([^>]*)>\u00A0?<\/p>/gi, '<p$1 mce_keep="true">&nbsp;</p>'); // Keep empty paragraphs
		h = h.replace(/<p([^>]*)>\s*&nbsp;\s*<\/p>/gi, '<p$1 mce_keep="true">&nbsp;</p>'); // Keep empty paragraphs
		h = h.replace(/<p([^>]*)>\s+<\/p>/gi, '<p$1 mce_keep="true">&nbsp;</p>'); // Keep empty paragraphs

		// Remove first comment
		e.innerHTML = tinyMCE.uniqueTag + h;
		e.firstChild.removeNode(true);

		// Remove weird auto generated empty paragraphs unless it's supposed to be there
		nl = e.getElementsByTagName("p");
		for (i=nl.length-1; i>=0; i--) {
			n = nl[i];

			if (n.nodeName == 'P' && !n.hasChildNodes() && !n.mce_keep)
				n.parentNode.removeChild(n);
		}
	} else {
		h = this.fixGeckoBaseHREFBug(1, e, h);
		e.innerHTML = h;
		this.fixGeckoBaseHREFBug(2, e, h);
	}
};

TinyMCE_Engine.prototype.getOuterHTML = function(e) {
	if (tinyMCE.isIE)
		return e.outerHTML;

	var d = e.ownerDocument.createElement("body");
	d.appendChild(e.cloneNode(true));
	return d.innerHTML;
};

TinyMCE_Engine.prototype.setOuterHTML = function(e, h, d) {
	var d = typeof(d) == "undefined" ? e.ownerDocument : d, i, nl, t;

	if (tinyMCE.isIE && e.nodeType == 1)
		e.outerHTML = h;
	else {
		t = d.createElement("body");
		t.innerHTML = h;

		for (i=0, nl=t.childNodes; i<nl.length; i++)
			e.parentNode.insertBefore(nl[i].cloneNode(true), e);

		e.parentNode.removeChild(e);
	}
};

TinyMCE_Engine.prototype._getElementById = function(id, d) {
	var e, i, j, f;

	if (typeof(d) == "undefined")
		d = document;

	e = d.getElementById(id);
	if (!e) {
		f = d.forms;

		for (i=0; i<f.length; i++) {
			for (j=0; j<f[i].elements.length; j++) {
				if (f[i].elements[j].name == id) {
					e = f[i].elements[j];
					break;
				}
			}
		}
	}

	return e;
};

TinyMCE_Engine.prototype.getNodeTree = function(n, na, t, nn) {
	return this.selectNodes(n, function(n) {
		return (!t || n.nodeType == t) && (!nn || n.nodeName == nn);
	}, na ? na : new Array());
};

TinyMCE_Engine.prototype.getParentElement = function(n, na, f, r) {
	var re = na ? new RegExp('^(' + na.toUpperCase().replace(/,/g, '|') + ')$') : 0, v;

	// Compatiblity with old scripts where f param was a attribute string
	if (f && typeof(f) == 'string')
		return this.getParentElement(n, na, function(no) {return tinyMCE.getAttrib(no, f) != '';});

	return this.getParentNode(n, function(n) {
		return ((n.nodeType == 1 && !re) || (re && re.test(n.nodeName))) && (!f || f(n));
	}, r);
};

TinyMCE_Engine.prototype.getParentNode = function(n, f, r) {
	while (n) {
		if (n == r)
			return null;

		if (f(n))
			return n;

		n = n.parentNode;
	}

	return null;
};

TinyMCE_Engine.prototype.getAttrib = function(elm, name, dv) {
	var v;

	if (typeof(dv) == "undefined")
		dv = "";

	// Not a element
	if (!elm || elm.nodeType != 1)
		return dv;

	try {
		v = elm.getAttribute(name, 0);
	} catch (ex) {
		// IE 7 may cast exception on invalid attributes
		v = elm.getAttribute(name, 2);
	}

	// Try className for class attrib
	if (name == "class" && !v)
		v = elm.className;

	// Workaround for a issue with Firefox 1.5rc2+
	if (tinyMCE.isGecko && name == "src" && elm.src != null && elm.src != "")
		v = elm.src;

	// Workaround for a issue with Firefox 1.5rc2+
	if (tinyMCE.isGecko && name == "href" && elm.href != null && elm.href != "")
		v = elm.href;

	if (name == "http-equiv" && tinyMCE.isIE)
		v = elm.httpEquiv;

	if (name == "style" && !tinyMCE.isOpera)
		v = elm.style.cssText;

	return (v && v != "") ? v : dv;
};

TinyMCE_Engine.prototype.setAttrib = function(el, name, va, fix) {
	if (typeof(va) == "number" && va != null)
		va = "" + va;

	if (fix) {
		if (va == null)
			va = "";

		va = va.replace(/[^0-9%]/g, '');
	}

	if (name == "style")
		el.style.cssText = va;

	if (name == "class")
		el.className = va;

	if (va != null && va != "" && va != -1)
		el.setAttribute(name, va);
	else
		el.removeAttribute(name);
};

TinyMCE_Engine.prototype.setStyleAttrib = function(e, n, v) {
	e.style[n] = v;

	// Style attrib deleted in IE
	if (tinyMCE.isIE && v == null || v == '') {
		v = tinyMCE.serializeStyle(tinyMCE.parseStyle(e.style.cssText));
		e.style.cssText = v;
		e.setAttribute("style", v);
	}
};

TinyMCE_Engine.prototype.switchClass = function(ei, c) {
	var e;

	if (tinyMCE.switchClassCache[ei])
		e = tinyMCE.switchClassCache[ei];
	else
		e = tinyMCE.switchClassCache[ei] = document.getElementById(ei);

	if (e) {
		// Keep tile mode
		if (tinyMCE.settings.button_tile_map && e.className && e.className.indexOf('mceTiledButton') == 0)
			c = 'mceTiledButton ' + c;

		e.className = c;
	}
};

TinyMCE_Engine.prototype.getAbsPosition = function(n, cn) {
	var l = 0, t = 0;

	while (n && n != cn) {
		l += n.offsetLeft;
		t += n.offsetTop;
		n = n.offsetParent;
	}

	return {absLeft : l, absTop : t};
};

TinyMCE_Engine.prototype.prevNode = function(e, n) {
	var a = n.split(','), i;

	while ((e = e.previousSibling) != null) {
		for (i=0; i<a.length; i++) {
			if (e.nodeName == a[i])
				return e;
		}
	}

	return null;
};

TinyMCE_Engine.prototype.nextNode = function(e, n) {
	var a = n.split(','), i;

	while ((e = e.nextSibling) != null) {
		for (i=0; i<a.length; i++) {
			if (e.nodeName == a[i])
				return e;
		}
	}

	return null;
};

TinyMCE_Engine.prototype.selectElements = function(n, na, f) {
	var i, a = [], nl, x;

	for (x=0, na = na.split(','); x<na.length; x++)
		for (i=0, nl = n.getElementsByTagName(na[x]); i<nl.length; i++)
			(!f || f(nl[i])) && a.push(nl[i]);

	return a;
};

TinyMCE_Engine.prototype.selectNodes = function(n, f, a) {
	var i;

	if (!a)
		a = new Array();

	if (f(n))
		a[a.length] = n;

	if (n.hasChildNodes()) {
		for (i=0; i<n.childNodes.length; i++)
			tinyMCE.selectNodes(n.childNodes[i], f, a);
	}

	return a;
};

TinyMCE_Engine.prototype.addCSSClass = function(e, c, b) {
	var o = this.removeCSSClass(e, c);
	return e.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c;
};

TinyMCE_Engine.prototype.removeCSSClass = function(e, c) {
	c = e.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' ');
	return e.className = c != ' ' ? c : '';
};

TinyMCE_Engine.prototype.hasCSSClass = function(n, c) {
	return new RegExp('\\b' + c + '\\b', 'g').test(n.className);
};

TinyMCE_Engine.prototype.renameElement = function(e, n, d) {
	var ne, i, ar;

	d = typeof(d) == "undefined" ? tinyMCE.selectedInstance.getDoc() : d;

	if (e) {
		ne = d.createElement(n);

		ar = e.attributes;
		for (i=ar.length-1; i>-1; i--) {
			if (ar[i].specified && ar[i].nodeValue)
				ne.setAttribute(ar[i].nodeName.toLowerCase(), ar[i].nodeValue);
		}

		ar = e.childNodes;
		for (i=0; i<ar.length; i++)
			ne.appendChild(ar[i].cloneNode(true));

		e.parentNode.replaceChild(ne, e);
	}
};

TinyMCE_Engine.prototype.getViewPort = function(w) {
	var d = w.document, m = d.compatMode == 'CSS1Compat', b = d.body, de = d.documentElement;

	return {
		left : w.pageXOffset || (m ? de.scrollLeft : b.scrollLeft),
		top : w.pageYOffset || (m ? de.scrollTop : b.scrollTop),
		width : w.innerWidth || (m ? de.clientWidth : b.clientWidth),
		height : w.innerHeight || (m ? de.clientHeight : b.clientHeight)
	};
};

/* file:jscripts/tiny_mce/classes/TinyMCE_URL.class.js */

TinyMCE_Engine.prototype.parseURL = function(url_str) {
	var urlParts = new Array();

	if (url_str) {
		var pos, lastPos;

		// Parse protocol part
		pos = url_str.indexOf('://');
		if (pos != -1) {
			urlParts['protocol'] = url_str.substring(0, pos);
			lastPos = pos + 3;
		}

		// Find port or path start
		for (var i=lastPos; i<url_str.length; i++) {
			var chr = url_str.charAt(i);

			if (chr == ':')
				break;

			if (chr == '/')
				break;
		}
		pos = i;

		// Get host
		urlParts['host'] = url_str.substring(lastPos, pos);

		// Get port
		urlParts['port'] = "";
		lastPos = pos;
		if (url_str.charAt(pos) == ':') {
			pos = url_str.indexOf('/', lastPos);
			urlParts['port'] = url_str.substring(lastPos+1, pos);
		}

		// Get path
		lastPos = pos;
		pos = url_str.indexOf('?', lastPos);

		if (pos == -1)
			pos = url_str.indexOf('#', lastPos);

		if (pos == -1)
			pos = url_str.length;

		urlParts['path'] = url_str.substring(lastPos, pos);

		// Get query
		lastPos = pos;
		if (url_str.charAt(pos) == '?') {
			pos = url_str.indexOf('#');
			pos = (pos == -1) ? url_str.length : pos;
			urlParts['query'] = url_str.substring(lastPos+1, pos);
		}

		// Get anchor
		lastPos = pos;
		if (url_str.charAt(pos) == '#') {
			pos = url_str.length;
			urlParts['anchor'] = url_str.substring(lastPos+1, pos);
		}
	}

	return urlParts;
};

TinyMCE_Engine.prototype.serializeURL = function(up) {
	var o = "";

	if (up['protocol'])
		o += up['protocol'] + "://";

	if (up['host'])
		o += up['host'];

	if (up['port'])
		o += ":" + up['port'];

	if (up['path'])
		o += up['path'];

	if (up['query'])
		o += "?" + up['query'];

	if (up['anchor'])
		o += "#" + up['anchor'];

	return o;
};

TinyMCE_Engine.prototype.convertAbsoluteURLToRelativeURL = function(base_url, url_to_relative) {
	var baseURL = this.parseURL(base_url);
	var targetURL = this.parseURL(url_to_relative);
	var strTok1;
	var strTok2;
	var breakPoint = 0;
	var outPath = "";
	var forceSlash = false;

	if (targetURL.path == "")
		targetURL.path = "/";
	else
		forceSlash = true;

	// Crop away last path part
	base_url = baseURL.path.substring(0, baseURL.path.lastIndexOf('/'));
	strTok1 = base_url.split('/');
	strTok2 = targetURL.path.split('/');

	if (strTok1.length >= strTok2.length) {
		for (var i=0; i<strTok1.length; i++) {
			if (i >= strTok2.length || strTok1[i] != strTok2[i]) {
				breakPoint = i + 1;
				break;
			}
		}
	}

	if (strTok1.length < strTok2.length) {
		for (var i=0; i<strTok2.length; i++) {
			if (i >= strTok1.length || strTok1[i] != strTok2[i]) {
				breakPoint = i + 1;
				break;
			}
		}
	}

	if (breakPoint == 1)
		return targetURL.path;

	for (var i=0; i<(strTok1.length-(breakPoint-1)); i++)
		outPath += "../";

	for (var i=breakPoint-1; i<strTok2.length; i++) {
		if (i != (breakPoint-1))
			outPath += "/" + strTok2[i];
		else
			outPath += strTok2[i];
	}

	targetURL.protocol = null;
	targetURL.host = null;
	targetURL.port = null;
	targetURL.path = outPath == "" && forceSlash ? "/" : outPath;

	// Remove document prefix from local anchors
	var fileName = baseURL.path;
	var pos;

	if ((pos = fileName.lastIndexOf('/')) != -1)
		fileName = fileName.substring(pos + 1);

	// Is local anchor
	if (fileName == targetURL.path && targetURL.anchor != "")
		targetURL.path = "";

	// If empty and not local anchor force filename or slash
	if (targetURL.path == "" && !targetURL.anchor)
		targetURL.path = fileName != "" ? fileName : "/";

	return this.serializeURL(targetURL);
};

TinyMCE_Engine.prototype.convertRelativeToAbsoluteURL = function(base_url, relative_url) {
	var baseURL = this.parseURL(base_url), baseURLParts, relURLParts;
	var relURL = this.parseURL(relative_url);

	if (relative_url == "" || relative_url.indexOf('://') != -1 || /^(mailto:|javascript:|#|\/)/.test(relative_url))
		return relative_url;

	// Split parts
	baseURLParts = baseURL['path'].split('/');
	relURLParts = relURL['path'].split('/');

	// Remove empty chunks
	var newBaseURLParts = new Array();
	for (var i=baseURLParts.length-1; i>=0; i--) {
		if (baseURLParts[i].length == 0)
			continue;

		newBaseURLParts[newBaseURLParts.length] = baseURLParts[i];
	}
	baseURLParts = newBaseURLParts.reverse();

	// Merge relURLParts chunks
	var newRelURLParts = new Array();
	var numBack = 0;
	for (var i=relURLParts.length-1; i>=0; i--) {
		if (relURLParts[i].length == 0 || relURLParts[i] == ".")
			continue;

		if (relURLParts[i] == '..') {
			numBack++;
			continue;
		}

		if (numBack > 0) {
			numBack--;
			continue;
		}

		newRelURLParts[newRelURLParts.length] = relURLParts[i];
	}

	relURLParts = newRelURLParts.reverse();

	// Remove end from absolute path
	var len = baseURLParts.length-numBack;
	var absPath = (len <= 0 ? "" : "/") + baseURLParts.slice(0, len).join('/') + "/" + relURLParts.join('/');
	var start = "", end = "";

	// Build output URL
	relURL.protocol = baseURL.protocol;
	relURL.host = baseURL.host;
	relURL.port = baseURL.port;

	// Re-add trailing slash if it's removed
	if (relURL.path.charAt(relURL.path.length-1) == "/")
		absPath += "/";

	relURL.path = absPath;

	return this.serializeURL(relURL);
};

TinyMCE_Engine.prototype.convertURL = function(url, node, on_save) {
	var prot = document.location.protocol;
	var host = document.location.hostname;
	var port = document.location.port;

	// Pass through file protocol
	if (prot == "file:")
		return url;

	// Something is wrong, remove weirdness
	url = tinyMCE.regexpReplace(url, '(http|https):///', '/');

	// Mailto link or anchor (Pass through)
	if (url.indexOf('mailto:') != -1 || url.indexOf('javascript:') != -1 || tinyMCE.regexpReplace(url,'[ \t\r\n\+]|%20','').charAt(0) == "#")
		return url;

	// Fix relative/Mozilla
	if (!tinyMCE.isIE && !on_save && url.indexOf("://") == -1 && url.charAt(0) != '/')
		return tinyMCE.settings['base_href'] + url;

	// Handle relative URLs
	if (on_save && tinyMCE.getParam('relative_urls')) {
		var curl = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], url);
		if (curl.charAt(0) == '/')
			curl = tinyMCE.settings['document_base_prefix'] + curl;

		var urlParts = tinyMCE.parseURL(curl);
		var tmpUrlParts = tinyMCE.parseURL(tinyMCE.settings['document_base_url']);

		// Force relative
		if (urlParts['host'] == tmpUrlParts['host'] && (urlParts['port'] == tmpUrlParts['port']))
			return tinyMCE.convertAbsoluteURLToRelativeURL(tinyMCE.settings['document_base_url'], curl);
	}

	// Handle absolute URLs
	if (!tinyMCE.getParam('relative_urls')) {
		var urlParts = tinyMCE.parseURL(url);
		var baseUrlParts = tinyMCE.parseURL(tinyMCE.settings['base_href']);

		// Force absolute URLs from relative URLs
		url = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], url);

		// If anchor and path is the same page
		if (urlParts['anchor'] && urlParts['path'] == baseUrlParts['path'])
			return "#" + urlParts['anchor'];
	}

	// Remove current domain
	if (tinyMCE.getParam('remove_script_host')) {
		var start = "", portPart = "";

		if (port != "")
			portPart = ":" + port;

		start = prot + "//" + host + portPart + "/";

		if (url.indexOf(start) == 0)
			url = url.substring(start.length-1);
	}

	return url;
};

TinyMCE_Engine.prototype.convertAllRelativeURLs = function(body) {
	var i, elms, src, href, mhref, msrc;

	// Convert all image URL:s to absolute URL
	elms = body.getElementsByTagName("img");
	for (i=0; i<elms.length; i++) {
		src = tinyMCE.getAttrib(elms[i], 'src');

		msrc = tinyMCE.getAttrib(elms[i], 'mce_src');
		if (msrc != "")
			src = msrc;

		if (src != "") {
			src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], src);
			elms[i].setAttribute("src", src);
		}
	}

	// Convert all link URL:s to absolute URL
	elms = body.getElementsByTagName("a");
	for (i=0; i<elms.length; i++) {
		href = tinyMCE.getAttrib(elms[i], 'href');

		mhref = tinyMCE.getAttrib(elms[i], 'mce_href');
		if (mhref != "")
			href = mhref;

		if (href && href != "") {
			href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], href);
			elms[i].setAttribute("href", href);
		}
	}
};

/* file:jscripts/tiny_mce/classes/TinyMCE_Array.class.js */

TinyMCE_Engine.prototype.clearArray = function(a) {
	var n;

	for (n in a)
		a[n] = null;

	return a;
};

TinyMCE_Engine.prototype.explode = function(d, s) {
	var ar = s.split(d), oar = new Array(), i;

	for (i = 0; i<ar.length; i++) {
		if (ar[i] != "")
			oar[oar.length] = ar[i];
	}

	return oar;
};

/* file:jscripts/tiny_mce/classes/TinyMCE_Event.class.js */

TinyMCE_Engine.prototype._setEventsEnabled = function(node, state) {
	var evs, x, y, elms, i, event;
	var events = ['onfocus','onblur','onclick','ondblclick',
				'onmousedown','onmouseup','onmouseover','onmousemove',
				'onmouseout','onkeypress','onkeydown','onkeydown','onkeyup'];

	evs = tinyMCE.settings['event_elements'].split(',');
	for (y=0; y<evs.length; y++){
		elms = node.getElementsByTagName(evs[y]);
		for (i=0; i<elms.length; i++) {
			event = "";

			for (x=0; x<events.length; x++) {
				if ((event = tinyMCE.getAttrib(elms[i], events[x])) != '') {
					event = tinyMCE.cleanupEventStr("" + event);

					if (!state)
						event = "return true;" + event;
					else
						event = event.replace(/^return true;/gi, '');

					elms[i].removeAttribute(events[x]);
					elms[i].setAttribute(events[x], event);
				}
			}
		}
	}
};

TinyMCE_Engine.prototype._eventPatch = function(editor_id) {
	var n, inst, win, e;

	// Remove odd, error
	if (typeof(tinyMCE) == "undefined")
		return true;

	try {
		// Try selected instance first
		if (tinyMCE.selectedInstance) {
			win = tinyMCE.selectedInstance.getWin();

			if (win && win.event) {
				e = win.event;

				if (!e.target)
					e.target = e.srcElement;

				TinyMCE_Engine.prototype.handleEvent(e);
				return;
			}
		}

		// Search for it
		for (n in tinyMCE.instances) {
			inst = tinyMCE.instances[n];

			if (!tinyMCE.isInstance(inst))
				continue;

			inst.select();
			win = inst.getWin();

			if (win && win.event) {
				e = win.event;

				if (!e.target)
					e.target = e.srcElement;

				TinyMCE_Engine.prototype.handleEvent(e);
				return;
			}
		}
	} catch (ex) {
		// Ignore error if iframe is pointing to external URL
	}
};

TinyMCE_Engine.prototype.findEvent = function(e) {
	var n, inst;

	if (e)
		return e;

	for (n in tinyMCE.instances) {
		inst = tinyMCE.instances[n];

		if (tinyMCE.isInstance(inst) && inst.getWin().event)
			return inst.getWin().event;
	}

	return null;
};

TinyMCE_Engine.prototype.unloadHandler = function() {
	tinyMCE.triggerSave(true, true);
};

TinyMCE_Engine.prototype.addEventHandlers = function(inst) {
	this.setEventHandlers(inst, 1);
};

TinyMCE_Engine.prototype.setEventHandlers = function(inst, s) {
	var doc = inst.getDoc(), ie, ot, i, f = s ? tinyMCE.addEvent : tinyMCE.removeEvent;

	ie = ['keypress', 'keyup', 'keydown', 'click', 'mouseup', 'mousedown', 'controlselect', 'dblclick'];
	ot = ['keypress', 'keyup', 'keydown', 'click', 'mouseup', 'mousedown', 'focus', 'blur', 'dragdrop'];

	inst.switchSettings();

	if (tinyMCE.isIE) {
		for (i=0; i<ie.length; i++)
			f(doc, ie[i], TinyMCE_Engine.prototype._eventPatch);
	} else {
		for (i=0; i<ot.length; i++)
			f(doc, ot[i], tinyMCE.handleEvent);

		// Force designmode
		try {
			doc.designMode = "On";
		} catch (e) {
			// Ignore
		}
	}
};

TinyMCE_Engine.prototype.onMouseMove = function() {
	var inst, lh;

	// Fix for IE7 bug where it's not restoring hover on anchors correctly
	if (tinyMCE.lastHover) {
		lh = tinyMCE.lastHover;

		// Call out on menus and refresh class on normal buttons
		if (lh.className.indexOf('mceMenu') != -1)
			tinyMCE._menuButtonEvent('out', lh);
		else
			lh.className = lh.className;

		tinyMCE.lastHover = null;
	}

	if (!tinyMCE.hasMouseMoved) {
		inst = tinyMCE.selectedInstance;

		// Workaround for bug #1437457 (Odd MSIE bug)
		if (inst.isFocused) {
			inst.undoBookmark = inst.selection.getBookmark();
			tinyMCE.hasMouseMoved = true;
		}
	}

//	tinyMCE.cancelEvent(inst.getWin().event);
//	return false;
};

TinyMCE_Engine.prototype.cancelEvent = function(e) {
	if (!e)
		return false;

	if (tinyMCE.isIE) {
		e.returnValue = false;
		e.cancelBubble = true;
	} else {
		e.preventDefault();
		e.stopPropagation && e.stopPropagation();
	}

	return false;
};

TinyMCE_Engine.prototype.addEvent = function(o, n, h) {
	// Add cleanup for all non unload events
	if (n != 'unload') {
		function clean() {
			var ex;

			try {
				tinyMCE.removeEvent(o, n, h);
				tinyMCE.removeEvent(window, 'unload', clean);
				o = n = h = null;
			} catch (ex) {
				// IE may produce access denied exception on unload
			}
		}

		// Add memory cleaner
		tinyMCE.addEvent(window, 'unload', clean);
	}

	if (o.attachEvent)
		o.attachEvent("on" + n, h);
	else
		o.addEventListener(n, h, false);
};

TinyMCE_Engine.prototype.removeEvent = function(o, n, h) {
	if (o.detachEvent)
		o.detachEvent("on" + n, h);
	else
		o.removeEventListener(n, h, false);
};

TinyMCE_Engine.prototype.addSelectAccessibility = function(e, s, w) {
	// Add event handlers 
	if (!s._isAccessible) {
		s.onkeydown = tinyMCE.accessibleEventHandler;
		s.onblur = tinyMCE.accessibleEventHandler;
		s._isAccessible = true;
		s._win = w;
	}

	return false;
};

TinyMCE_Engine.prototype.accessibleEventHandler = function(e) {
	var win = this._win;
	e = tinyMCE.isIE ? win.event : e;
	var elm = tinyMCE.isIE ? e.srcElement : e.target;

	// Unpiggyback onchange on blur
	if (e.type == "blur") {
		if (elm.oldonchange) {
			elm.onchange = elm.oldonchange;
			elm.oldonchange = null;
		}

		return true;
	}

	// Piggyback onchange
	if (elm.nodeName == "SELECT" && !elm.oldonchange) {
		elm.oldonchange = elm.onchange;
		elm.onchange = null;
	}

	// Execute onchange and remove piggyback
	if (e.keyCode == 13 || e.keyCode == 32) {
		elm.onchange = elm.oldonchange;
		elm.onchange();
		elm.oldonchange = null;

		tinyMCE.cancelEvent(e);
		return false;
	}

	return true;
};

TinyMCE_Engine.prototype._resetIframeHeight = function() {
	var ife;

	if (tinyMCE.isRealIE) {
		ife = tinyMCE.selectedInstance.iframeElement;

/*		if (ife._oldWidth) {
			ife.style.width = ife._oldWidth;
			ife.width = ife._oldWidth;
		}*/

		if (ife._oldHeight) {
			ife.style.height = ife._oldHeight;
			ife.height = ife._oldHeight;
		}
	}
};

/* file:jscripts/tiny_mce/classes/TinyMCE_Selection.class.js */

function TinyMCE_Selection(inst) {
	this.instance = inst;
};

TinyMCE_Selection.prototype = {
	getSelectedHTML : function() {
		var inst = this.instance;
		var e, r = this.getRng(), h;

		if (!r)
			return null;

		e = document.createElement("body");

		if (r.cloneContents)
			e.appendChild(r.cloneContents());
		else if (typeof(r.item) != 'undefined' || typeof(r.htmlText) != 'undefined')
			e.innerHTML = r.item ? r.item(0).outerHTML : r.htmlText;
		else
			e.innerHTML = r.toString(); // Failed, use text for now

		h = tinyMCE._cleanupHTML(inst, inst.contentDocument, inst.settings, e, e, false, true, false);

		// When editing always use fonts internaly
		//if (tinyMCE.getParam("convert_fonts_to_spans"))
		//	tinyMCE.convertSpansToFonts(inst.getDoc());

		return h;
	},

	getSelectedText : function() {
		var inst = this.instance;
		var d, r, s, t;

		if (tinyMCE.isIE) {
			d = inst.getDoc();

			if (d.selection.type == "Text") {
				r = d.selection.createRange();
				t = r.text;
			} else
				t = '';
		} else {
			s = this.getSel();

			if (s && s.toString)
				t = s.toString();
			else
				t = '';
		}

		return t;
	},

	getBookmark : function(simple) {
		var inst = this.instance;
		var rng = this.getRng();
		var doc = inst.getDoc(), b = inst.getBody();
		var sp, le, s, e, nl, i, si, ei, w;
		var trng, sx, sy, xx = -999999999, vp = inst.getViewPort();

		sx = vp.left;
		sy = vp.top;

		if (tinyMCE.isSafari || tinyMCE.isOpera || simple)
			return {rng : rng, scrollX : sx, scrollY : sy};

		if (tinyMCE.isIE) {
			if (rng.item) {
				e = rng.item(0);

				nl = b.getElementsByTagName(e.nodeName);
				for (i=0; i<nl.length; i++) {
					if (e == nl[i]) {
						sp = i;
						break;
					}
				}

				return {
					tag : e.nodeName,
					index : sp,
					scrollX : sx,
					scrollY : sy
				};
			} else {
				trng = doc.body.createTextRange();
				trng.moveToElementText(inst.getBody());
				trng.collapse(true);
				bp = Math.abs(trng.move('character', xx));

				trng = rng.duplicate();
				trng.collapse(true);
				sp = Math.abs(trng.move('character', xx));

				trng = rng.duplicate();
				trng.collapse(false);
				le = Math.abs(trng.move('character', xx)) - sp;

				return {
					start : sp - bp,
					length : le,
					scrollX : sx,
					scrollY : sy
				};
			}
		}

		if (tinyMCE.isGecko) {
			s = this.getSel();
			e = this.getFocusElement();

			if (!s)
				return null;

			if (e && e.nodeName == 'IMG') {
				/*nl = b.getElementsByTagName('IMG');
				for (i=0; i<nl.length; i++) {
					if (e == nl[i]) {
						sp = i;
						break;
					}
				}*/

				return {
					start : -1,
					end : -1,
					index : sp,
					scrollX : sx,
					scrollY : sy
				};
			}

			// Caret or selection
			if (s.anchorNode == s.focusNode && s.anchorOffset == s.focusOffset) {
				e = this._getPosText(b, s.anchorNode, s.focusNode);

				if (!e)
					return {scrollX : sx, scrollY : sy};

				return {
					start : e.start + s.anchorOffset,
					end : e.end + s.focusOffset,
					scrollX : sx,
					scrollY : sy
				};
			} else {
				e = this._getPosText(b, rng.startContainer, rng.endContainer);

				if (!e)
					return {scrollX : sx, scrollY : sy};

				return {
					start : e.start + rng.startOffset,
					end : e.end + rng.endOffset,
					scrollX : sx,
					scrollY : sy
				};
			}
		}

		return null;
	},

	moveToBookmark : function(bookmark) {
		var inst = this.instance;
		var rng, nl, i, ex, b = inst.getBody(), sd;
		var doc = inst.getDoc();
		var win = inst.getWin();
		var sel = this.getSel();

		if (!bookmark)
			return false;

		if (tinyMCE.isSafari) {
			sel.setBaseAndExtent(bookmark.rng.startContainer, bookmark.rng.startOffset, bookmark.rng.endContainer, bookmark.rng.endOffset);
			return true;
		}

		if (tinyMCE.isRealIE) {
			if (bookmark.rng) {
				try {
					bookmark.rng.select();
				} catch (ex) {
					// Ignore
				}

				return true;
			}

			win.focus();

			if (bookmark.tag) {
				rng = b.createControlRange();

				nl = b.getElementsByTagName(bookmark.tag);

				if (nl.length > bookmark.index) {
					try {
						rng.addElement(nl[bookmark.index]);
					} catch (ex) {
						// Might be thrown if the node no longer exists
					}
				}
			} else {
				// Try/catch needed since this operation breaks when TinyMCE is placed in hidden divs/tabs
				try {
					// Incorrect bookmark
					if (bookmark.start < 0)
						return true;

					rng = inst.getSel().createRange();
					rng.moveToElementText(inst.getBody());
					rng.collapse(true);
					rng.moveStart('character', bookmark.start);
					rng.moveEnd('character', bookmark.length);
				} catch (ex) {
					return true;
				}
			}

			rng.select();

			win.scrollTo(bookmark.scrollX, bookmark.scrollY);
			return true;
		}

		if (tinyMCE.isGecko || tinyMCE.isOpera) {
			if (!sel)
				return false;

			if (bookmark.rng) {
				sel.removeAllRanges();
				sel.addRange(bookmark.rng);
			}

			if (bookmark.start != -1 && bookmark.end != -1) {
				try {
					sd = this._getTextPos(b, bookmark.start, bookmark.end);
					rng = doc.createRange();
					rng.setStart(sd.startNode, sd.startOffset);
					rng.setEnd(sd.endNode, sd.endOffset);
					sel.removeAllRanges();
					sel.addRange(rng);
					win.focus();
				} catch (ex) {
					// Ignore
				}
			}

			/*
			if (typeof(bookmark.index) != 'undefined') {
				tinyMCE.selectElements(b, 'IMG', function (n) {
					if (bookmark.index-- == 0) {
						// Select image in Gecko here
					}

					return false;
				});
			}
			*/

			win.scrollTo(bookmark.scrollX, bookmark.scrollY);
			return true;
		}

		return false;
	},

	_getPosText : function(r, sn, en) {
		var w = document.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {};

		while ((n = w.nextNode()) != null) {
			if (n == sn)
				d.start = p;

			if (n == en) {
				d.end = p;
				return d;
			}

			p += n.nodeValue ? n.nodeValue.length : 0;
		}

		return null;
	},

	_getTextPos : function(r, sp, ep) {
		var w = document.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {};

		while ((n = w.nextNode()) != null) {
			p += n.nodeValue ? n.nodeValue.length : 0;

			if (p >= sp && !d.startNode) {
				d.startNode = n;
				d.startOffset = sp - (p - n.nodeValue.length);
			}

			if (p >= ep) {
				d.endNode = n;
				d.endOffset = ep - (p - n.nodeValue.length);

				return d;
			}
		}

		return null;
	},

	selectNode : function(node, collapse, select_text_node, to_start) {
		var inst = this.instance, sel, rng, nodes;

		if (!node)
			return;

		if (typeof(collapse) == "undefined")
			collapse = true;

		if (typeof(select_text_node) == "undefined")
			select_text_node = false;

		if (typeof(to_start) == "undefined")
			to_start = true;

		if (inst.settings.auto_resize)
			inst.resizeToContent();

		if (tinyMCE.isRealIE) {
			rng = inst.getDoc().body.createTextRange();

			try {
				rng.moveToElementText(node);

				if (collapse)
					rng.collapse(to_start);

				rng.select();
			} catch (e) {
				// Throws illigal agrument in MSIE some times
			}
		} else {
			sel = this.getSel();

			if (!sel)
				return;

			if (tinyMCE.isSafari) {
				sel.setBaseAndExtent(node, 0, node, node.innerText.length);

				if (collapse) {
					if (to_start)
						sel.collapseToStart();
					else
						sel.collapseToEnd();
				}

				this.scrollToNode(node);

				return;
			}

			rng = inst.getDoc().createRange();

			if (select_text_node) {
				// Find first textnode in tree
				nodes = tinyMCE.getNodeTree(node, new Array(), 3);
				if (nodes.length > 0)
					rng.selectNodeContents(nodes[0]);
				else
					rng.selectNodeContents(node);
			} else
				rng.selectNode(node);

			if (collapse) {
				// Special treatment of textnode collapse
				if (!to_start && node.nodeType == 3) {
					rng.setStart(node, node.nodeValue.length);
					rng.setEnd(node, node.nodeValue.length);
				} else
					rng.collapse(to_start);
			}

			sel.removeAllRanges();
			sel.addRange(rng);
		}

		this.scrollToNode(node);

		// Set selected element
		tinyMCE.selectedElement = null;
		if (node.nodeType == 1)
			tinyMCE.selectedElement = node;
	},

	scrollToNode : function(node) {
		var inst = this.instance, w = inst.getWin(), vp = inst.getViewPort(), pos = tinyMCE.getAbsPosition(node), cvp, p, cwin;

		// Only scroll if out of visible area
		if (pos.absLeft < vp.left || pos.absLeft > vp.left + vp.width || pos.absTop < vp.top || pos.absTop > vp.top + (vp.height-25))
			w.scrollTo(pos.absLeft, pos.absTop - vp.height + 25);

		// Scroll container window
		if (inst.settings.auto_resize) {
			cwin = inst.getContainerWin();
			cvp = tinyMCE.getViewPort(cwin);
			p = this.getAbsPosition(node);

			if (p.absLeft < cvp.left || p.absLeft > cvp.left + cvp.width || p.absTop < cvp.top || p.absTop > cvp.top + cvp.height)
				cwin.scrollTo(p.absLeft, p.absTop - cvp.height + 25);
		}
	},

	getAbsPosition : function(n) {
		var pos = tinyMCE.getAbsPosition(n), ipos = tinyMCE.getAbsPosition(this.instance.iframeElement);

		return {
			absLeft : ipos.absLeft + pos.absLeft,
			absTop : ipos.absTop + pos.absTop
		};
	},

	getSel : function() {
		var inst = this.instance;

		if (tinyMCE.isRealIE)
			return inst.getDoc().selection;

		return inst.contentWindow.getSelection();
	},

	getRng : function() {
		var s = this.getSel();

		if (s == null)
			return null;

		if (tinyMCE.isRealIE)
			return s.createRange();

		if (tinyMCE.isSafari && !s.getRangeAt)
			return '' + window.getSelection();

		if (s.rangeCount > 0)
			return s.getRangeAt(0);

		return null;
	},

	isCollapsed : function() {
		var r = this.getRng();

		if (r.item)
			return false;

		return r.boundingWidth == 0 || this.getSel().isCollapsed;
	},

	collapse : function(b) {
		var r = this.getRng(), s = this.getSel();

		if (r.select) {
			r.collapse(b);
			r.select();
		} else {
			if (b)
				s.collapseToStart();
			else
				s.collapseToEnd();
		}
	},

	getFocusElement : function() {
		var inst = this.instance, doc, rng, sel, elm;

		if (tinyMCE.isRealIE) {
			doc = inst.getDoc();
			rng = doc.selection.createRange();

	//		if (rng.collapse)
	//			rng.collapse(true);

			elm = rng.item ? rng.item(0) : rng.parentElement();
		} else {
			if (!tinyMCE.isSafari && inst.isHidden())
				return inst.getBody();

			sel = this.getSel();
			rng = this.getRng();

			if (!sel || !rng)
				return null;

			elm = rng.commonAncestorContainer;
			//elm = (sel && sel.anchorNode) ? sel.anchorNode : null;

			// Handle selection a image or other control like element such as anchors
			if (!rng.collapsed) {
				// Is selection small
				if (rng.startContainer == rng.endContainer) {
					if (rng.startOffset - rng.endOffset < 2) {
						if (rng.startContainer.hasChildNodes())
							elm = rng.startContainer.childNodes[rng.startOffset];
					}
				}
			}

			// Get the element parent of the node
			elm = tinyMCE.getParentElement(elm);

			//if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "img")
			//	elm = tinyMCE.selectedElement;
		}

		return elm;
	}

	};

/* file:jscripts/tiny_mce/classes/TinyMCE_UndoRedo.class.js */

function TinyMCE_UndoRedo(inst) {
	this.instance = inst;
	this.undoLevels = new Array();
	this.undoIndex = 0;
	this.typingUndoIndex = -1;
	this.undoRedo = true;
};

TinyMCE_UndoRedo.prototype = {
	add : function(l) {
		var b, customUndoLevels, newHTML, inst = this.instance, i, ul, ur;

		if (l) {
			this.undoLevels[this.undoLevels.length] = l;
			return true;
		}

		if (this.typingUndoIndex != -1) {
			this.undoIndex = this.typingUndoIndex;

			if (tinyMCE.typingUndoIndex != -1)
				tinyMCE.undoIndex = tinyMCE.typingUndoIndex;
		}

		newHTML = tinyMCE.trim(inst.getBody().innerHTML);
		if (this.undoLevels[this.undoIndex] && newHTML != this.undoLevels[this.undoIndex].content) {
			//tinyMCE.debug(newHTML, this.undoLevels[this.undoIndex].content);

			tinyMCE.dispatchCallback(inst, 'onchange_callback', 'onChange', inst);

			// Time to compress
			customUndoLevels = tinyMCE.settings['custom_undo_redo_levels'];
			if (customUndoLevels != -1 && this.undoLevels.length > customUndoLevels) {
				for (i=0; i<this.undoLevels.length-1; i++)
					this.undoLevels[i] = this.undoLevels[i+1];

				this.undoLevels.length--;
				this.undoIndex--;

				// Todo: Implement global undo/redo logic here
			}

			b = inst.undoBookmark;

			if (!b)
				b = inst.selection.getBookmark();

			this.undoIndex++;
			this.undoLevels[this.undoIndex] = {
				content : newHTML,
				bookmark : b
			};

			// Remove all above from global undo/redo
			ul = tinyMCE.undoLevels;
			for (i=tinyMCE.undoIndex + 1; i<ul.length; i++) {
				ur = ul[i].undoRedo;

				if (ur.undoIndex == ur.undoLevels.length -1)
					ur.undoIndex--;

				ur.undoLevels.length--;
			}

			// Add global undo level
			tinyMCE.undoLevels[tinyMCE.undoIndex++] = inst;
			tinyMCE.undoLevels.length = tinyMCE.undoIndex;

			this.undoLevels.length = this.undoIndex + 1;

			return true;
		}

		return false;
	},

	undo : function() {
		var inst = this.instance;

		// Do undo
		if (this.undoIndex > 0) {
			this.undoIndex--;

			tinyMCE.setInnerHTML(inst.getBody(), this.undoLevels[this.undoIndex].content);
			inst.repaint();

			if (inst.settings.custom_undo_redo_restore_selection)
				inst.selection.moveToBookmark(this.undoLevels[this.undoIndex].bookmark);
		}
	},

	redo : function() {
		var inst = this.instance;

		tinyMCE.execCommand("mceEndTyping");

		if (this.undoIndex < (this.undoLevels.length-1)) {
			this.undoIndex++;

			tinyMCE.setInnerHTML(inst.getBody(), this.undoLevels[this.undoIndex].content);
			inst.repaint();

			if (inst.settings.custom_undo_redo_restore_selection)
				inst.selection.moveToBookmark(this.undoLevels[this.undoIndex].bookmark);
		}

		tinyMCE.triggerNodeChange();
	}

	};

/* file:jscripts/tiny_mce/classes/TinyMCE_ForceParagraphs.class.js */

var TinyMCE_ForceParagraphs = {
	_insertPara : function(inst, e) {
		var doc = inst.getDoc(), sel = inst.getSel(), body = inst.getBody(), win = inst.contentWindow, rng = sel.getRangeAt(0);
		var rootElm = doc.documentElement, blockName = "P", startNode, endNode, startBlock, endBlock;
		var rngBefore, rngAfter, direct, startNode, startOffset, endNode, endOffset, b = tinyMCE.isOpera ? inst.selection.getBookmark() : null;
		var paraBefore, paraAfter, startChop, endChop, contents;

		function isEmpty(para) {
			function isEmptyHTML(html) {
				return html.replace(new RegExp('[ \t\r\n]+', 'g'), '').toLowerCase() == "";
			}

			// Check for images
			if (para.getElementsByTagName("img").length > 0)
				return false;

			// Check for tables
			if (para.getElementsByTagName("table").length > 0)
				return false;

			// Check for HRs
			if (para.getElementsByTagName("hr").length > 0)
				return false;

			// Check all textnodes
			var nodes = tinyMCE.getNodeTree(para, new Array(), 3);
			for (var i=0; i<nodes.length; i++) {
				if (!isEmptyHTML(nodes[i].nodeValue))
					return false;
			}

			// No images, no tables, no hrs, no text content then it's empty
			return true;
		}

	//	tinyMCE.debug(body.innerHTML);

	//	debug(e.target, sel.anchorNode.nodeName, sel.focusNode.nodeName, rng.startContainer, rng.endContainer, rng.commonAncestorContainer, sel.anchorOffset, sel.focusOffset, rng.toString());

		// Setup before range
		rngBefore = doc.createRange();
		rngBefore.setStart(sel.anchorNode, sel.anchorOffset);
		rngBefore.collapse(true);

		// Setup after range
		rngAfter = doc.createRange();
		rngAfter.setStart(sel.focusNode, sel.focusOffset);
		rngAfter.collapse(true);

		// Setup start/end points
		direct = rngBefore.compareBoundaryPoints(rngBefore.START_TO_END, rngAfter) < 0;
		startNode = direct ? sel.anchorNode : sel.focusNode;
		startOffset = direct ? sel.anchorOffset : sel.focusOffset;
		endNode = direct ? sel.focusNode : sel.anchorNode;
		endOffset = direct ? sel.focusOffset : sel.anchorOffset;

		startNode = startNode.nodeName == "BODY" ? startNode.firstChild : startNode;
		endNode = endNode.nodeName == "BODY" ? endNode.firstChild : endNode;

		// Get block elements
		startBlock = inst.getParentBlockElement(startNode);
		endBlock = inst.getParentBlockElement(endNode);

		// If absolute force paragraph generation within
		if (startBlock && new RegExp('absolute|relative|static', 'gi').test(startBlock.style.position))
			startBlock = null;

		if (endBlock && new RegExp('absolute|relative|static', 'gi').test(endBlock.style.position))
			endBlock = null;

		// Use current block name
		if (startBlock != null) {
			blockName = startBlock.nodeName;

			// Use P instead
			if (blockName == "TD" || blockName == "TABLE" || (blockName == "DIV" && new RegExp('left|right', 'gi').test(startBlock.style.cssFloat)))
				blockName = "P";
		}

		// Within a list use normal behaviour
		if (tinyMCE.getParentElement(startBlock, "OL,UL", null, body) != null)
			return false;

		// Within a table create new paragraphs
		if ((startBlock != null && startBlock.nodeName == "TABLE") || (endBlock != null && endBlock.nodeName == "TABLE"))
			startBlock = endBlock = null;

		// Setup new paragraphs
		paraBefore = (startBlock != null && startBlock.nodeName == blockName) ? startBlock.cloneNode(false) : doc.createElement(blockName);
		paraAfter = (endBlock != null && endBlock.nodeName == blockName) ? endBlock.cloneNode(false) : doc.createElement(blockName);

		// Is header, then force paragraph under
		if (/^(H[1-6])$/.test(blockName))
			paraAfter = doc.createElement("p");

		// Setup chop nodes
		startChop = startNode;
		endChop = endNode;

		// Get startChop node
		node = startChop;
		do {
			if (node == body || node.nodeType == 9 || tinyMCE.isBlockElement(node))
				break;

			startChop = node;
		} while ((node = node.previousSibling ? node.previousSibling : node.parentNode));

		// Get endChop node
		node = endChop;
		do {
			if (node == body || node.nodeType == 9 || tinyMCE.isBlockElement(node))
				break;

			endChop = node;
		} while ((node = node.nextSibling ? node.nextSibling : node.parentNode));

		// Fix when only a image is within the TD
		if (startChop.nodeName == "TD")
			startChop = startChop.firstChild;

		if (endChop.nodeName == "TD")
			endChop = endChop.lastChild;

		// If not in a block element
		if (startBlock == null) {
			// Delete selection
			rng.deleteContents();

			if (!tinyMCE.isSafari)
				sel.removeAllRanges();

			if (startChop != rootElm && endChop != rootElm) {
				// Insert paragraph before
				rngBefore = rng.cloneRange();

				if (startChop == body)
					rngBefore.setStart(startChop, 0);
				else
					rngBefore.setStartBefore(startChop);

				paraBefore.appendChild(rngBefore.cloneContents());

				// Insert paragraph after
				if (endChop.parentNode.nodeName == blockName)
					endChop = endChop.parentNode;

				// If not after image
				//if (rng.startContainer.nodeName != "BODY" && rng.endContainer.nodeName != "BODY")
					rng.setEndAfter(endChop);

				if (endChop.nodeName != "#text" && endChop.nodeName != "BODY")
					rngBefore.setEndAfter(endChop);

				contents = rng.cloneContents();
				if (contents.firstChild && (contents.firstChild.nodeName == blockName || contents.firstChild.nodeName == "BODY"))
					paraAfter.innerHTML = contents.firstChild.innerHTML;
				else
					paraAfter.appendChild(contents);

				// Check if it's a empty paragraph
				if (isEmpty(paraBefore))
					paraBefore.innerHTML = "&nbsp;";

				// Check if it's a empty paragraph
				if (isEmpty(paraAfter))
					paraAfter.innerHTML = "&nbsp;";

				// Delete old contents
				rng.deleteContents();
				rngAfter.deleteContents();
				rngBefore.deleteContents();

				// Insert new paragraphs
				if (tinyMCE.isOpera) {
					paraBefore.normalize();
					rngBefore.insertNode(paraBefore);
					paraAfter.normalize();
					rngBefore.insertNode(paraAfter);
				} else {
					paraAfter.normalize();
					rngBefore.insertNode(paraAfter);
					paraBefore.normalize();
					rngBefore.insertNode(paraBefore);
				}

				//tinyMCE.debug("1: ", paraBefore.innerHTML, paraAfter.innerHTML);
			} else {
				body.innerHTML = "<" + blockName + ">&nbsp;</" + blockName + "><" + blockName + ">&nbsp;</" + blockName + ">";
				paraAfter = body.childNodes[1];
			}

			inst.selection.moveToBookmark(b);
			inst.selection.selectNode(paraAfter, true, true);

			return true;
		}

		// Place first part within new paragraph
		if (startChop.nodeName == blockName)
			rngBefore.setStart(startChop, 0);
		else
			rngBefore.setStartBefore(startChop);

		rngBefore.setEnd(startNode, startOffset);
		paraBefore.appendChild(rngBefore.cloneContents());

		// Place secound part within new paragraph
		rngAfter.setEndAfter(endChop);
		rngAfter.setStart(endNode, endOffset);
		contents = rngAfter.cloneContents();

		if (contents.firstChild && contents.firstChild.nodeName == blockName) {
	/*		var nodes = contents.firstChild.childNodes;
			for (var i=0; i<nodes.length; i++) {
				//tinyMCE.debug(nodes[i].nodeName);
				if (nodes[i].nodeName != "BODY")
					paraAfter.appendChild(nodes[i]);
			}
	*/
			paraAfter.innerHTML = contents.firstChild.innerHTML;
		} else
			paraAfter.appendChild(contents);

		// Check if it's a empty paragraph
		if (isEmpty(paraBefore))
			paraBefore.innerHTML = "&nbsp;";

		// Check if it's a empty paragraph
		if (isEmpty(paraAfter))
			paraAfter.innerHTML = "&nbsp;";

		// Create a range around everything
		rng = doc.createRange();

		if (!startChop.previousSibling && startChop.parentNode.nodeName.toUpperCase() == blockName) {
			rng.setStartBefore(startChop.parentNode);
		} else {
			if (rngBefore.startContainer.nodeName.toUpperCase() == blockName && rngBefore.startOffset == 0)
				rng.setStartBefore(rngBefore.startContainer);
			else
				rng.setStart(rngBefore.startContainer, rngBefore.startOffset);
		}

		if (!endChop.nextSibling && endChop.parentNode.nodeName.toUpperCase() == blockName)
			rng.setEndAfter(endChop.parentNode);
		else
			rng.setEnd(rngAfter.endContainer, rngAfter.endOffset);

		// Delete all contents and insert new paragraphs
		rng.deleteContents();

		if (tinyMCE.isOpera) {
			rng.insertNode(paraBefore);
			rng.insertNode(paraAfter);
		} else {
			rng.insertNode(paraAfter);
			rng.insertNode(paraBefore);
		}

		//tinyMCE.debug("2", paraBefore.innerHTML, paraAfter.innerHTML);

		// Normalize
		paraAfter.normalize();
		paraBefore.normalize();

		inst.selection.moveToBookmark(b);
		inst.selection.selectNode(paraAfter, true, true);

		return true;
	},

	_handleBackSpace : function(inst) {
		var r = inst.getRng(), sn = r.startContainer, nv, s = false;

		// Added body check for bug #1527787
		if (sn && sn.nextSibling && sn.nextSibling.nodeName == "BR" && sn.parentNode.nodeName != "BODY") {
			nv = sn.nodeValue;

			// Handle if a backspace is pressed after a space character #bug 1466054 removed since fix for #1527787
			/*if (nv != null && nv.length >= r.startOffset && nv.charAt(r.startOffset - 1) == ' ')
				s = true;*/

			// Only remove BRs if we are at the end of line #bug 1464152
			if (nv != null && r.startOffset == nv.length)
				sn.nextSibling.parentNode.removeChild(sn.nextSibling);
		}

		if (inst.settings.auto_resize)
			inst.resizeToContent();

		return s;
	}

	};

/* file:jscripts/tiny_mce/classes/TinyMCE_Layer.class.js */

function TinyMCE_Layer(id, bm) {
	this.id = id;
	this.blockerElement = null;
	this.events = false;
	this.element = null;
	this.blockMode = typeof(bm) != 'undefined' ? bm : true;
	this.doc = document;
};

TinyMCE_Layer.prototype = {
	moveRelativeTo : function(re, p) {
		var rep = this.getAbsPosition(re);
		var w = parseInt(re.offsetWidth);
		var h = parseInt(re.offsetHeight);
		var e = this.getElement();
		var ew = parseInt(e.offsetWidth);
		var eh = parseInt(e.offsetHeight);
		var x, y;

		switch (p) {
			case "tl":
				x = rep.absLeft;
				y = rep.absTop;
				break;

			case "tr":
				x = rep.absLeft + w;
				y = rep.absTop;
				break;

			case "bl":
				x = rep.absLeft;
				y = rep.absTop + h;
				break;

			case "br":
				x = rep.absLeft + w;
				y = rep.absTop + h;
				break;

			case "cc":
				x = rep.absLeft + (w / 2) - (ew / 2);
				y = rep.absTop + (h / 2) - (eh / 2);
				break;
		}

		this.moveTo(x, y);
	},

	moveBy : function(x, y) {
		var e = this.getElement();
		this.moveTo(parseInt(e.style.left) + x, parseInt(e.style.top) + y);
	},

	moveTo : function(x, y) {
		var e = this.getElement();

		e.style.left = x + "px";
		e.style.top = y + "px";

		this.updateBlocker();
	},

	resizeBy : function(w, h) {
		var e = this.getElement();
		this.resizeTo(parseInt(e.style.width) + w, parseInt(e.style.height) + h);
	},

	resizeTo : function(w, h) {
		var e = this.getElement();

		if (w != null)
			e.style.width = w + "px";

		if (h != null)
			e.style.height = h + "px";

		this.updateBlocker();
	},

	show : function() {
		this.getElement().style.display = 'block';
		this.updateBlocker();
	},

	hide : function() {
		this.getElement().style.display = 'none';
		this.updateBlocker();
	},

	isVisible : function() {
		return this.getElement().style.display == 'block';
	},

	getElement : function() {
		if (!this.element)
			this.element = this.doc.getElementById(this.id);

		return this.element;
	},

	setBlockMode : function(s) {
		this.blockMode = s;
	},

	updateBlocker : function() {
		var e, b, x, y, w, h;

		b = this.getBlocker();
		if (b) {
			if (this.blockMode) {
				e = this.getElement();
				x = this.parseInt(e.style.left);
				y = this.parseInt(e.style.top);
				w = this.parseInt(e.offsetWidth);
				h = this.parseInt(e.offsetHeight);

				b.style.left = x + 'px';
				b.style.top = y + 'px';
				b.style.width = w + 'px';
				b.style.height = h + 'px';
				b.style.display = e.style.display;
			} else
				b.style.display = 'none';
		}
	},

	getBlocker : function() {
		var d, b;

		if (!this.blockerElement && this.blockMode) {
			d = this.doc;
			b = d.getElementById(this.id + "_blocker");

			if (!b) {
				b = d.createElement("iframe");

				b.setAttribute('id', this.id + "_blocker");
				b.style.cssText = 'display: none; position: absolute; left: 0; top: 0';
				b.src = 'javascript:false;';
				b.frameBorder = '0';
				b.scrolling = 'no';
	
				d.body.appendChild(b);
			}

			this.blockerElement = b;
		}

		return this.blockerElement;
	},

	getAbsPosition : function(n) {
		var p = {absLeft : 0, absTop : 0};

		while (n) {
			p.absLeft += n.offsetLeft;
			p.absTop += n.offsetTop;
			n = n.offsetParent;
		}

		return p;
	},

	create : function(n, c, p, h) {
		var d = this.doc, e = d.createElement(n);

		e.setAttribute('id', this.id);

		if (c)
			e.className = c;

		if (!p)
			p = d.body;

		if (h)
			e.innerHTML = h;

		p.appendChild(e);

		return this.element = e;
	},

	exists : function() {
		return this.doc.getElementById(this.id) != null;
	},

	parseInt : function(s) {
		if (s == null || s == '')
			return 0;

		return parseInt(s);
	},

	remove : function() {
		var e = this.getElement(), b = this.getBlocker();

		if (e)
			e.parentNode.removeChild(e);

		if (b)
			b.parentNode.removeChild(b);
	}

	};

/* file:jscripts/tiny_mce/classes/TinyMCE_Menu.class.js */

function TinyMCE_Menu() {
	var id;

	if (typeof(tinyMCE.menuCounter) == "undefined")
		tinyMCE.menuCounter = 0;

	id = "mc_menu_" + tinyMCE.menuCounter++;

	TinyMCE_Layer.call(this, id, true);

	this.id = id;
	this.items = new Array();
	this.needsUpdate = true;
};

TinyMCE_Menu.prototype = tinyMCE.extend(TinyMCE_Layer.prototype, {
	init : function(s) {
		var n;

		// Default params
		this.settings = {
			separator_class : 'mceMenuSeparator',
			title_class : 'mceMenuTitle',
			disabled_class : 'mceMenuDisabled',
			menu_class : 'mceMenu',
			drop_menu : true
		};

		for (n in s)
			this.settings[n] = s[n];

		this.create('div', this.settings.menu_class);
	},

	clear : function() {
		this.items = new Array();
	},

	addTitle : function(t) {
		this.add({type : 'title', text : t});
	},

	addDisabled : function(t) {
		this.add({type : 'disabled', text : t});
	},

	addSeparator : function() {
		this.add({type : 'separator'});
	},

	addItem : function(t, js) {
		this.add({text : t, js : js});
	},

	add : function(mi) {
		this.items[this.items.length] = mi;
		this.needsUpdate = true;
	},

	update : function() {
		var e = this.getElement(), h = '', i, t, m = this.items, s = this.settings;

		if (this.settings.drop_menu)
			h += '<span class="mceMenuLine"></span>';

		h += '<table border="0" cellpadding="0" cellspacing="0">';

		for (i=0; i<m.length; i++) {
			t = tinyMCE.xmlEncode(m[i].text);
			c = m[i].class_name ? ' class="' + m[i].class_name + '"' : '';

			switch (m[i].type) {
				case 'separator':
					h += '<tr class="' + s.separator_class + '"><td>';
					break;

				case 'title':
					h += '<tr class="' + s.title_class + '"><td><span' + c +'>' + t + '</span>';
					break;

				case 'disabled':
					h += '<tr class="' + s.disabled_class + '"><td><span' + c +'>' + t + '</span>';
					break;

				default:
					h += '<tr><td><a href="' + tinyMCE.xmlEncode(m[i].js) + '" onmousedown="' + tinyMCE.xmlEncode(m[i].js) + ';return tinyMCE.cancelEvent(event);" onclick="return tinyMCE.cancelEvent(event);" onmouseup="return tinyMCE.cancelEvent(event);"><span' + c +'>' + t + '</span></a>';
			}

			h += '</td></tr>';
		}

		h += '</table>';

		e.innerHTML = h;

		this.needsUpdate = false;
		this.updateBlocker();
	},

	show : function() {
		var nl, i;

		if (tinyMCE.lastMenu == this)
			return;

		if (this.needsUpdate)
			this.update();

		if (tinyMCE.lastMenu && tinyMCE.lastMenu != this)
			tinyMCE.lastMenu.hide();

		TinyMCE_Layer.prototype.show.call(this);

		if (!tinyMCE.isOpera) {
			// Accessibility stuff
/*			nl = this.getElement().getElementsByTagName("a");
			if (nl.length > 0)
				nl[0].focus();*/
		}

		tinyMCE.lastMenu = this;
	}

	});

/* file:jscripts/tiny_mce/classes/TinyMCE_Compatibility.class.js */

if (!Function.prototype.call) {
	Function.prototype.call = function() {
		var a = arguments, s = a[0], i, as = '', r, o;

		for (i=1; i<a.length; i++)
			as += (i > 1 ? ',' : '') + 'a[' + i + ']';

		o = s._fu;
		s._fu = this;
		r = eval('s._fu(' + as + ')');
		s._fu = o;

		return r;
	};
};

/* file:jscripts/tiny_mce/classes/TinyMCE_Debug.class.js */

TinyMCE_Engine.prototype.debug = function() {
	var m = "", a, i, l = tinyMCE.log.length;

	for (i=0, a = this.debug.arguments; i<a.length; i++) {
		m += a[i];

		if (i<a.length-1)
			m += ', ';
	}

	if (l < 1000)
		tinyMCE.log[l] = "[debug] " + m;
};

//////////////////////////////////////////////////////////////////////
// EDIT - DETAILS FICHE
//
var tabContainer;
var selectedTab;
var MAX_ONG;
var GALLERY_ID = 'g';
var CONTACT_ID = 'c';
var CATALOG_ID = 'k';


//////////////////////////////////////////////////////////////////////
// Initialise les variables au onLoad de la page
//
function initVar(isEdit) {
    isEditable = isEdit;
    tabContainer = new Array();
    MAX_ONG = 6;
    selectedTab = -1;
}


//////////////////////////////////////////////////////////////////////
// Permet d'ajouter les tabs déjà cochés dans le tableau d'affichage
// au load de la page
//
function addTabToArray(id, name, tabName) {
    var tabArray = new Array();
    tabArray[tabArray.length] = id;
    tabArray[tabArray.length] = name;
    tabArray[tabArray.length] = tabName;
    tabContainer[tabContainer.length] = tabArray;
}


//////////////////////////////////////////////////////////////////////
// Au onLoad de la page, affiche le contenu correspondant, soit un
// message s'il n'y a pas d'onglets, ou le contenu de l'onglet
// sélectionné
//
function setInitialDisplay() {
    
    // Cas rien de coché
    if(tabContainer == null || !(tabContainer.length > 0)) {
        showNoTabsMsg();
    } else {
        showTabs();
        selectTab();
        if (selectedTab.toString().charAt(0) == 'g') {
            showPhotoGallery();
        } else if (selectedTab.toString().charAt(0) == 'c') {
            showContact();
        } else if (selectedTab.toString().charAt(0) == 'k') {
            showCatalog();
        } else {
            showContent();
        }
    }   
}


//////////////////////////////////////////////////////////////////////
// Construit un menu d'onglets à partir d'une liste de noms et d'id
//
function showTabs() {
    
    // Effacer le contenu du tableau d'onglets
    document.getElementById('tabsContainer').style.display = 'block';
    document.getElementById('tabs').innerHTML = '';
    
    for (i = 0; i < tabContainer.length; i++) {
        var tabArray = tabContainer[i];
        var id = tabArray[0].toString();
        var name = tabArray[1];
        var tabName = tabArray[2];

        document.getElementById('tabs').innerHTML +=    '<div id="' + id + '" onclick="shopSwapTabFiche(\'' + id + '\');" onmouseover="swapOngletFiche(\'' + id + '\', true);showCompleteName(\'' + name + '\', \'' + tabName + '\');" onmouseout="nd();swapOngletFiche(\'' + id + '\', false)">'   +
                                                        '   <div class="tabs">'   +
                                                        '       <img src="images/fiche/dark_left.jpg" id="'+id+'a" alt=""/>'   +
                                                        '   </div>'   +
                                                        '   <div class="darktabs" id="'+id+'b">'   +
                                                        '       <div class="tabstext"></span>&#160;<span id="tabName">'+tabName+'</span></div>'+
                                                        '   </div>'   +
                                                        '   <div class="tabs tabsspacer">'   +
                                                        '       <img src="images/fiche/dark_right.jpg" id="'+id+'c" alt=""/>'   +
                                                        '   </div>                                                                  '   +
                                                        '</div>                                                                     ';
    
    }
}


//////////////////////////////////////////////////////////////////////
// Afficher le nom complet en overlib
//
function showCompleteName(name, tabName) {
    if (name.length >= 7) {
        html = "<div style='font-size: 9px; font-weight: bold; padding: 2px 3px; letter-spacing: 1px;'>" + 
        name + "</div>";        
        return overlib(html, WIDTH, 200);
    }
}
        

//////////////////////////////////////////////////////////////////////
// Après l'affichage des onglets, sélectionne l'onglet relevant
//
function selectTab() {
    if (selectedTab == -1) {
        
        // Sélectionner le premier onglet
        if (tabContainer.length > 0) {
            var tabArray = tabContainer[0];
            swapOngletFiche(tabArray[0], true);
            document.getElementById(tabArray[0]).onclick = null;
            document.getElementById(tabArray[0]).onmouseover = function() {showCompleteName(tabArray[1], tabArray[2]);};
            document.getElementById(tabArray[0]).onmouseout = function() {nd(); };
            selectedTab = tabArray[0];
        }
        
    } else {
        
        // Sélectionner l'onglet déjà existant
        for (i = 0; i < tabContainer.length;i++) {
            var tabArray = tabContainer[i];
            swapOngletFiche(tabArray[0], false);
            if (selectedTab == tabArray[0]) {
                swapOngletFiche(tabArray[0], true);
            }
        }
    }
}


function hideTextContainers() {
    for (i = 0; i < tabContainer.length; i++) {
        var tabArray = tabContainer[i];

        if (!(tabArray[0].charAt(0) == 'c') && !(tabArray[0].charAt(0) == 'g')  && !(tabArray[0].charAt(0) == 'k')) { // Disparaitre les divs contenants les autres textes
            document.getElementById('txtcont'+tabArray[0]).style.display = 'none';
        }
    }
}


//////////////////////////////////////////////////////////////////////
// Gère l'ajout ou l'enlèvement des onglets selon le click sur un
// checkbox (la liste des onglets existants)
//
function addOrRemoveTab(id, tabName, name) {
    var isChecked = document.getElementById('h_'+id).value;
    
    if (isChecked == 'true') { 
        
        // Enlever 
        document.getElementById('h_'+id).value = 'false'; 
        
        for (i = 0; i < tabContainer.length; i++) {
            var tabArray = tabContainer[i];
            
            if (tabArray[0] == id) {
                for (j = i; j < tabContainer.length - 1; j++) {
                    var array = tabContainer[j + 1];
                    tabContainer[j] = array;
                }
                tabContainer.length = tabContainer.length - 1;
                
                // Si l'onglet enlevé est celui sélectionné
                if (id == selectedTab) {
                    selectedTab = -1;
                }
            }
        }
        document.getElementById('txtcont'+id).style.display = 'none';
    } else if(isChecked == 'false') {
        
        if (tabContainer.length < MAX_ONG) {
            
            // Ajouter
            document.getElementById('h_' + id).value = 'true';
            addTabToArray(id, tabName, name);
            
        } else {
            
            alert("Vous ne pouvez ajouter plus de 6 onglets !");
            document.getElementById('h_'+id).value = 'false';
            document.getElementById('c_'+id).checked = false;
            document.getElementById('txtcont'+id).style.display = 'none';
        }
    }
    
    setInitialDisplay();
    
    var status = document.getElementById('h_'+id).value;
    updateTabsInDB(id, status);
}


function updateTabsInDB(id, status) {
    doc = new XML();
    doc._method = "POST";
    doc.setAttribute("id", id);
    doc.setAttribute("isActive", status);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.sendAndLoad("actions-checkActiveTabStatus.do");
}


//////////////////////////////////////////////////////////////////////
// Affiche un message lorsqu'il n'y a pas d'onglets
//
function showNoTabsMsg() {
    document.getElementById('tabsContainer').style.display = 'none';
    document.getElementById('photoGalleryContainer').style.display = 'none';
    hideTextContainers();
    document.getElementById('contactContainer').style.display = 'none';
    document.getElementById('msgContainer').style.display = 'block';
    document.getElementById('msgContainer').innerHTML = "Il n\u0027y a pr\u00E9sentement pas d\\u0027onglets \u00E0 afficher";
}


//////////////////////////////////////////////////////////////////////
// Changer le visuel d'un onglet actif au onclick
//
function shopSwapTabFiche(id){
    //if (selectedTab.toString().charAt(0) != 'c' && selectedTab.toString().charAt(0) != 'g' && isEditable) {
    //    verifyChanges();
    //}

    var hidd = selectedTab;
    var tabArray;
    var name1;
    var tabName1;
    for (i = 0; i < tabContainer.length; i++) {
        tabArray = tabContainer [i];
        if (tabArray[0] == id) {
           name1 = tabArray[1];
           tabName1 = tabArray[2];
        }
    }
    
    var name2;
    var tabName2;
    for (i = 0; i < tabContainer.length; i++) {
        tabArray = tabContainer [i];
        if (tabArray[0] == hidd) {
           name2 = tabArray[1];
           tabName2 = tabArray[2];
        }
    }        
    
    document.getElementById(id).onclick = null;
    document.getElementById(id).onmouseover = function() {showCompleteName(name1, tabName1);};
    document.getElementById(id).onmouseout = function() {nd(); };
    
    swapOngletFiche(id,true);
    
    document.getElementById(hidd).onclick = function(){
        shopSwapTabFiche(hidd);
    };
    document.getElementById(hidd).onmouseover = function(){
        swapOngletFiche(hidd,true);
        showCompleteName(name2, tabName2);
    };
    document.getElementById(hidd).onmouseout = function(){
        swapOngletFiche(hidd,false);
        nd();
    };    
    
    swapOngletFiche(hidd,false);
    
    selectedTab = id;
    if (selectedTab.toString().charAt(0) == 'g') {
        showPhotoGallery();
    } else if (selectedTab.toString().charAt(0) == 'c') {
        showContact();
    } else if (selectedTab.toString().charAt(0) == 'k') {
        showCatalog();
    } else {
        showContent();
    }
}


//////////////////////////////////////////////////////////////////////
// Changer le visuel de l'onglet du mode "actif" au "non actif"
//
function swapOngletFiche(id, onOff){
    if(onOff){        
        document.getElementById(id+'a').src = 'images/fiche/light_left.jpg';
        document.getElementById(id+'b').className = 'lighttabs';
        document.getElementById(id+'c').src = 'images/fiche/light_right.jpg';
    }
    else{
        document.getElementById(id+'a').src = 'images/fiche/dark_left.jpg';
        document.getElementById(id+'b').className = 'darktabs';
        document.getElementById(id+'c').src = 'images/fiche/dark_right.jpg';
    }
}


//////////////////////////////////////////////////////////////////////
// Sauvegarder si changements
// NON NÉCESSAIRE POUR L'INSTANT - PASCAL
//
function saveCurrentTab(orgId) {
    for (i = 0; i < tabContainer.length; i++) {
        var tabArray = tabContainer[i];
        if (tabArray[0] == selectedTab) {
            document.getElementById('content').innerHTML = tabArray[2];
            tinyMCE.execCommand('mceResetDesignMode');
            tinyMCE.setContent(tabArray[2]);
            tabArray[2] = tinyMCE.getContent();
            tinyMCE.setContent(tabArray[2]);
            tabContainer[i] = tabArray;
            
            doc = new XML();
            doc._method = "POST";
            doc.setAttribute("organizationId", orgId);
            doc.setAttribute("tabId", tabArray[0]);
            doc.setAttribute("name", tabArray[1]);
            doc.setAttribute("content", '<div>'+tabArray[2]+'</div>');
            doc.setAttribute("uniqId", Math.round(Math.random()*10000));
            doc.sendAndLoad("actions-updateTab.do");
            
            alert("Changements sauvegardés");
        }
    }
}


//////////////////////////////////////////////////////////////////////
// Si on onglet change, demander de sauvegarder les changements
// NON NÉCESSAIRE POUR L'INSTANT - PASCAL
//
function verifyChanges() {
    // Doit trouver une nouvelle façon de vérifier les changements...
}


//////////////////////////////////////////////////////////////////////
// Affiche le formulaire d'ajout d'onglet
//
function openAddTabForm() {
    if (document.getElementById('h_addTabForm').value == 'false' )  {
        document.getElementById('h_addTabForm').value = true;
        document.getElementById('addTabForm').style.display = 'block';
        document.getElementById('t_addTabForm').innerHTML = 'Cacher le formulaire d\'ajout d\'un onglet';
    } else {
        document.getElementById('h_addTabForm').value = false;
        document.getElementById('addTabForm').style.display = 'none';
        document.getElementById('t_addTabForm').innerHTML = 'Afficher le formulaire d\'ajout d\'un onglet';
    }
}


//////////////////////////////////////////////////////////////////////
// Permet de ne pas afficher l'onglet Gallerie en mode Affichage
// EN CONSTRUCTION ! - PASCAL
//
function showGalleryTab(id, name) {
    var isChecked = document.getElementById('galleryid_' + id).value;
    
    if (isChecked == 'true') {

        // Enlever
        document.getElementById('galleryid_' + id).value = 'false';
        
        for (i = 0; i < tabContainer.length; i++) {
            var tabArray = tabContainer[i];

            if (tabArray[0] == 'g' + id) {
                for (j = i; j < tabContainer.length - 1; j++) {
                    var array = tabContainer[j + 1];
                    tabContainer[j] = array;
                }
                tabContainer.length = tabContainer.length - 1;
            
                // Si l'onglet enlevé est celui sélectionné
                if ('g' + id == selectedTab) {
                    selectedTab = -1;
                }
            }
        }
    } else {

        if (tabContainer.length < MAX_ONG) {

            // Ajouter
            document.getElementById('galleryid_' + id).value = 'true';
            addTabToArray('g' + id, name, '');

        } else {

            alert("Vous ne pouvez ajouter plus de 6 onglets !");
            document.getElementById('galleryid_' + id).value = 'false';
            document.getElementById('gallerycbox_' + id).checked = false;
        }
    }

    setInitialDisplay();
}


//////////////////////////////////////////////////////////////////////
// Affiche le contenu de l'onglet actif en mode edit
//
function showContent() {    
    if(isEditable){        
        document.getElementById('msgContainer').style.display = 'none';
    }

    document.getElementById('photoGalleryContainer').style.display = 'none';
    document.getElementById('contactContainer').style.display = 'none';
    document.getElementById('catalogContainer').style.display = 'none';
    hideTextContainers();
    document.getElementById('txtcont'+selectedTab).style.display = 'block';
}


//////////////////////////////////////////////////////////////////////
// Affiche le contenu de l'onglet "Affichage"
//
function showPhotoGallery() {
    if (isEditable) {
        document.getElementById('msgContainer').style.display = 'none';
    }
    
    hideTextContainers();
    document.getElementById('contactContainer').style.display = 'none';
    document.getElementById('photoGalleryContainer').style.display = 'block';
    document.getElementById('catalogContainer').style.display = 'none';
}


//////////////////////////////////////////////////////////////////////
// Affiche le contenu de l'onglet "Coordonnée"
//
function showContact() {
    if (isEditable) {
        document.getElementById('msgContainer').style.display = 'none';
    }
    
    hideTextContainers();
    document.getElementById('contactContainer').style.display = 'block';
    document.getElementById('photoGalleryContainer').style.display = 'none';
    document.getElementById('catalogContainer').style.display = 'none';
}


//////////////////////////////////////////////////////////////////////
// Affiche le contenu de l'onglet "Catalogue"
//
function showCatalog() {
    if (isEditable) {
        document.getElementById('msgContainer').style.display = 'none';
    }
    
    hideTextContainers();
    document.getElementById('contactContainer').style.display = 'none';
    document.getElementById('photoGalleryContainer').style.display = 'none';
    document.getElementById('catalogContainer').style.display = 'block';
}

function showEmail(v, n){
    document.write(decodeEmail(v, n));		
}

function decodeEmail(v, n){
    var c = v.split(";");	
    var r = "";	
    var k = c.length & 1;
    
    for(var i=c.length-2;i>=0;i--){
        r += String.fromCharCode(c[i] >> (((i + k) & 1) + 1));
    }
    
    if(!n){
        n = r;
    }
    
    return "<a href='mailto:"+r+"'>"+n+"</a>";
}

function chgBigImgInGallery(mediaId){                   
    document.getElementById('bigLeftGal').src = 'uploaded/InfoPage/Gallery/' + mediaId + '-Large.jpg';                                            
}
function _expandNode(id, elemid){
    if(document.getElementById(id).style.display == 'none'){
        document.getElementById(id).style.display = 'block';
        document.getElementById(elemid).src = 'images/open.jpg';
    }
    else{
        document.getElementById(id).style.display = 'none';
        document.getElementById(elemid).src = 'images/closed.jpg';
    }
}    

function _chooseCategory(id) {
    document.getElementById('radio_'+id).checked = true;
    document.getElementById('input_categoryId').value = id;
}







/**********************/
// CODE BELOW: POUR L'ONGLET BOUTIQUE DES FICHE D'ENTREPRISES
/**********************/

var boutiqueOrganizationId = -1;
var boutiqueIsAdmin = false;
var boutiqueCategoryId = -1337;
var boutiqueCurrentProdPage = 0;
var boutiqueMySpace = false;

function setBoutiqueOrganizationId(organizationId) {
    boutiqueOrganizationId = organizationId;
}

function setBoutiqueMySpace(f) {
    boutiqueMySpace = f;
}

function setAdmin(isAdmin) {
    boutiqueIsAdmin = isAdmin;
}

function boutiqueLoadAllCategories(categoryId) {    
    if(boutiqueCategoryId == categoryId)
        return;
    
    boutiqueCategoryId = categoryId;
    
    
    var doc = new XML();     
    doc._method = 'POST';
    
    doc.setAttribute('categoryId', categoryId);
    doc.setAttribute('organizationId', boutiqueOrganizationId);
    doc.setAttribute('uniqId', Math.round(Math.random() * 10000));
    
    doc.addListener(onBoutiqueAllCategoriesLoaded); 
    doc.sendAndLoad('actions-ListCategoriesByOrgAndCat.do');
    
    if(boutiqueIsAdmin) {
	document.getElementById('lnkNew').href = 'page-shopcreateproduct.do?organizationId=' + boutiqueOrganizationId + '&redirect=infopage';
    }
}

function onBoutiqueAllCategoriesLoaded(response) {
    var div = document.getElementById('BoutiqueCategories');
    var xmldoc = response.responseXML.documentElement;
    
    var cats = getItems(xmldoc, 'Category').items();
    var count = cats.length;
    
    if(count == 0) {
        div.innerHTML = 'Aucun produit à afficher.';
        return;
    }
    
    var outhtml = '';   
    
    for(var i = 0; i < count; i++) { 
        var id = parseInt(cats[i].getAttribute('id'));
        var name = cats[i].getAttribute('name');
        var countProducts = parseInt(cats[i].getAttribute('products'));
        var has_childs = cats[i].getAttribute('has_childs');
        
        outhtml += '<div>';
        outhtml += '<img src="img/bullets/news_bullet_orange.jpg" style="margin-bottom: 1px;" />';
        outhtml += '<span style="margin-left: 10px;"><a class="GrayA" href="javascript:';
        if(has_childs == 'true') {
            outhtml += 'boutiqueLoadAllCategories(' + id + ')';
        }
        else {
            outhtml += 'boutiqueLoadProducts(' + id + ')';
        }
        outhtml += '">' + name + ' ('+countProducts+' produits)' +  '</a></span>';
        outhtml += '</div>';
    }   
    
    boutiqueReloadCategoryPath();
    div.innerHTML = outhtml;
}

function boutiqueLoadCategory(categoryId) {    
    if(boutiqueCategoryId == categoryId)
        return;
    
    boutiqueCategoryId = categoryId;
    
    
    var doc = new XML();     
    doc._method = 'POST';
    
    doc.setAttribute('categoryId', categoryId);
    doc.setAttribute('organizationId', boutiqueOrganizationId);
    doc.setAttribute('uniqId', Math.round(Math.random() * 10000));
    
    doc.addListener(onBoutiqueCategoriesLoaded); 
    doc.sendAndLoad('actions-GetCategoriesByOrgShop.do');
    
    if(boutiqueIsAdmin) {
	document.getElementById('lnkNew').href = 'page-shopcreateproduct.do?organizationId=' + boutiqueOrganizationId + '&redirect=infopage';
    }
    
}

function onBoutiqueCategoriesLoaded(response) {
    var div = document.getElementById('BoutiqueCategories');
    var xmldoc = response.responseXML.documentElement;
    
    var cats = getItems(xmldoc, 'Category').items();
    var count = cats.length;
    
    if(count == 0) {
        div.innerHTML = 'Aucun produit à afficher.';
        return;
    }
    
    var outhtml = '';   
    
    for(var i = 0; i < count; i++) { 
        var id = parseInt(cats[i].getAttribute('id'));
        var name = cats[i].getAttribute('name');
        var countProducts = parseInt(cats[i].getAttribute('countProducts'));
        
        outhtml += '<div>';
        outhtml += '<img src="img/bullets/news_bullet_orange.jpg" style="margin-bottom: 1px;" />';
        outhtml += '<span style="margin-left: 10px;"><a href="javascript:';
        if(countProducts == 0) {
            outhtml += 'boutiqueLoadCategory(' + id + ')';
        }
        else {
            outhtml += 'boutiqueLoadProducts(' + id + ')';
        }
        outhtml += '">' + name + '</a></span>';
        outhtml += '</div>';
    }   
    
    boutiqueReloadCategoryPath();
    div.innerHTML = outhtml;
}

function boutiqueLoadProducts(categoryId) {
    if(boutiqueCategoryId == categoryId)
        return;
    
    boutiqueCategoryId = categoryId;
    
    
    var doc = new XML();     
    doc._method = 'POST';
    
    doc.setAttribute('categoryId', categoryId);
    doc.setAttribute('organizationId', boutiqueOrganizationId);
    doc.setAttribute('ppp', 5);
    doc.setAttribute('page', boutiqueCurrentProdPage);
    doc.setAttribute('uniqId', Math.round(Math.random() * 10000));
    
    doc.addListener(onBoutiqueProductsLoaded); 
    doc.sendAndLoad('actions-GetProductsByCatAndOrg.do');
    
    if(boutiqueIsAdmin) {
	document.getElementById('lnkNew').href = 'page-shopcreateproduct.do?organizationId=' + boutiqueOrganizationId + '&redirect=infopage&categoryId=' + categoryId;
    }    
}

function onBoutiqueProductsLoaded(response) {
    var xmldoc = response.responseXML.documentElement;
    
    var prods = getItems(xmldoc, 'product').items();
    var outhtml = '';    
    var numProducts = parseInt(getItems(xmldoc, 'count').items()[0].getAttribute('count'));
    var shopNbPages = numProducts / 5;
    if (Math.round(shopNbPages) < shopNbPages)
        shopNbPages = Math.round(shopNbPages) + 1;
    else
        shopNbPages = Math.round(shopNbPages);

    var num = prods.length;
    if(num == 0) {
        document.getElementById('BoutiqueCategories').innerHTML = 'Aucun produit à afficher.';
        return;
    }

    for(var i = 0; i < num; i++) { 
        //VARIABLES POUR LE CONTENU DES FIELDS
        var model = "";
        var make = "";       
        var price = "0";        
        var prodId = prods[i].getAttribute('id');

        outhtml += '<div>';
        
        //DÉFINITIONS DES VARIABLES POUR LE CONTENU DES FIELDS
        var fields = getItems(prods[i], "field").items();
        var fieldsL = fields.length;
        
        for(var j = 0; j < fieldsL; j++) {
            var field = fields[j].getAttribute('name');
            switch(field) {
                case "model":
                    model = fields[j].getAttribute('value');
                    break;
                case "make":
                    make = fields[j].getAttribute('value');
                    break;    
                case "price":
                    price = fields[j].getAttribute('value');
                    break;    
             }
        }
        
        if(price == "0")
          price = "N/D";


        //SECTION D'AJOUT DE L'IMAGE 
        var galleries = getItems(prods[i], "gallery").items();
        var galleriesL = galleries.length;
        for (var j = 0; j < galleriesL; j++) {
            if(galleries[j].getAttribute('name') == "productimages") {
                var images = getItems(galleries[j], "media").items();
                for(var k = 0; k < images.length; k++) {
                    var image = images[k].getAttribute('urlsmall');
		    outhtml += '<div style="float: left; margin-right: 15px;">';
                    outhtml += '<a href="page-shopitem.do?productId=' + prodId + '">';
                    outhtml += '<img src="' + images[k].getAttribute('urlsmall') + '" alt="" class="imgBoutique" />';
                    outhtml += '</a>';
		    outhtml += '</div>';
                }
            }
        }

        
        //SECTION D'AJOUT DES DÉTAILS DU PRODUIT
	outhtml += '<div style="float: left;">';
	
        outhtml += '<div class="BoutiqueProductTitle">';
        outhtml += '<a class="GrayA" href="page-shopitem.do?productId=' + prodId + '">' + model + '</a>';
        outhtml += '</div>';
        outhtml += '<div class="BoutiqueProductMake">de ' + make + '</div>';
	if(boutiqueIsAdmin) {
	    outhtml += '<div style="margin-top: 10px;"><a style="font-size: 11px;" class="GrayA" href="page-shopeditproduct.do?productId=' + prodId + '&redirect=infopage">Modifier ce produit</a></div>';
	    outhtml += '<div><a style="font-size: 11px;" class="GrayA" href="javascript:DeleteProductAction(' + prodId + ', \'' + model + '\')">Supprimer ce produit</a></div>';
	}
        else {
            if(price == 0) {
              outhtml += '<div>Prix: N/A</div>';
            }
            else {
                outhtml += '<div>Prix: ' + price + ' $</div>';
            }
        }
	
        outhtml += '</div>';
		
		
	outhtml += '</div>';	
	outhtml += '<div style="clear: both; height: 10px;"></div>'
	outhtml += '<div class="BoutiqueSeparatorBox"></div>';
    }


    boutiqueReloadCategoryPath();
    document.getElementById('BoutiqueCategories').innerHTML = outhtml;
}

function boutiqueReloadCategoryPath() {
    var doc = new XML();     
    doc._method = 'POST';
    
    doc.setAttribute('categoryId', boutiqueCategoryId);
    
    doc.addListener(onBoutiqueCategoryPathLoaded); 
    doc.sendAndLoad('actions-GetBoutiqueCategoriesPath.do');
}

function onBoutiqueCategoryPathLoaded(response) {
    var xmldoc = response.responseXML.documentElement;
    
    var cats = getItems(xmldoc, 'Category').items();
    var outhtml = '';   

    for(var i = 0; i < cats.length; i++) {      
        var id = cats[i].getAttribute('id');
        var name = cats[i].getAttribute('name');
        
        if(boutiqueMySpace && name == 'Boutique') {
            name = 'Mes produits';
        }
        
        outhtml += '<img src="img/bullets/news_bullet_gray.jpg" /> ';
        
        if(boutiqueMySpace) {
           outhtml += '<a href="javascript:boutiqueLoadAllCategories('+id+')">'+name+'</a>'; 
        }
        else {
          outhtml += '<a href="javascript:boutiqueLoadCategory('+id+')">'+name+'</a>';
        }
        if(i < cats.length-1) {
            outhtml += ' ';
        }
    }        
    
    document.getElementById('BoutiquePath').innerHTML = outhtml;
}


function DeleteProductAction(prodId, name) {
    var conf = confirm("Êtes vous sur de vouloir supprimer le produit '" + name + "' ?");
    
    if(conf == true) {
        var doc = new XML();     
        doc._method = 'POST';
    
        doc.setAttribute('productId', prodId);    
        doc.setAsyn(false);
        doc.sendAndLoad('actions-shopDeleteProductAjax.do');
    
        var i = boutiqueCategoryId;
        boutiqueCategoryId = -1337;
        boutiqueLoadProducts(i);
    }
}

// END OF NCHOBOUTIQUE

function changeToVisible(elementId) {
    document.getElementById(elementId).style.visibility = 'visible';
} 

function changeToHidden(elementId) {
    document.getElementById(elementId).style.visibility = 'hidden';
}

function productGalleryImgOver(mediaId, urllarge) {    
    document.getElementById('bigLeftGal').src = urllarge;  
    document.getElementById('boxGallery-' + mediaId).style.border = '1px solid black';
}

function productGalleryImgOut(mediaId) {    
    document.getElementById('boxGallery-' + mediaId).style.border = '1px solid #CCCCCC';
}



var lockedGalleryProductMedia = -1;
function AdminProductGalleryImgOver(mediaId, urllarge) {  
    if(lockedGalleryProductMedia == -1) {
        document.getElementById('bigLeftGal').src = urllarge;  
        document.getElementById('boxGallery-' + mediaId).style.border = '1px solid black';
    }
}

function AdminProductGalleryImgOut(mediaId) {    
    if(lockedGalleryProductMedia == -1) {
        document.getElementById('boxGallery-' + mediaId).style.border = '1px solid #CCCCCC';
    }
}

function AdminProductGalleryClick(mediaId, urllarge) {
    if(mediaId == lockedGalleryProductMedia) {    
        AdminProductGalleryReload(lockedGalleryProductMedia, -1);
        document.getElementById('boxGallery-' + lockedGalleryProductMedia).style.border = '1px solid #CCCCCC';
        lockedGalleryProductMedia = -1;
        return;
    }

    if(lockedGalleryProductMedia != -1) {
        AdminProductGalleryReload(lockedGalleryProductMedia, mediaId);
        
        document.getElementById('boxGallery-' + lockedGalleryProductMedia).style.border = '1px solid #CCCCCC';
        lockedGalleryProductMedia = -1;
        
        document.getElementById('bigLeftGal').src = urllarge;   
        
        lockedGalleryProductMedia = mediaId;
        document.getElementById('boxGallery-' + mediaId).style.border = '1px solid black';
    }
    else {
        AdminProductGalleryReload(-1, mediaId);
        
        lockedGalleryProductMedia = mediaId;
        document.getElementById('boxGallery-' + mediaId).style.border = '1px solid black';
    }
}


function AdminProductGalleryReload(mediaIdToHide, mediaIdToShow) {
    if(mediaIdToHide != -1) {
        document.getElementById('editPhotosDiv-' + mediaIdToHide).style.display = 'none';
        //alert('hiding editPhotosDiv-' + mediaIdToShow);
    }
    else
        document.getElementById('addPhotosDiv').style.display = 'none'; 
    
    
    if(mediaIdToShow != -1) {
        document.getElementById('editPhotosDiv-' + mediaIdToShow).style.display = 'block';
      //  alert('showing editPhotosDiv-' + mediaIdToShow);
    }
    else {
        document.getElementById('addPhotosDiv').style.display = 'block'; 
    }
}

function modifyGalleryTitle(infopageId) {
    var div = document.getElementById('photoGalleryTitle');
    var title = div.value;
    
    
    var hi = function(response) {
        alert('Le titre de la galerie a été modifié.');
    }
    
    var doc = new XML();     
    doc._method = 'POST';
    
    doc.setAttribute('title', title);
    doc.setAttribute('infopageId', infopageId);
    doc.setAttribute('uniqId', Math.round(Math.random() * 10000));
    
    doc.addListener(hi); 
    doc.sendAndLoad('actions-ajaxChangeGalleryTitle.do');
}


/*

function getAdminProdsPager() {
    var pagesOffset = 2;    
    var outhtml = '';
    
    
    outhtml += '<div class="navigation bottom" style="margin-top: 3px;">';    
    outhtml += '<div class="pageLinks">';
    outhtml += '<div class="pages">';      
    // first + previous
    if(shopCurrentPage > 0) {
        outhtml += '<div class="pageLink btn">';
        outhtml += '<a href="javascript:getProdsByOrganization(0)">';
        outhtml += '<img src="images/btn/btn-pager-first-off.gif"  onmouseout="swap(this);" onmouseover="swap(this);" title="Première Page" alt="Première Page"/>';
        outhtml += '</a>&#160;';
        outhtml += '</div>';
        
        outhtml += '<div class="pageLink btn">';
        outhtml += '<a href="javascript:getProdsByOrganization(' + (shopCurrentPage-1) + ')">';
        outhtml += '<img src="images/btn/btn-pager-previous-off.gif"  onmouseout="swap(this);" onmouseover="swap(this);" title="Page Pr\u00E9c\u00E9dente" alt="Page Pr\u00E9c\u00E9dente" />';
        outhtml += '</a>&#160;';
        outhtml += '</div>';
    }    
    
    var start = 0;
    if(shopCurrentPage > pagesOffset) {
        start = shopCurrentPage - pagesOffset;
        outhtml += '<div class="more">...</div>';
    }    
    for(var i = start; i < shopCurrentPage; i++) 
        outhtml += '<div class="pageLink"><a href="javascript:getProdsByOrganization(' + i + ')">' + (i + 1) + '</a><span class="pageSpacer"> </span></div>';
    outhtml += '<div class="pageLink curPage"><strong class="pageLink">' + (shopCurrentPage+1) + '</strong><span class="pageSpacer"> </span></div>';
    start = shopCurrentPage + 1;
    var end = shopNbPages;
    if(end > start + pagesOffset)
        end = start + pagesOffset;
    for(var i = start; i < end; i++) 
        outhtml += '<div class="pageLink"><a href="javascript:getProdsByOrganization(' + i + ')">' + (i + 1) + '</a><span class="pageSpacer"> </span></div>';
    if(end != shopNbPages)
        outhtml += '<div class="more">...</div>';
    
    // next + last
    if((shopCurrentPage+1) < shopNbPages) {
        outhtml += '<div class="pageLink btn">';
        outhtml += '<a href="javascript:getProdsByOrganization(' + (shopCurrentPage+1) + ')">';
        outhtml += '<img src="images/btn/btn-pager-next-off.gif"  onmouseout="swap(this);" onmouseover="swap(this);" title="Page Suivante" alt="Page Suivante"/>';
        outhtml += '</a>&#160;';
        outhtml += '</div>';
        
        outhtml += '<div class="pageLink btn">';
        outhtml += '<a href="javascript:getProdsByOrganization(' + (shopNbPages-1) + ')">';
        outhtml += '<img src="images/btn/btn-pager-last-off.gif"  onmouseout="swap(this);" onmouseover="swap(this);" title="Dernière Page" alt="Dernière Page" />';
        outhtml += '</a>&#160;';
        outhtml += '</div>';
    }  
    
    
    outhtml += '</div>';
    outhtml += '</div>';
    outhtml += '<div class="pages pageSelector">';
    outhtml += '<a class="pageLink" href="javascript:void(0);" onclick="return ProdsShowPageSelector();" onmouseout="return nd();">' + shopNbPages + ' Page' + (shopNbPages > 1 ? 's' : '') + '</a>';
    outhtml += '</div><div class="pages"> | </div><div class="pages pagerCount"><strong>' + numProducts + '</strong> r\u00E9sultat' + (numProducts > 1 ? 's' : '') + '</div></div>';
    

    return outhtml;
}

function ProdsShowPageSelector(){
    return overlib(
    '<input type="text" id="page" style="margin-right: 2px;width:60px" />' +
    '<input type="button" class="pageSelectBtn" value="Ok" style="width: 30px;" onclick="getProdsByOrganization(parseInt(document.getElementById(\'page\').value)-1); return nd();"/>', 
    STICKY, CAPTION, 'Aller &agrave; la page', CENTER, OFFSETY, -70, WIDTH, 100, HEIGHT, 24);
}



function AdminProductGalleryImgOver(mediaId, urllarge) {  
    if(lockedGalleryProductMedia == -1) {
        document.getElementById('bigLeftGal').src = urllarge;  
        document.getElementById('boxGallery-' + mediaId).style.border = '1px solid black';
    }
}

*/










function updateOrgType(id, org_name) {
    var type = document.getElementById('type' + id).value;
    document.getElementById('submit' + id).style.display = 'none';
    
    var retfunc = function(response) {      
        var div = document.getElementById('lnk'+id);
        
        if(type == 'normal') {
            div.href = 'page-admin-entr.do?organizationId=' + id;
            alert("L'entreprise '" + org_name + "' est maintenant une entreprise sans partenariat.");
        }
        else if(type == 'card') {
            div.href = 'page-admin-entr.do?organizationId=' + id + '&card';
            alert("L'entreprise '" + org_name + "' possède maintenant une carte d'affaire.");
        }
        else if(type == 'infopage') {
            div.href = 'page-admin-entr.do?organizationId=' + id + '&fiche';
            alert("L'entreprise '" + org_name + "' possède maintenant une fiche d'entreprise.");
        }
        else if(type == 'boutique') {
            div.href = 'page-admin-entr.do?organizationId=' + id + '&fiche';
            alert("L'entreprise '" + org_name + "' possède maintenant une boutique.");
        }
    };
    
    var doc = new XML();    
    doc.method = 'POST';    
    doc.setAsyn(false);   
    doc.addListener(retfunc);                   
    doc.setAttribute('uniqId', Math.round(Math.random()*10000));
    doc.setAttribute('organizationId', id);
    doc.setAttribute('type', type);
    doc.sendAndLoad('actions-setOrgType.do');
}

function activerOrg(id, org_name) {
    var spanTxt = document.getElementById('txtAct_' + id);
    var suspendre = true;
    var url = 'actions-suspendOrganization.do?noredirect&organizationId=' + id;
    
    var retfunc = function(response) {      
        if(suspendre) {
            alert("L'entreprise '" + org_name + "' est maintenant suspendue.");
            spanTxt.innerHTML = 'Activer';
        }
        else {
            alert("L'entreprise '" + org_name + "' est maintenant active.");
            spanTxt.innerHTML = 'Suspendre';
        }
    };
    
    
    if(spanTxt.innerHTML == 'Activer') {        
        suspendre = false;
        url += '&u=1';
    }
    
    var doc = new XML();    
    doc.method = 'GET';    
    doc.setAsyn(false);   
    doc.addListener(retfunc);                   
    doc.sendAndLoad(url);
}



// hey gaetanne, les fonctions admin pour les bannieres sont en dessous
function displayZoneInfo(sel) {
    var div = document.getElementById('adminbZoneInfo1');
    var lbl = document.getElementById('adminbZoneLabel1');
    var id = sel.options[sel.selectedIndex].value;
    if (id == -1) {
        div.style.display = "none";
        lbl.style.display="none;"
    } else {
        lbl.style.display="block";
        div.style.display = "block";
        doc = new XML(); 
        doc.addListener(onLoadedZoneInfo);
        doc._method = "POST";
        doc.setAttribute("zoneId", id);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.sendAndLoad("actions-ajaxZoneInfo.do");
    }
}

function onLoadedZoneInfo(response) {
    var desc = document.getElementById('adminbZoneDesc');
    var dim = document.getElementById('adminbZoneDim');
    var camp = document.getElementById('adminbZoneCampaign');
    var doc = response.responseXML.documentElement;
    desc.innerHTML = "Description: " + doc.getAttribute("description");
    dim.innerHTML = "Dimension: " + doc.getAttribute("width") + " x " + doc.getAttribute("height") + " pixels";
    camp.innerHTML = "Campagne: " + doc.getAttribute("campaign");
}

function deleteBannerZone() {
    var form = document.getElementById('adminbRemoveZone');
    if (confirm(Labels['js.deleteBannerZone.eraseZone'])) {
        form.submit();
    }
}

function categorySwap(id) {
    var avail = document.getElementById('admingavail');
    var curr = document.getElementById('admingcurr');
    var swapDiv = document.getElementById('gcat-'+id);
    if (swapDiv.parentNode.getAttribute("id") == "admingcurr") {
        curr.removeChild(swapDiv);
        avail.appendChild(swapDiv);
    } else {
        avail.removeChild(swapDiv);
        curr.appendChild(swapDiv);
    }
    updateGroupCategoryIds(curr);
}

function updateGroupCategoryIds(container) {
    var gaetannes = container.childNodes;
    var ids = "";
    for (var i = 0; i < gaetannes.length; i++) {
        if (gaetannes[i].nodeType == 1) {
            ids += (gaetannes[i].getAttribute("id") + ",");
        }
    }
    ids += "END";
    document.getElementById('idsInput').value = ids;
}

function zoneSwap(id) {
    var avail = document.getElementById('admingzavail');
    var curr = document.getElementById('admingzcurr');
    var swapDiv = document.getElementById('gzone-'+id);
    if (swapDiv.parentNode.getAttribute("id") == "admingzcurr") {
        curr.removeChild(swapDiv);
        avail.appendChild(swapDiv);
    } else {
        avail.removeChild(swapDiv);
        curr.appendChild(swapDiv);
    }
    updateGroupZoneIds(curr);
}

function updateGroupZoneIds(container) {
    var gaetannes = container.childNodes;
    var ids = "";
    for (var i = 0; i < gaetannes.length; i++) {
        if (gaetannes[i].nodeType == 1) {
            ids += (gaetannes[i].getAttribute("id") + ",");
        }
    }
    ids += "END";
    document.getElementById('idsInputZ').value = ids;
}

function displayBannerInfo(sel) {
    var div = document.getElementById('adminbBannerInfo1');
    var id = sel.options[sel.selectedIndex].value;
    if (id == -1) {
        div.style.display = "none";
    } else {
        div.style.display = "block";
        doc = new XML(); 
        doc.addListener(onLoadedBannerInfo);
        doc._method = "POST";
        doc.setAttribute("bannerId", id);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.sendAndLoad("actions-ajaxBannerInfo.do");
    }
}

function onLoadedBannerInfo(response) {
    var title = document.getElementById('adminbBannertitle');
    var href = document.getElementById('adminbBannerhref');
    var zone = document.getElementById('adminbBannerzone');
    var img = document.getElementById('adminbBannerimage');
    var target = document.getElementById('adminbBannertarget');
    var doc = response.responseXML.documentElement;
    var tar = doc.getAttribute("target");
    removeAllOptions(target);
    if (tar == '_blank') {
        addOption(target, 'blank', '_blank', true);
        addOption(target, 'self', '_self', false);
    } else {
        addOption(target, 'blank', '_blank', false);
        addOption(target, 'self', '_self', true);
    }
    title.value = doc.getAttribute("title");
    href.value = doc.getAttribute("href");
    zone.innerHTML = "Zone: " + doc.getAttribute("zoneName");
    img.src = doc.getAttribute("mediaUrl");
}

function deleteBanner() {
    var form = document.getElementById('adminbBannerForm');
    form.action = "actions-adminbRemoveBanner.do";
    form.submit();
}

function updateBanner() {
    var form = document.getElementById('adminbBannerForm');
    form.action = "actions-adminbUpdateBanner.do";
    form.submit();
}

function editProfile() {
    var persC = new CountriesProvincesSelect('selectCountries', 'selectProvinces', 'province_lbl');    
    persC.setDefault(document.getElementById('orgCountryId').innerHTML, document.getElementById('orgProvinceId').innerHTML);
    persC.loadCountries();
    
    for (var i = 1; i <= 13; i++) {
        var div1 = document.getElementById('profileData'+i);
        var div2 = document.getElementById('profileInput'+i);
        if(div1 != null)
          div1.style.display = "none";
        if(div2 != null)
          div2.style.display = "block";
    }
    
    for (var i = 1; i <= 6; i++) {
        var div = document.getElementById('show_required_field' + i);
        if(div != null) {
            document.getElementById('show_required_field' + i).style.display= 'inline';
        }
    }    
    
    document.getElementById('profileModBtn').style.display = "none";
    document.getElementById('profileUpdateBtn').style.display = "block";
    document.getElementById('profileCancelBtn').style.display = "block";   
}

function undoEditProfile() {
    for (var i = 1; i <= 13; i++) {
        var div1 = document.getElementById('profileData'+i);
        var div2 = document.getElementById('profileInput'+i);
        if(div1 != null)
          div1.style.display = "block";
        if(div2 != null)
          div2.style.display = "none";
    }
    
    for (var i = 1; i <= 6; i++) {
        var div = document.getElementById('show_required_field' + i);
        if(div != null) {
            document.getElementById('show_required_field' + i).style.display= 'none';
        }
    }   
    
    document.getElementById('profileModBtn').style.display = "block";
    document.getElementById('profileUpdateBtn').style.display = "none";
    document.getElementById('profileCancelBtn').style.display = "none";
}

function switch2valuesDisplay(idblock,idnone,annuler){
    if (annuler) {
        emptyPass();
    }
    document.getElementById(idblock).style.display = 'block';
    document.getElementById(idnone).style.display = 'none';                
}                            

function emptyPass(){
    document.getElementById('clonePassword').value = "";
    document.getElementById('srcPassword').value = "";
}

function comparePasswords(){
    var first = document.getElementById('srcPassword').value;
    var second = document.getElementById('clonePassword').value;
    if((first == "")&&(second == "")){
        return true;
    }
    else if(first == second){
        return true;
    }
    else{
        alert('Les mots de passes de correspondent pas.');
        return false;
    }
}

function editProfileRet() {
    var ret = comparePasswords();
    if(ret == false)
        return false;
    return tb.handleSubmit();
 }


var countNewOffices = 1;

function showDivsIAm(){
    target = document.getElementById('individual').checked;    
    
    if(target){
        document.getElementById("checkorgs").style.display = "none";
        document.getElementById("didyoufindit").style.display= "none";
        document.getElementById("choicemanager").style.display = "none";
        document.getElementById("orgdoesntshow").style.display = "none";
        document.getElementById("personinfo").style.display = "block";
        document.getElementById("completeorginfos").style.display = "none";
        document.getElementById("orgclassify").style.display = "none";
        document.getElementById("subsbottom").style.display = "block";
        document.getElementById("memberorg").style.display = "block";
    }else{
        document.getElementById("checkorgs").style.display = "block";
        document.getElementById("didyoufindit").style.display= "none";
        document.getElementById("choicemanager").style.display = "none";
        document.getElementById("orgdoesntshow").style.display = "none";
        document.getElementById("personinfo").style.display = "block";
        document.getElementById("completeorginfos").style.display = "none";
        document.getElementById("orgclassify").style.display = "none";
        document.getElementById("subsbottom").style.display = "block";
        document.getElementById("memberorg").style.display = "none";
    }
}

function showDivsPartOfOrg(rep)
{
    if(rep == "no")
        document.getElementById("checkorgs").style.display = "none";
    else
        document.getElementById("checkorgs").style.display = "block";
}

function showChoiceFound(){
    document.getElementById("didyoufindit").style.display= "block";
}

function lookForMainContact() {
    var orgId = document.getElementById('organizationSelelection').options[document.getElementById('organizationSelelection').selectedIndex].value;
    doc = new XML(); 
    doc._method = "POST";
    doc.addListener(onLookedForContact);    
    doc.setAttribute("organizationId", orgId);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.sendAndLoad("actions-hasMainContact.do");
}

function onLookedForContact(response) {
    var xmldoc = response.responseXML.documentElement;    
    var hasMainContact = false;

    
    
    var items = getItems(xmldoc, "MainContact").items();
    if(items[0].getAttribute("hasMainContact") == "true") {
        hasMainContact = true;
    }    


    if (hasMainContact == false) {
        document.getElementById('alertTitle').innerHTML = "Il n'y a pr&eacute;sentement aucun compte associ&eacute; &agrave; cette entreprise.";
        document.getElementById('alertMessage').innerHTML = "Pour devenir administrateur de cette entreprise, <a class=\"GrayA\" style=\"text-decoration: underline;\" href=\"javascript:submitOrganizationForm('true')\">cliquez ici</a>";
        document.getElementById('alertBox').style.display="block";
        //document.getElementById('formInscriptionEntreprise').submit();
    }
    else {
        document.getElementById('alertTitle').innerHTML = "Il y a d&eacute;j&agrave; un compte qui est administrateur de cette entreprise";
        document.getElementById('alertMessage').innerHTML = "Si vous d&eacute;sirez devenir l'administrateur de cette entreprise, <a class=\"GrayA\" style=\"text-decoration: underline;\" href=\"javascript:callReplaceMainContactForm()\">cliquez ici</a>";
        document.getElementById('alertBox').style.display="block";
    }
}

function callReplaceMainContactForm() {

    var orgId = document.getElementById('organizationSelelection').options[document.getElementById('organizationSelelection').selectedIndex].value;
    window.location = "page-inscriptionorgremplacer.do?orgId="+orgId;

}


function fillOrgForm(orgId) {
    doc = new XML(); 
    doc.addListener(onFillSignupOrg);    
    doc.setAttribute("organizationId", orgId);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.sendAndLoad("actions-getOrgInfo.do");
}

function redirectIfOwner(orgId) {
    var ret = function(response) {
        var doc = response.responseXML.documentElement;
        
            
        var xmldoc = response.responseXML.documentElement;
      var contactsgbl = getItems(xmldoc, "Persons").items();
      var conts = getItems(contactsgbl[0], "Person").items();
      var contsL = conts.length;
      var hasMainContact = "false";

      for(var i1=0; i1<contsL; i1++){
          var contact = conts[i1];
          var isMainContact = (getItems(contact, "mainContact").items())[0].firstChild.nodeValue;
          if (isMainContact == "true") {
              hasMainContact = "true";
              break;
          }
      }
         
        if(hasMainContact == "true") {
            window.location = 'page-inscriptionorgremplacer.do?orgId=' + orgId;
        }
    };
    
    doc = new XML(); 
    doc.addListener(ret);    
    doc.setAttribute("organizationId", orgId);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.setAsyn(false);
    doc.sendAndLoad("actions-guideOrganizationProfil.do");
}

function onFillSignupOrg(response) {
    var doc = response.responseXML.documentElement;
    document.getElementById('orgName_text').value = doc.getAttribute("name");
    document.getElementById('orgAddress_text').value = doc.getAttribute("address");
    document.getElementById('orgAddress2_text').value = doc.getAttribute("address2");
    document.getElementById('orgCity_text').value = doc.getAttribute("city");
    document.getElementById('orgProvince_hidden').value = doc.getAttribute("province");
    document.getElementById('orgCountry_hidden').value = doc.getAttribute("country");
    document.getElementById('orgPostalCode_text').value = doc.getAttribute("postalCode");
    var mail = decodeEmail(doc.getAttribute("email"));    
    mail = mail.replace(/<a([^<]*)>([^<]*)<\/a>/g, '$2');
    document.getElementById('orgEmail_text').value = mail;
    document.getElementById('orgWeb_text').value = doc.getAttribute("web");
    document.getElementById('orgPhone_text').value = doc.getAttribute("phone");
    document.getElementById('orgFax_text').value = doc.getAttribute("fax");
}

function loadOrgForm(orgId) {
    doc = new XML(); 
    doc.addListener(onLoadSignupOrg);    
    doc.setAttribute("organizationId", orgId);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.sendAndLoad("actions-getOrgInfo.do");
}

function onLoadSignupOrg(response) {
    var doc = response.responseXML.documentElement;
    document.getElementById('org1').innerHTML = doc.getAttribute("name");
    document.getElementById('org2').innerHTML = doc.getAttribute("address");
    document.getElementById('org3').innerHTML = doc.getAttribute("address2");
    document.getElementById('org4').innerHTML = doc.getAttribute("city");
    document.getElementById('org5').innerHTML = doc.getAttribute("province");
    document.getElementById('org6').innerHTML = doc.getAttribute("country");
    document.getElementById('org7').innerHTML = doc.getAttribute("postalCode");
    document.getElementById('org8').innerHTML = decodeEmail(doc.getAttribute("email"));
    document.getElementById('org9').innerHTML = doc.getAttribute("web");
    /*document.getElementById('org10').innerHTML = doc.getAttribute("phone");
    document.getElementById('org11').innerHTML = doc.getAttribute("fax");*/
  
}

function clearOrgInfoField() {
    for (var i = 1; i<=9; i++) {
        var fieldName = "org"+i;
        document.getElementById(fieldName).innerHTML = "";
    }
    document.getElementById('contName').innerHTML = "";
}

function foundOrNot(target){
    if(target.id == "foundorgidyes"){
        loadOrgForm();
        document.getElementById("choicemanager").style.display = "block"; 
        document.getElementById("orgdoesntshow").style.display = "none";
        document.getElementById("completeorginfos").style.display = "none";
        document.getElementById("orgclassify").style.display = "none";
        document.getElementById("choicemanageryes").checked = false;
        document.getElementById("choicemanagerno").checked = false;
        document.getElementById("subsbottom").style.display = "none";
        /*for(i=1;i<10;i++){
            document.getElementById("org"+i).readOnly = true;
            document.getElementById("org"+i).style.backgroundColor = "#FFFFCC";
            document.getElementById("org_error"+i).style.display = "none";
            document.getElementById("org"+i).style.borderColor = "#666";
            document.getElementById("orglabel"+i).innerHTML = "";
        } */       
    }else{
        for(i=1;i<10;i++){
            document.getElementById("org"+i).value = "";
        }
        document.getElementById("choicemanager").style.display = "none"; 
        document.getElementById("orgdoesntshow").style.display = "block";
        document.getElementById("completeorginfos").style.display = "none";
        document.getElementById("orgclassify").style.display = "none";
        document.getElementById("doesntshowyes").checked = false;
        document.getElementById("doesntshowno").checked = false;
        document.getElementById("subsbottom").style.display = "none";
    }
}

function manageOrNot(target){
    document.getElementById("completeorginfos").style.display = "block";
    document.getElementById("orgclassify").style.display = "none"; 
    document.getElementById("subsbottom").style.display = "block";
    /*if(target.id == "choicemanageryes"){
        document.getElementById("personinfo").style.display = "block";
        document.getElementById("completeorginfos").style.display = "block";
        document.getElementById("orgclassify").style.display = "none";
        document.getElementById("subsbottom").style.display = "block";          
        for(i=1;i<10;i++){
            document.getElementById("org"+i).readOnly = false;
            document.getElementById("org"+i).style.backgroundColor = "#FFF";
            document.getElementById("orglabel"+i).innerHTML = "*";
        }      
    }else{
        document.getElementById("personinfo").style.display = "block";
        document.getElementById("completeorginfos").style.display = "block";
        document.getElementById("orgclassify").style.display = "none"; 
        document.getElementById("subsbottom").style.display = "block";
        for(i=1;i<10;i++){
            document.getElementById("org"+i).readOnly = true;
            document.getElementById("orglabel"+i).innerHTML = "";
            document.getElementById("org"+i).style.backgroundColor = "#FFFFCC";
            document.getElementById("org_error"+i).style.display = "none";
            document.getElementById("org"+i).style.borderColor = "#666";
        }         
    }*/
}

function subOrNot(target){
    if(target.id == "doesntshowyes"){
        document.getElementById("completeorginfos").style.display = "block";
        document.getElementById("orgclassify").style.display = "block"; 
        document.getElementById("subsbottom").style.display = "block";       
        for(i=1;i<10;i++){
            document.getElementById("org"+i).innetHTML = "";
            document.getElementById("org"+i).readOnly = false;
            document.getElementById("org"+i).style.backgroundColor = "#FFF";
            //document.getElementById("orglabel"+i).innerHTML = "*";
        }
    }else{
        document.getElementById("completeorginfos").style.display = "none";
        document.getElementById("orgclassify").style.display = "none";
        document.getElementById("subsbottom").style.display = "block";
        for(i=1;i<10;i++){
            document.getElementById("org"+i).readOnly = true;
            //document.getElementById("orglabel"+i).innerHTML = "";
            document.getElementById("org"+i).style.backgroundColor = "#FFFFCC";
            document.getElementById("org"+i).style.borderColor = "#666";
            document.getElementById("org"+i).innetHTML = "";
        }
        document.getElementById("org_error1").style.display = "none";
        document.getElementById("org_error2").style.display = "none";
        document.getElementById("org_error4").style.display = "none";
        document.getElementById("org_error5").style.display = "none";
        document.getElementById("org_error6").style.display = "none";
        document.getElementById("org_error8").style.display = "none";
        
    }
}


/* Fonction pour valider l'inscription */
function submitValidation(){    
    if(document.getElementById('completeorginfos').style.display != 'block'){
        return tb.handleSubmit();
    }else{
        var bool = tb.handleSubmit();        
        var bool2 = tb2.handleSubmit();        
        if(document.getElementById('categories').value == "" && document.getElementById('orgclassify').style.display == "block"){       
            alert(Labels['js.submitValidation.err']);
            document.getElementById('selectedSubCategoryList').style.backgroundColor = "#ffffcb";
            return false;
        }
        else{
            document.getElementById('selectedSubCategoryList').style.backgroundColor = "#FFF";    
            return bool && bool2;
        }
    }
}

/* Fonction pour valider la modification d'une entreprise */
function submitValidationModif() {
     if(document.getElementById('categories') != null && document.getElementById('categories').value == ""){
        alert(Labels['js.submitValidation.err']);
        document.getElementById('selectedSubCategoryList').style.backgroundColor = "#ffffcb";
        return false;
    }
    else{
        if(document.getElementById('selectedSubCategoryList') != null)
            document.getElementById('selectedSubCategoryList').style.backgroundColor = "#FFF";    
        return tb.handleSubmit();
    }
}

function validateEmail(email){
    
    try {            
        
        var callback = function(response) {
            if(response.responseXML.firstChild.textContent != 'false'){
                alert(Labels['js.validateEmail.invalidEmail']);
            }          
        };        
        
        doc = new XML();
        doc.addListener(callback);
        doc.setAttribute("email", email);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.sendAndLoad("actions-existsUser.do");
    } catch(e) {
        alert(e);
    }
}

function searchEntreprises() {
    var valq = document.forms['formInscriptionEntreprise'].q;
    if (valq.value.length >= 3) {
    document.getElementById("selectionTitre").style.visibility = "hidden";
    document.getElementById("organizationSelelection").style.visibility = "hidden";
    document.getElementById("inscriptionOptionsAfterSearch").style.visibility = "hidden";
    document.getElementById("orgInfo").style.visibility = "hidden";
    doc = new XML();     
    doc.setAttribute("q", document.formInscriptionEntreprise.q.value);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));   
    doc.addListener(onSearchedEntreprises); 
    doc.sendAndLoad("actions-searchOrganizations.do");
    }
    else {
        alert("La recherche doit \u00EAtre d\u0027un minimum de 3 caract\u00E8res");
    }
}

function onSearchedEntreprises(response) {
    var xmldoc = response.responseXML;
    var liste = document.getElementById("organizationSelelection");
    var GBLorgs = getItems(xmldoc, "Organizations").items();
    var GBLorgsL = GBLorgs.length;
    if (GBLorgsL != 0) {
        document.getElementById("selectionTitre").style.visibility = "visible";
        document.getElementById("organizationSelelection").style.visibility = "visible";
        document.getElementById("inscriptionOptionsAfterSearch").style.visibility = "visible";
    }
    var orgs = getItems(GBLorgs[0], "Organization").items();
    //var orgs = xmldoc.evaluate('//Organization', xmldoc, null, XPathResult.ANY_TYPE, null) ;
    var orgsL = orgs.length;
    removeAllOptions(liste);
    for(var i1=0; i1<orgsL; i1++){
        var org = orgs[i1];
        addOption(liste, org.getAttribute("name"), org.getAttribute("id"), false);
    }

}

function submitOrganizationForm(isfound) {

    if (isfound == 'false') {
        document.getElementById('formInscriptionEntreprise').action="page-inscriptionorgnotfound.do";
        document.getElementById('formInscriptionEntreprise').onSubmit="";
        document.getElementById('formInscriptionEntreprise').submit();
    }
    else if(isfound == 'true') {
        var selectionBox = document.getElementById('organizationSelelection');
        var orgId = selectionBox.options[selectionBox.selectedIndex].value;
        document.getElementById('formInscriptionEntreprise').action="page-inscriptionmodifentreprises.do?organizationId="+orgId;
        document.getElementById('formInscriptionEntreprise').submit();
    }

} 

function noenter() {
    if (window.event.keyCode == 13) {
        document.getElementById("goButton").performClick();
        window.event.keyCode =0;
    }
  //return !(window.event && window.event.keyCode == 13); 
}

function updateSearchButtons() {
    if (document.getElementById('subCategoriesList').selectedIndex != -1) {
        document.getElementById('addButton').style.visibility="visible";
    }
    else {
        document.getElementById('addButton').style.visibility="hidden";
    }
}


function specialHandleSubmit(tb) {
    if (tb.handleSubmit() == false) {
        return false;
    }
    else if(CategoryManager.selectedSubCategories.length < 1) {
        alert("Vous devez minimalement sélectionner une catégorie pour que votre entreprise soit affichée dans le Bâtiguide.");
        return false;
    }
    else {
        return true;
    }
}

/*function getInscriptionOfficeInfo(tempOfficeId) {
    document.forms['frmOrgCreation'].
)*/

function inscriptionAddOffice() {
    var selectedValue = document.forms['frmOrgCreation'].officeSelection.options[document.forms['frmOrgCreation'].officeSelection.selectedIndex].value;
    if (selectedValue == 0) {
        document.getElementById('newOfficesField').innerHTML = document.getElementById('newOfficesField').innerHTML +
        "<div id=\"officeDiv_"+countNewOffices+"\">"+
        "<input type=\"hidden\" name=\"office_name_"+countNewOffices+"\" value=\""+document.forms['frmOrgCreation'].office_name.value+"\" />"+
        "<input type=\"hidden\" name=\"office_address_"+countNewOffices+"\" value=\""+document.forms['frmOrgCreation'].office_address.value+"\" />"+
        "<input type=\"hidden\" name=\"office_city_"+countNewOffices+"\" value=\""+document.forms['frmOrgCreation'].office_city.value+"\" />"+
        "<input type=\"hidden\" name=\"office_postalCode_"+countNewOffices+"\" value=\""+document.forms['frmOrgCreation'].office_postalCode.value+"\" />"+
        "<input type=\"hidden\" name=\"office_fax_"+countNewOffices+"\" value=\""+document.forms['frmOrgCreation'].office_fax.value+"\" />"+
        "<input type=\"hidden\" name=\"office_phone_"+countNewOffices+"\" value=\""+document.forms['frmOrgCreation'].office_phone.value+"\" />"+
        "<input type=\"hidden\" name=\"office_cell_"+countNewOffices+"\" value=\""+document.forms['frmOrgCreation'].office_cell.value+"\" />"+
        "<input type=\"hidden\" name=\"office_tollFree_"+countNewOffices+"\" value=\""+document.forms['frmOrgCreation'].office_tollFree.value+"\" />"+
        "<input type=\"hidden\" name=\"office_country_"+countNewOffices+"\" value=\""+document.forms['frmOrgCreation'].officePays.value+"\" />"+
        "<input type=\"hidden\" name=\"office_province_"+countNewOffices+"\" value=\""+document.forms['frmOrgCreation'].officeProvince.value+"\" />";
        document.forms['frmOrgCreation'].officeSelection.innerHTML = document.forms['frmOrgCreation'].officeSelection.innerHTML +
        "<option value=\""+countNewOffices+"\">"+document.forms['frmOrgCreation'].office_name.value+"</option>";
        countNewOffices++;
        document.forms['frmOrgCreation'].officeSelection.selectedIndex=document.forms['frmOrgCreation'].officeSelection.length-1;
        document.forms['frmOrgCreation'].officeCount.value++;
        document.getElementById('addOrModifyButton').value="Modifier";
    }
    else {
        inscriptionEditOffice();
    }
}

function inscriptionEditOffice() {
        var selectedValue = document.forms['frmOrgCreation'].officeSelection.options[document.forms['frmOrgCreation'].officeSelection.selectedIndex].value;
        document.getElementById('officeDiv_'+selectedValue).innerHTML = 
        "<input type=\"hidden\" name=\"office_name_"+selectedValue+"\" value=\""+document.forms['frmOrgCreation'].office_name.value+"\" />"+
        "<input type=\"hidden\" name=\"office_address_"+selectedValue+"\" value=\""+document.forms['frmOrgCreation'].office_address.value+"\" />"+
        "<input type=\"hidden\" name=\"office_city_"+selectedValue+"\" value=\""+document.forms['frmOrgCreation'].office_city.value+"\" />"+
        "<input type=\"hidden\" name=\"office_postalCode_"+selectedValue+"\" value=\""+document.forms['frmOrgCreation'].office_postalCode.value+"\" />"+
        "<input type=\"hidden\" name=\"office_fax_"+selectedValue+"\" value=\""+document.forms['frmOrgCreation'].office_fax.value+"\" />"+
        "<input type=\"hidden\" name=\"office_phone_"+selectedValue+"\" value=\""+document.forms['frmOrgCreation'].office_phone.value+"\" />"+
        "<input type=\"hidden\" name=\"office_cell_"+selectedValue+"\" value=\""+document.forms['frmOrgCreation'].office_cell.value+"\" />"+
        "<input type=\"hidden\" name=\"office_tollFree_"+selectedValue+"\" value=\""+document.forms['frmOrgCreation'].office_tollFree.value+"\" />"+
        "<input type=\"hidden\" name=\"office_country_"+selectedValue+"\" value=\""+document.forms['frmOrgCreation'].officePays.value+"\" />"+
        "<input type=\"hidden\" name=\"office_province_"+selectedValue+"\" value=\""+document.forms['frmOrgCreation'].officeProvince.value+"\" />";
        document.forms['frmOrgCreation'].officeSelection.options[document.forms['frmOrgCreation'].officeSelection.selectedIndex].innerHTML = document.forms['frmOrgCreation'].office_name.value;
}

function getInscriptionOfficeInfo(optionValue) {
    inscriptionClearOfficeInfo();
    if (optionValue != 0) {
        document.forms['frmOrgCreation'].office_name.value = document.forms['frmOrgCreation'].elements['office_name_'+optionValue].value;
        document.forms['frmOrgCreation'].office_address.value = document.forms['frmOrgCreation'].elements['office_address_'+optionValue].value;
        document.forms['frmOrgCreation'].office_city.value = document.forms['frmOrgCreation'].elements['office_city_'+optionValue].value;
        document.forms['frmOrgCreation'].office_postalCode.value = document.forms['frmOrgCreation'].elements['office_postalCode_'+optionValue].value;
        document.forms['frmOrgCreation'].office_fax.value = document.forms['frmOrgCreation'].elements['office_fax_'+optionValue].value;
        document.forms['frmOrgCreation'].office_phone.value = document.forms['frmOrgCreation'].elements['office_phone_'+optionValue].value;
        document.forms['frmOrgCreation'].office_cell.value = document.forms['frmOrgCreation'].elements['office_cell_'+optionValue].value;
        document.forms['frmOrgCreation'].office_tollFree.value = document.forms['frmOrgCreation'].elements['office_tollFree_'+optionValue].value;
        document.getElementById('addOrModifyButton').value="Modifier";
    }
    else {
        
        document.getElementById('addOrModifyButton').value="Ajouter";
    }
}

function inscriptionDeleteOffice(officeIndex) {
    if (officeIndex != 0) {
        var officeValue = document.forms['frmOrgCreation'].officeSelection.options[officeIndex].value;
        var divInfoOffice = "officeDiv_"+officeValue;
        document.getElementById(divInfoOffice).innerHTML = "";
        document.forms['frmOrgCreation'].officeSelection.options[officeIndex] = null;
        if (document.forms['frmOrgCreation'].officeSelection.selectedIndex) {
            document.forms['frmOrgCreation'].officeSelection.selectedIndex = officeIndex;
        }
        else {
            officeIndex--;
            document.forms['frmOrgCreation'].officeSelection.selectedIndex = officeIndex;
        }
    }
    inscriptionClearOfficeInfo();
    document.getElementById('addOrModifyButton').value="Ajouter";
    if (officeIndex != 0) {
        var selectionValue = document.forms['frmOrgCreation'].officeSelection.options[officeIndex].value;
        getInscriptionOfficeInfo(selectionValue);
        document.getElementById('addOrModifyButton').value="Modifier";
    }
}

function inscriptionClearOfficeInfo() {
    document.forms['frmOrgCreation'].office_name.value = "";
    document.forms['frmOrgCreation'].office_address.value =  "";
    document.forms['frmOrgCreation'].office_city.value =  "";
    document.forms['frmOrgCreation'].office_postalCode.value =  "";
    document.forms['frmOrgCreation'].office_fax.value =  "";
    document.forms['frmOrgCreation'].office_phone.value =  "";
    document.forms['frmOrgCreation'].office_cell.value =  "";
    document.forms['frmOrgCreation'].office_tollFree.value =  "";
}

function selectOrgChanged(orgId) {
    clearOrgInfoField(); 
    loadOrgForm(orgId);
    lookForMainContact();
    document.getElementById('orgInfo').style.visibility = 'visible';
}

function submitRecherche() {

    document.getElementById('gobutton').click();
    return false;
    
}

/* Les onglets dans le MyAccount */
function changeTabSize(name,onOff,classe){
    if(classe != 'big'){
        if (onOff) {
            document.getElementById(name+'1').className = 'bigTabLeft';
            document.getElementById(name+'2').className = 'bigTabCenter';
            document.getElementById(name+'3').className = 'bigTabRight';
        }
        else {
            document.getElementById(name+'1').className = 'smallTabLeft';
            document.getElementById(name+'2').className = 'smallTabCenter';
            document.getElementById(name+'3').className = 'smallTabRight';
        }
    }
} 

function menuOver(menuItem){
    if(menuItem.className.indexOf("selected") == -1){
        menuItem.style.backgroundColor = '#B3D0F0';
    }
}

function menuOut(menuItem){
    if(menuItem.className.indexOf("selected") == -1){
        menuItem.style.backgroundColor = '#FFFFFF';
    }
}

var currentPagerUrl = null;
var currentNbPages = 1;
function showPageSelector(url, nbPages){
    
    var params = url.split("?");    
    var hiddenInputs = "";    
    if(params.length > 1){
        var ps = params[1].split("&");
        for(var pp in ps){
            var temp = ps[pp].split("=");
            hiddenInputs += '<input type="hidden" name="'+temp[0]+'" value="'+temp[1]+'"/>';
        }
    }
    
    currentPagerUrl = url;
    currentNbPages = nbPages; 
    return overlib(
    '<form action="'+url+'" method="get" name="pageSelectorForm">' + hiddenInputs + 
    '<input type="text" name="page" style="margin-right: 2px;width:60px" />' +
    '<input type="button" class="pageSelectBtn" value="Ok" style="width: 30px;" onclick="goToSelectedPage()"/></form>', 
    STICKY, CAPTION, 'Aller &agrave; la page', CENTER, OFFSETY, -70, WIDTH, 100, HEIGHT, 24);
}

function goToSelectedPage(){
    var page = parseInt(document.forms.pageSelectorForm.page.value);
    if(isNaN(page) || page < 1){
        page = 1;
    }else if(page > currentNbPages){
        page = currentNbPages;
    }
    window.location = currentPagerUrl + "&page=" + page;
}

function showRefuseContact(url){
    
    var params = url.split("?");    
    var hiddenInputs = "";    
    if(params.length > 1){
        var ps = params[1].split("&");
        for(var pp in ps){
            var temp = ps[pp].split("=");
            hiddenInputs += '<input type="hidden" name="'+temp[0]+'" value="'+temp[1]+'"/>';
        }
    }
    
    return overlib(
    '<form action="'+params[0]+'" method="get" name="refuseContactForm">' + hiddenInputs + 
    '<input type="text" name="comments" style="width:200px; height: 40px;" />' +
    '<input type="submit" value="Confirmer le refus" /></form>', 
    STICKY, CAPTION, 'Pourquoi refusez vous ce contact?', LEFT, OFFSETY, -50, WIDTH, 100, HEIGHT, 24, BGCOLOR, '#65543A');
}

function showEmail(v, n){
    document.write(decodeEmail(v, n));		
}

function decodeEmail(v, n){
    var c = v.split(";");	
    var r = "";	
    var k = c.length & 1;
    
    for(var i=c.length-2;i>=0;i--){
        r += String.fromCharCode(c[i] >> (((i + k) & 1) + 1));
    }
    
    if(!n){
        n = r;
    }
    
    return "<a href='mailto:"+r+"'>"+n+"</a>";
}

function swap(img){
    var str = img.src;
    if(str.indexOf("-off.") != -1){
        str = str.replace("-off.", "-on.");
    }else{
        str = str.replace("-on.", "-off.");
    }
    img.src = str;
    img.setAttribute("src", str);
}

function swapImgSrc(img, src){
    img.setAttribute("src", src);
}

function hideDiv(target) {
    document.getElementById(target).style.display = "none";
}

function displayShopImage(urll){
    return overlib('<img src="'+urll+'" />', HEIGHT, 300, WIDTH, 280, OFFSETY, -140);
}

/*This function give a maximum length to the target's string*/
function txtMaxLength(target,maxLength){ 
    if (target.value.length > maxLength){
        target.value = target.value.substring(0, maxLength);
    }
}

/*This function puts a line break in the target's string at the number of caracter specified*/
function txtLineBreak(target,lineBreakValue){
    var line = target.value.split('\n');
    console.info(line[line.length-1].length);
    if (line[line.length-1].length == lineBreakValue){
        target.value += "\n"; 
    }    
}

/*This function strips a caracter in a given string*/
function stripCaracter(target,caracter){
    var str = document.getElementById(target).value;
    var strFinal = "";
    for (i = 0; i < str.length; i++) {
        if(str.charAt(i) != caracter){
            strFinal += str.charAt(i);
        }else{
            strFinal += " ";
        }
    }
    document.getElementById(target).value = strFinal;
}

function validateSubmit(text){            
    if(confirm(text)){
        return true;
    }
    return false;     
}

function validateSubmitAndDetach(text, elementId){            
    if(confirm(text)){
        detach(elementId);
        return true;
    }
    return false;     
}

function validateSearch(value){
    
    if(!value){
        value = "";
    }
    
    value = value.replace(/^\s*|\s*$/g, "");
    
    if(value.length < 3){        
        alert(Labels['js.validateSearch.threeChars']);
        return false;
    }
    return true;
}

function detach(elementId) {
    var gncho = document.getElementById(elementId);
    gncho.parentNode.removeChild(gncho);
}

function outputSubBanner(groupName){
    document.write('<object type="application/x-shockwave-flash" data="swf/subbanner.swf?group=' + 
    groupName + '" width="710" height="54">' +
    '<param name="movie" value="swf/subbanner.swf?group='+ groupName +'" /></object>');
}

function selectPollVote() {
    document.getElementById('votePollConfirm').value = 'confirm';
}

function submitPollVote() {
    if (document.getElementById('votePollConfirm').value == "") {        
        alert('Vous devez sélectionner une option avant de voter.');
    } else {
        document.getElementById('votePoll').submit();
    }
}

function removeJob(jobId, srcPage) {    
    if (confirm(Labels['js.removeJob.delJob'])) {
        window.location='actions-jobsRemoveJob.do?jobId='+jobId+'&srcPage='+srcPage;
    }
}

function signupNewsletter() {
    
    return overlib(
    '<form action="actions-signupNewsletter.do" method="get">' +
    'Pr\u00E9nom:<br/><input type="text" name="firstName" style="width: 200px; height: 20px;" /><br/>' +
    'Nom:<br/><input type="text" name="lastName" style="width: 200px; height: 20px;" /><br/>' +
    'Courriel:<br/><input type="text" name="email" style="width: 200px; height: 20px;" /><br/>' +
    '<input type="submit" class="pageSelectBtn" value="Envoyer" /></form>', 
    STICKY, CAPTION, 'Info Lettre', LEFT, OFFSETY, -150, WIDTH, 150, HEIGHT, 150);
    
}

function getVoteResults(pollId) {
    doc = new XML(); 
    doc.addListener(onLoadedPollResults);
    doc._method = "POST";
    doc.setAttribute("pollId", pollId);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.sendAndLoad("actions-ajaxPoll.do");
}

function onLoadedPollResults(response) {
    //document.getElementById('mainSearchSelect').style.visibility = "hidden";
    var doc = response.responseXML.documentElement;
    var items = getItems(doc, "PollOption").items();
    var len = items.length;
    var html = "<table width=\"100%\" cellpading=\"0\" cellspacing=\"0\" style=\"s-index: 1337;\">";
    var totalVotes = 0;
    html += '<tr style="background-color: #DEDBD6; height: 25px; text-transform: uppercase; font-weight: bold;">';
    html += '<td colspan="2" style="color: #000000;">&#160;R\u00E9sultats</td>';
    html += '<td align="right"><a href="#X" onclick="return closePollVote()" style="color: #000000; font-size: 12px;" id="xclickOverlib">X</a>&#160;</td></tr>';
    html += '<tr><td colspan="3" style="height: 4px;"> </td></tr>';
    for(var i=0; i<len; i++){
        var item = items[i];
        if(item.getAttribute("value") == null || item.getAttribute("value") == '')
          continue;
        var percentage = item.getAttribute("percentage");
        var width = parseInt(percentage);
        totalVotes += parseInt(item.getAttribute("votes"));
        html += "<tr>";
        html += '<td style="padding-left: 5px;" width="130">'+item.getAttribute("value")+'</td>'
        + '<td width="100"><img src="images/percentage_bar.jpg" alt="'
        + percentage +'" style="width: '+width+'px; height: 10px;"/></td>'
        + '<td>'+ percentage +'%</td>';
        html += "</tr>";
    }
    html += "<tr><td></td><td></td><td><strong>" + totalVotes + " Votes</strong></td></tr>";
    html += '<tr><td colspan="3" style="height: 4px;"> </td></tr>';
    html += "</table>";
    
    return overlib(
    html, 
    STICKY, LEFT, OFFSETX, -10, OFFSETY, 40, WIDTH, 300, HEIGHT, (20 * len));
}


function closePollVote() {
    nd();
    nd();
    //document.getElementById('mainSearchSelect').style.visibility = "visible";
}

function getVoteForm(pollId) {
    doc = new XML(); 
    doc.addListener(onLoadedPollForm);
    doc._method = "POST";
    doc.setAttribute("pollId", pollId);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.sendAndLoad("actions-ajaxPoll.do");
    
    
}

function onLoadedPollForm(response) {
    //document.getElementById('mainSearchSelect').style.visibility = "hidden";
    var doc = response.responseXML.documentElement;
    var items = getItems(doc, "PollOption").items();
    var len = items.length;
    var html = '<form id="votePoll" action="actions-pollVote.do" class="form">';
    html += '<input type="hidden" value="" id="votePollConfirm"/>';
    html += "<table width=\"100%\" cellpading=\"0\" cellspacing=\"0\" style=\"s-index: 1337;\">";
    html += '<tr style="background-color: #DEDBD6; height: 25px; text-transform: uppercase; font-weight: bold;">';
    html += '<td style="color: #000000;">&#160;Voter</td>';
    html += '<td align="right"><a href="#X" onclick="return closePollVote()" style="color: #000000; font-size: 12px;" id="xclickOverlib">X</a>&#160;</td></tr>';
    for(var i=0; i<len; i++){
        var item = items[i];
        if(item.getAttribute("value") == null || item.getAttribute("value") == '')
          continue;
        html += "<tr>";
        html += '<td colspan="2"><input type="radio" name="optionId" value="'+item.getAttribute("id")+'" onclick="selectPollVote()"/>&#160;' + item.getAttribute("value") + '</td>';
        html += "</tr>";
    }
    html += '<tr><td colspan="2" align="right"><a class="GrayA" href="javascript:submitPollVote();">Voter</a></td></tr>';
    html += "</table>";
    html += '</form>';
    return overlib(
    html, 
    STICKY, LEFT, OFFSETX, -20, WIDTH, 150, HEIGHT, (30 * len));
}


function getLoginErrorForm() {
    var html = '<form id="votePoll" action="actions-pollVote.do" class="form">';
    html += '<input type="hidden" value="" id="votePollConfirm"/>';
    html += "<table width=\"100%\" cellpading=\"0\" cellspacing=\"0\" style=\"s-index: 1337;\">";
    
    html += '<tr style="background-color: #DEDBD6; height: 25px; text-transform: uppercase; font-weight: bold;">';
    html += '<td style="color: #000000;">&#160;RÉSULTATS</td>';
    html += '<td align="right"><a href="#X" onclick="return closePollVote()" style="color: #000000; font-size: 12px;" id="xclickOverlib">X</a>&#160;</td></tr>';
    
    
    html += '<tr><td colspan="2">&#160;</td></tr>';
    html += '<tr><td colspan="2">&#160;&#160;Connectez-vous pour</td></tr>';
    html += '<tr><td colspan="2">&#160;&#160;voir les résultats.</td></tr>';
    html += '<tr><td colspan="2">&#160;</td></tr>';
    html += "</table>";
    html += '</form>';
    overlib(
    html, 
    STICKY, LEFT, OFFSETX, -20, WIDTH, 150, HEIGHT, 30 );
    
}


var displayMenu = false;
var selLabelKey;

var isLogged = false;
var subscribedNewsLetter = false;

function menuDescription(labelKey, isLoggedBool, subscribedNewsLetter) {
    
    if(isLoggedBool){
        isLogged = true;
    }    
    if(subscribedNewsLetter){
        subscribedNewsLetter = true;
    }    
    
    selLabelKey = labelKey;
    displayMenu = true;
    /*
    var onLoad = function(response){        
        try{            
            if (displayMenu) {
     
     var doc = response.responseXML.documentElement;        
                var html = doc.firstChild.nodeValue;
     */
    // Patch pour cacher le textarea de la recherche
    if(isLogged){                                
        if(subscribedNewsLetter){
            if(selLabelKey.indexOf('search') != -1 || selLabelKey.indexOf('myaccount') != -1){
                document.getElementById('mainSearchSelect').style.visibility = "hidden";
            }
        }
        else{
            if (selLabelKey.indexOf('search') != -1 || selLabelKey.indexOf('faq') != -1 || selLabelKey.indexOf('sitemap') != -1 || selLabelKey.indexOf('signup') != -1 || selLabelKey.indexOf('myaccount') != -1) {
                document.getElementById('mainSearchSelect').style.visibility = "hidden";
            }
        }            
    }
    else{   
        if (selLabelKey.indexOf('search') != -1 || selLabelKey.indexOf('faq') != -1 || selLabelKey.indexOf('sitemap') != -1 || selLabelKey.indexOf('signup') != -1 || selLabelKey.indexOf('myaccount') != -1) {
            document.getElementById('mainSearchSelect').style.visibility = "hidden";
        }
    }
    html = "<div style='font-size: 9px; font-weight: bold; padding: 2px 3px; letter-spacing: 1px;'>" + 
    Labels[labelKey] + "</div>";        
    return overlib(html, WIDTH, 200);
}

function unloadDescription() {
    document.getElementById('mainSearchSelect').style.visibility = "visible";
    displayMenu = false;
    nd();
}

var setLink;
function specialTooltip(labelKey, clickableLink) {
    setLink = clickableLink;
    doc = new XML(); 
    doc.addListener(onLoadedSpecialTooltip);
    doc._method = "POST";
    doc.setAttribute("key", labelKey);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.sendAndLoad("actions-ajaxGetLabel.do");
}

function onLoadedSpecialTooltip(response) {
    var doc = response.responseXML.documentElement;        
    var html = doc.firstChild.nodeValue;
    if(setLink != null) {
        html = html + '<div style="float: right; padding-top: 5px;"><a href="'+setLink+'">En savoir plus...</a></div>';
    }
    html = "<div style='font-size: 11px; font-weight: bold; padding: 20px; letter-spacing: 1px;'>" + html + "</div>";  
    return overlib(html, STICKY, CAPTION, 'Aide', OFFSETY, -160);
}

function advancedSearchSection(sel) {
    var pressDiv = document.getElementById('pressCriterias');
    var advanDiv = document.getElementById('advancedCriterias');
    var guideDiv = document.getElementById('guideCriterias');
    var val = sel.options[sel.selectedIndex].value;
    if (val == 'guide') {
        pressDiv.style.display = "none";
        advanDiv.style.display = "none";
        guideDiv.style.display = "block";
    } else {
        pressDiv.style.display = "block";
        advanDiv.style.display = "block";
        guideDiv.style.display = "none";
    }
}
/* ************* */
/* ADMIN ARTICLE */
/* ************* */

/* add article */
function getEditionsInEditionGroupAddArticle() {        
    var sel = document.getElementById('pressAddArticleAdminEditionGroupSelect');
    var id = sel.options[sel.selectedIndex].value;
    if (id != -1) {
        doc = new XML(); 
        doc.addListener(onLoadedAddArticleEditionsAdmin);
        doc._method = "POST";
        doc.setAttribute("editionGroupId", id);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.sendAndLoad("actions-pressAjaxGetEditions.do");
    }
}
function onLoadedAddArticleEditionsAdmin(response) {        
    var doc = response.responseXML.documentElement;
    var liste = document.getElementById('pressAddArticleAdminEditionSelect');        
    removeAllOptions(liste);        
    addOption(liste, "Choisir une rubrique", -1, false);        
    var cats = getItems(doc, "Edition").items();
    var catsL = cats.length;
    for(var i1=0; i1<catsL; i1++){
        var cat = cats[i1];        
        addOption(liste, cat.getAttribute("name"), cat.getAttribute("id"), false);
    }
}

/* delete - mofidy article*/
function getEditionsInEditionGroup() {
    var div = document.getElementById('pressAdminEditionContainer');
    var div2 = document.getElementById('pressAdminListContent');    
    var sel = document.getElementById('pressAdminEditionGroupSelect');
    var id = sel.options[sel.selectedIndex].value;
    if (id == -1) {
        div.style.display = "none";
        div2.style.display = "none";        
    } else {
        div.style.display = "block";
        doc = new XML(); 
        doc.addListener(onLoadedEditionsAdmin);
        doc._method = "POST";
        doc.setAttribute("editionGroupId", id);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.sendAndLoad("actions-pressAjaxGetEditions.do");
    }
}
function onLoadedEditionsAdmin(response) {
    var doc = response.responseXML.documentElement;
    var liste = document.getElementById("pressAdminEditionSelect");
    removeAllOptions(liste);
    addOption(liste, "Choisir une rubrique", -1, false);
    var cats = getItems(doc, "Edition").items();
    var catsL = cats.length;
    for(var i1=0; i1<catsL; i1++){
        var cat = cats[i1];
        addOption(liste, cat.getAttribute("name"), cat.getAttribute("id"), false);
    }
}
function getArticlesInEdition() {
    var div = document.getElementById('pressAdminListContent');    
    var sel = document.getElementById('pressAdminEditionSelect');
    var id = sel.options[sel.selectedIndex].value;
    if (id == -1) {
        div.style.display = "none";        
    } else {
        div.style.display = "block";                
        doc = new XML(); 
        doc.addListener(onLoadedArticlesAdmin);
        doc._method = "POST";
        doc.setAttribute("editionId", id);
        doc.setAttribute("status", 0);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.sendAndLoad("actions-pressAjaxGetArticles.do");
    }
}
function onLoadedArticlesAdmin(response) {
    var doc = response.responseXML.documentElement;
    var array2 = getItems(doc, "ArticleName").items();    
    var div = document.getElementById('pressAdminListContent');      
    var html = "";    
    html += '<table cellspacing="0" cellpadding="0" class="listing" >';
    html += '   <tr class="theader">';
    html += '       <td>Articles</td>';
    html += '       <td>Date</td>';
    html += '       <td>Rédacteur</td>';
    html += '       <td>Action</td>';
    html += '   </tr>';
    if(array2.length == 0){
        html += '<tr>';
        html += '   <td colspan="4">Aucune article trouvé.</td>';
        html += '</tr>';
    }
    else{
        for (var i = 0; i < array2.length; i++) {
            var article = array2[i];
            var altbg = "line2";//classe css
            if((i%2)==1){
                altbg = "line1";//classe css
            }            
            html += '<tr class="'+altbg+'">';
            html += '   <td class="bold">'+article.getAttribute("name")+'</td>';
            html += '   <td class="alt">'+article.getAttribute("modDate")+'</td>';
            html += '   <td>'+article.getAttribute("reviewerName")+'</td>';
            html += '   <td class="alt">';
            
            
            html += '<a href="actions-pressUpdateArticleStatus.do?statusId=3&amp;articleId='+article.getAttribute("id")+'">';
            html += '    <img src="img/btn/suspendre.gif" alt="Suspendre" title="Suspendre"/>';
            html += '</a>';
            
            html += '<a href="page-adminarticleedit.do?articleId='+article.getAttribute("id")+'">';
            html += '    <img src="img/btn/editer.gif" alt="Modifier" title="Modifier"/>';
            html += '</a>';
	    html += '<a onclick="return confirm(\'Êtes vous sur de vouloir supprimer cet article ?\');" href="actions-pressRemoveArticle.do?articleId='+article.getAttribute("id")+'">';
            html += '    <img src="img/btn/supprimer.gif" alt="Supprimer" title="Supprimer"/>';
            html += '</a>';     
          
            html += '   </td>';
            html += '</tr>';
        }
    }            
    html += '</table>';
    div.innerHTML = html;
}

var ongletsWhite = false;

/* CODE POUR LES ONGLETS */
function addOnglets(nomDiv, titres) {
    var mainDiv = document.getElementById(nomDiv + 'Menu');
    var html = '';
        
    var colors = new Array('white');
    if(!ongletsWhite)
      colors = new Array('orange', 'yellow', 'green');    
    for(var i = 0; i < titres.length; i++) {
        var color = colors[i % colors.length];
        
        html += '<div style="float: left; width: 130px;">';
        html += '<div id="' + nomDiv + 'TabsMenu' + i + '" class="OngletsTitleTab" style="background: url(\'img/onglets/'+color+'_out.gif\');" onclick="ongletOnclick(\'' + nomDiv + '\', '+i+')" />';
        html += '<div class="OngletsTitleTabText" style="font-family: Tahoma;">' + titres[i] + '</div>';
        html += '</div>';
        html += '</div>';
    }   

    mainDiv.innerHTML = html;
    

    // select first onglet
    ongletOnclick(nomDiv, 0);
}

function ongletOnclick(name, number) {    
    var ongletDiv = document.getElementById(name + 'TabsMenu' + number);

    // selected img
    var src = ongletDiv.style.backgroundImage;
    if(src.indexOf('on.gif') != -1)
        return;
    src = src.replace(/out.gif/, 'on.gif');
    
    ongletDiv.style.backgroundImage = src;
    
    // hide previously select img / content
    for(var i = 0; i < 3; i++) {
        if(i != number) {
            var x = document.getElementById(name + 'TabsMenu' + i);
            
            if(x != null) {
                var y = x.style.backgroundImage;
                y = y.replace(/on.gif/, 'out.gif');    
                x.style.backgroundImage = y;
                
                x.style.cursor = 'pointer';
                x.style.height = '22px';
            }
            
            
            x = document.getElementById(name + 'Content' + i);
            if(x != null) {
                x.style.display = 'none';
            }
        }
    }
    
    ongletDiv.style.cursor = '';
    ongletDiv.style.height = '23px';

    var div = document.getElementById(name + 'Content' + number);
    div.style.display = 'block';
}


/* 411: LEFT COL */
function categoryChangeStyle(id, div, over) {
    if(over) {
        document.getElementById('imgArrowCat_' + id).src = 'img/411/leftcol_bullet_on.gif';
        div.className = 'selectedMenuItem';
    }
    else {
        document.getElementById('imgArrowCat_' + id).src = 'img/411/leftcol_bullet_out.gif';
        div.className = 'menuItem';
    }
}

function editRestaurant() {
    var s = document.getElementById('selectEditRestaurant');
    var id = s.options[s.selectedIndex].value;
    
    window.location.href = 'page-admin-restaurants.do?restaurantId=' + id;
}

function deleteRestaurant() {
    var s = document.getElementById('selectEditRestaurant');
    var id = s.options[s.selectedIndex].value;
    
    window.location.href = 'actions-adminRestaurant.do?delete&restaurantId=' + id;
}

function editRecette() {
    var s = document.getElementById('selectEditRecette');
    var id = s.options[s.selectedIndex].value;
    
    window.location.href = 'page-admin-restaurants.do?recetteId=' + id;
}

function deleteRecette() {
    var s = document.getElementById('selectEditRecette');
    var id = s.options[s.selectedIndex].value;
    
    window.location.href = 'actions-adminRestaurant.do?delete&recetteId=' + id;
}

function ongletMouseOver(div) {
    div.style.backgroundImage = div.style.backgroundImage.replace(/_out.gif/, '_on.gif');  
}

function ongletMouseOut(div) {
    div.style.backgroundImage = div.style.backgroundImage.replace(/_on.gif/, '_out.gif');   
}

function editOrgDetails() {
    /*
    var orgC = new CountriesProvincesSelect('selectCountries', 'selectProvinces', 'province_lbl');    
    orgC.setDefault(document.getElementById('orgCountryId').innerHTML, document.getElementById('orgProvinceId').innerHTML);
    orgC.loadCountries();
    */
   
    for (var i = 1; i <= 13; i++) {
        var str1 = 'orgData'+i;
        var str2 = 'orgInput'+i;
        var divDava = document.getElementById(str1);
        var divInput = document.getElementById(str2);
        
        if(divDava != null) {
            divDava.style.display = "none";
        }
        
        if(divInput != null) {
            divInput.style.display = "block";
        }
    }
    
    document.getElementById('orgModBtn').style.display = "none";
    document.getElementById('orgUpdateBtn').style.display = "block";
    document.getElementById('orgCancelBtn').style.display = "block";
    if(document.getElementById('categoriesShow') != null)
        document.getElementById('categoriesShow').style.display = "none";
    if(document.getElementById('categoriesChooser') != null)
        document.getElementById('categoriesChooser').style.display = "block";
    
    for (var i = 1; i <= 9; i++) {
        var div = document.getElementById('show_required_field' + i);
        if(div != null) {
            document.getElementById('show_required_field' + i).style.display= 'inline';
        }
    }    
}

function cancelEditOrgDetails() {
    for (var i = 1; i <= 13; i++) {
        var str1 = 'orgData'+i;
        var str2 = 'orgInput'+i;
        var divDava = document.getElementById(str1);
        var divInput = document.getElementById(str2);
        
        if(divDava != null) {
            divDava.style.display = "block";
        }
        
        if(divInput != null) {
            divInput.style.display = "none";
        }
    }
    document.getElementById('orgModBtn').style.display = "block";
    document.getElementById('orgUpdateBtn').style.display = "none";
    document.getElementById('orgCancelBtn').style.display = "none";
    if(document.getElementById('categoriesShow') != null)
        document.getElementById('categoriesShow').style.display = "block";
    if(document.getElementById('categoriesChooser') != null)
        document.getElementById('categoriesChooser').style.display = "none";
    for (var i = 1; i <= 9; i++) {
        var div = document.getElementById('show_required_field' + i);
        if(div != null) {
            document.getElementById('show_required_field' + i).style.display= 'none';
        }
    }
}


function feedbackShowDelete(folder) {
    if (folder == "Inbox") {
        alert(Labels['js.feedbackShowDelete.inbox']);
    } else if (folder == "Envoy&eacute;s") {
        alert(Labels['js.feedbackShowDelete.file']);        
    } else {
        document.getElementById('confirmDelete').style.display = "block";
        feedbackHideNewFolder();
        feedbackHideModifyFolder();
    }
}
  
function feedbackHideDelete() {
    document.getElementById('confirmDelete').style.display = "none";
}

function feedbackShowNewFolder() {
    document.getElementById('newFolder').style.display = "block";
    feedbackHideDelete();
    feedbackHideModifyFolder();
}

function feedbackHideNewFolder() {
    document.getElementById('newFolder').style.display = "none";
}

function feedbackShowModifyFolder(folder) {
    if (folder == "Inbox") {
        alert(Labels['js.feedbackShowModifyFolder.inbox']);
    } else if (folder == "Envoy&eacute;s") {
        alert(Labels['js.feedbackShowModifyFolder.file']);        
    } else {
        document.getElementById('modifyFolder').style.display = "block";
        feedbackHideNewFolder();
        feedbackHideDelete();
    }
}

function feedbackHideModifyFolder() {
    document.getElementById('modifyFolder').style.display = "none";
}

function feedbackShowMessage(timestamp, folderId, feedbackId) {
    feedbackHideActions();
    doc = new XML();
    doc.addListener(onFeedbackMessageLoaded);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.setAttribute("feedbackId", (feedbackId+""));
    document.getElementById('listTable').style.display = "none";
    document.getElementById('messageCont').style.display = "block";
    var msgDiv = document.getElementById('message');
    msgDiv.innerHTML = "<img src=\"../shared/img/loading.gif\" alt=\"\" />";
    doc.sendAndLoad("actions-feedbackAjaxMsg.do");
}

function onFeedbackMessageLoaded(response) {
    var doc = response.responseXML.documentElement;
    var msg = getItems(doc, "FeedbackMsg").items()[0];
    var msgInfoDiv = document.getElementById('messageInfo');
    var msgDiv = document.getElementById('message');
    msgInfoDiv.innerHTML = msg.getAttribute("subject") + " - " + msg.getAttribute("timestamp");
    
    var content = msg.getAttribute("content");
    msgDiv.innerHTML = content;
    var replyDiv = document.getElementById('replyLink');
    replyDiv.innerHTML = "<a class=\"GrayA\" href=\"javascript:feedbackShowReply('"+msg.getAttribute("folderId")+"', '"+msg.getAttribute("id")+"');\">R&eacute;pliquer</a>";
    
    
}

function feedbackHideMessage() { 
    document.getElementById('listTable').style.display = "block";
    document.getElementById('messageCont').style.display = "none";
    if (feedbackIsChecked()) {
        feedbackShowActions();
    }
}

function feedbackHideReply() { 
    document.getElementById('listTable').style.display = "block";
    document.getElementById('replyMessage').style.display = "none";
}

function feedbackShowReply(folderId, feedbackId) {
    doc = new XML();
    doc.addListener(onFeedbackReplyLoaded);
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.setAttribute("feedbackId", (feedbackId+""));
    document.getElementById('messageCont').style.display = "none";
    document.getElementById('replyMessage').style.display = "block";    
    var replyDiv = document.getElementById('reply');
    doc.sendAndLoad("actions-feedbackAjaxMsg.do");
}

function onFeedbackReplyLoaded(response) {
    var doc = response.responseXML.documentElement;
    var msg = getItems(doc, "FeedbackMsg").items()[0];
    var replyDiv = document.getElementById('reply');
    var replyInfoDiv = document.getElementById('replyInfo');
    replyInfoDiv.innerHTML = "RE: " + msg.getAttribute("subject");
    
    var content = msg.getAttribute("content");
    content = myreplaceAll(content, "\n", "");
    content = myreplaceAll(content, "\r", "");
    content = myreplaceAll(content, "<br>", "\n");
    content = myreplaceAll(content, "<br/>", "\n");    
    replyDiv.innerHTML = "<form method=\"post\" action=\"actions-feedbackReply.do\" onsubmit=\"alert('Votre commentaire a bien été envoyé, merci.'); return true;\"><input type=\"hidden\" name=\"feedbackId\" value=\""+msg.getAttribute("id")+"\"/><input type=\"hidden\" name=\"subject\" value=\"RE: "+msg.getAttribute("subject")+"\"/><input type=\"hidden\" name=\"folderId\" value=\""+msg.getAttribute("folderId")+"\"/><input type=\"hidden\" name=\"email\" value=\""+msg.getAttribute("email")+"\"/><textarea cols=\"74\" rows=\"14\" name=\"content\">\n\n\n\n\nVous avez &eacute;crit ("+msg.getAttribute("timestamp")+"): \n" + content + "</textarea><br/><input type=\"submit\" value=\"Envoyer\"/></form>";
}

function myreplaceAll(str, torep, rep) {
    var ret;
    var val = str;
    
    do {
        ret = val;
        val = ret.replace(torep, rep);
    }
    while(val != ret);
    
    return ret;
}

function feedbackImage(image) {
    javascript:window.open(image,"Image attach&eacute;e","toolbar=no");
    return void(0);
}

var feedbackChecked = [];

function feedbackCheck(id, chkBox) {
    if (chkBox.checked) {
        feedbackShowActions();
        feedbackChecked[id] = true;
    } else {
        delete feedbackChecked[id];
    }
    
    if (!feedbackIsChecked()) {
        feedbackHideActions();
    }
}

function feedbackIsChecked() {
    var found = false;
    for(var i in feedbackChecked){
        found = true;
        break; 
    }
    return found;
}
    
function feedbackPushValues() {
    var ids = [];
    for (var i in feedbackChecked) {
        ids.push(i);
    }
    document.getElementById('feedbackInput').value = ids.join(",");
    document.getElementById('feedbackInput2').value = ids.join(",");
}

function feedbackHideActions() {
    document.getElementById('feedbackAdminActions').style.display = "none";
}

function feedbackShowActions() {
    document.getElementById('feedbackAdminActions').style.display = "block";
}

function feedbackDoAction(form, name) {
    if (confirm(Labels['js.feedbackDoAction.msg1']+' '+name+' '+Labels['js.feedbackDoAction.msg2'])) {
        feedbackPushValues();
        document.getElementById(form).submit();
    }
}

// return the parameter value by his name from URL
function getParameter(name)
{
	name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
	var regexS = "[\\?&]"+name+"=([^&#]*)";
	var regex = new RegExp( regexS );
	var results = regex.exec( window.location.href );
	if( results == null ) {
		return "";
	}
	else {
		return results[1];
	}
}

// get the current page's name
function getCurrentPage()
{
	// using POST method
	var sPath = window.location.pathname;
	var sPage = sPath.substring(sPath.lastIndexOf('/') + 1);

	// cut the word 'page-'
	sPage = sPage.substring(5);
	sPage = sPage.substring(0, sPage.indexOf('.'));

	return sPage;
}

// by AT at 2008/02/22
function doPostByAjax(url, parameters, callback)
{
	var currentTime = new Date();
	var val = currentTime.getTime();
	parameters = parameters + "&mpsrft=" + val;

	makeAjaxRequest(url, parameters, callback, "POST");
}

// by AT at 2008/02/22
function doGetByAjax(url, parameters, callback)
{
	var currentTime = new Date();
	var val = currentTime.getTime();
	url = url + "&mpsrft=" + val;

	makeAjaxRequest(url, parameters, callback, "GET");
}

function makeAjaxRequest(url, parameters, callback, method)
{
	var httpRequest;

	if (window.XMLHttpRequest)
	{ // Mozilla, Safari, ...
		httpRequest = new XMLHttpRequest();

		if (httpRequest.overrideMimeType) {
			httpRequest.overrideMimeType('text/xml');
		}
        }
	else if (window.ActiveXObject)
	{ // IE
		try {
			httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} 
		catch (e)
		{
			try {
				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			}catch (e) {}
		}
	}

        if (!httpRequest)
	{
		alert('Error: Cannot create an XMLHTTP instance');
		return false;
	}

	httpRequest.onreadystatechange = function() { eval(callback(httpRequest)); };
	httpRequest.open(method, url, true);
	httpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
	httpRequest.setRequestHeader("Content-length", parameters.length);
	httpRequest.send(parameters);
        return true;
}

function getHost()
{
	var url = window.location.href;
	var hostName = window.location.hostname;
	var hostNameIndex = url.indexOf(hostName);
	// get the url from hostname till to end
	var tmpUrl = url.substring(hostNameIndex);
	// string start at first /
	var firstSlashIndex = tmpUrl.indexOf("/");
	// hostname:port
	return "http://" + tmpUrl.substring(0, firstSlashIndex);
}

function getSiteName()
{
	var url = window.location.href;
	tmpStr = url.substring(url.indexOf("sites") + 6);
	var sitename = tmpStr.substring(0, tmpStr.indexOf("/"));
	// site's name
	return sitename;
}

/**used be tree */
function buildBranch(parent, child)
{
	var oTextNode = new YAHOO.widget.TextNode(child, parent, false);
        //oTextNodeMap[oTextNode.labelElId] = oTextNode;
        return oTextNode;
}

/** recursively build a tree */
function buildTree(parent, nodeAsXML)
{
	if(nodeAsXML.childNodes.length > 0)
	{
		var childs = nodeAsXML.childNodes;

		for (var i=0; i<childs.length; i++)
		{
			var childNode = { label: childs[i].getAttribute("name"), id: childs[i].getAttribute("id") };

			var child = buildBranch(parent, childNode);
                        child.labelStyle = "icon-doc";

			if(childs[i].childNodes.length > 0) {
				buildTree(child, childs[i]);
                        }
		}				
	}
}
/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.5.2
*/
if(typeof YAHOO=="undefined"||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var A=arguments,E=null,C,B,D;for(C=0;C<A.length;C=C+1){D=A[C].split(".");E=YAHOO;for(B=(D[0]=="YAHOO")?1:0;B<D.length;B=B+1){E[D[B]]=E[D[B]]||{};E=E[D[B]];}}return E;};YAHOO.log=function(D,A,C){var B=YAHOO.widget.Logger;if(B&&B.log){return B.log(D,A,C);}else{return false;}};YAHOO.register=function(A,E,D){var I=YAHOO.env.modules;if(!I[A]){I[A]={versions:[],builds:[]};}var B=I[A],H=D.version,G=D.build,F=YAHOO.env.listeners;B.name=A;B.version=H;B.build=G;B.versions.push(H);B.builds.push(G);B.mainClass=E;for(var C=0;C<F.length;C=C+1){F[C](B);}if(E){E.VERSION=H;E.BUILD=G;}else{YAHOO.log("mainClass is undefined for module "+A,"warn");}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(A){return YAHOO.env.modules[A]||null;};YAHOO.env.ua=function(){var C={ie:0,opera:0,gecko:0,webkit:0,mobile:null,air:0};var B=navigator.userAgent,A;if((/KHTML/).test(B)){C.webkit=1;}A=B.match(/AppleWebKit\/([^\s]*)/);if(A&&A[1]){C.webkit=parseFloat(A[1]);if(/ Mobile\//.test(B)){C.mobile="Apple";}else{A=B.match(/NokiaN[^\/]*/);if(A){C.mobile=A[0];}}A=B.match(/AdobeAIR\/([^\s]*)/);if(A){C.air=A[0];}}if(!C.webkit){A=B.match(/Opera[\s\/]([^\s]*)/);if(A&&A[1]){C.opera=parseFloat(A[1]);A=B.match(/Opera Mini[^;]*/);if(A){C.mobile=A[0];}}else{A=B.match(/MSIE\s([^;]*)/);if(A&&A[1]){C.ie=parseFloat(A[1]);}else{A=B.match(/Gecko\/([^\s]*)/);if(A){C.gecko=1;A=B.match(/rv:([^\s\)]*)/);if(A&&A[1]){C.gecko=parseFloat(A[1]);}}}}}return C;}();(function(){YAHOO.namespace("util","widget","example");if("undefined"!==typeof YAHOO_config){var B=YAHOO_config.listener,A=YAHOO.env.listeners,D=true,C;if(B){for(C=0;C<A.length;C=C+1){if(A[C]==B){D=false;break;}}if(D){A.push(B);}}}})();YAHOO.lang=YAHOO.lang||{};(function(){var A=YAHOO.lang,C=["toString","valueOf"],B={isArray:function(D){if(D){return A.isNumber(D.length)&&A.isFunction(D.splice);}return false;},isBoolean:function(D){return typeof D==="boolean";},isFunction:function(D){return typeof D==="function";},isNull:function(D){return D===null;},isNumber:function(D){return typeof D==="number"&&isFinite(D);},isObject:function(D){return(D&&(typeof D==="object"||A.isFunction(D)))||false;},isString:function(D){return typeof D==="string";},isUndefined:function(D){return typeof D==="undefined";},_IEEnumFix:(YAHOO.env.ua.ie)?function(F,E){for(var D=0;D<C.length;D=D+1){var H=C[D],G=E[H];if(A.isFunction(G)&&G!=Object.prototype[H]){F[H]=G;}}}:function(){},extend:function(H,I,G){if(!I||!H){throw new Error("extend failed, please check that "+"all dependencies are included.");}var E=function(){};E.prototype=I.prototype;H.prototype=new E();H.prototype.constructor=H;H.superclass=I.prototype;if(I.prototype.constructor==Object.prototype.constructor){I.prototype.constructor=I;}if(G){for(var D in G){if(A.hasOwnProperty(G,D)){H.prototype[D]=G[D];}}A._IEEnumFix(H.prototype,G);}},augmentObject:function(H,G){if(!G||!H){throw new Error("Absorb failed, verify dependencies.");}var D=arguments,F,I,E=D[2];if(E&&E!==true){for(F=2;F<D.length;F=F+1){H[D[F]]=G[D[F]];}}else{for(I in G){if(E||!(I in H)){H[I]=G[I];}}A._IEEnumFix(H,G);}},augmentProto:function(G,F){if(!F||!G){throw new Error("Augment failed, verify dependencies.");}var D=[G.prototype,F.prototype];for(var E=2;E<arguments.length;E=E+1){D.push(arguments[E]);}A.augmentObject.apply(this,D);},dump:function(D,I){var F,H,K=[],L="{...}",E="f(){...}",J=", ",G=" => ";if(!A.isObject(D)){return D+"";}else{if(D instanceof Date||("nodeType" in D&&"tagName" in D)){return D;}else{if(A.isFunction(D)){return E;}}}I=(A.isNumber(I))?I:3;if(A.isArray(D)){K.push("[");for(F=0,H=D.length;F<H;F=F+1){if(A.isObject(D[F])){K.push((I>0)?A.dump(D[F],I-1):L);}else{K.push(D[F]);}K.push(J);}if(K.length>1){K.pop();}K.push("]");}else{K.push("{");for(F in D){if(A.hasOwnProperty(D,F)){K.push(F+G);if(A.isObject(D[F])){K.push((I>0)?A.dump(D[F],I-1):L);}else{K.push(D[F]);}K.push(J);}}if(K.length>1){K.pop();}K.push("}");}return K.join("");},substitute:function(S,E,L){var I,H,G,O,P,R,N=[],F,J="dump",M=" ",D="{",Q="}";for(;;){I=S.lastIndexOf(D);if(I<0){break;}H=S.indexOf(Q,I);if(I+1>=H){break;}F=S.substring(I+1,H);O=F;R=null;G=O.indexOf(M);if(G>-1){R=O.substring(G+1);O=O.substring(0,G);}P=E[O];if(L){P=L(O,P,R);}if(A.isObject(P)){if(A.isArray(P)){P=A.dump(P,parseInt(R,10));}else{R=R||"";var K=R.indexOf(J);if(K>-1){R=R.substring(4);}if(P.toString===Object.prototype.toString||K>-1){P=A.dump(P,parseInt(R,10));}else{P=P.toString();}}}else{if(!A.isString(P)&&!A.isNumber(P)){P="~-"+N.length+"-~";N[N.length]=F;}}S=S.substring(0,I)+P+S.substring(H+1);}for(I=N.length-1;I>=0;I=I-1){S=S.replace(new RegExp("~-"+I+"-~"),"{"+N[I]+"}","g");}return S;},trim:function(D){try{return D.replace(/^\s+|\s+$/g,"");}catch(E){return D;}},merge:function(){var G={},E=arguments;for(var F=0,D=E.length;F<D;F=F+1){A.augmentObject(G,E[F],true);}return G;},later:function(K,E,L,G,H){K=K||0;E=E||{};var F=L,J=G,I,D;if(A.isString(L)){F=E[L];}if(!F){throw new TypeError("method undefined");}if(!A.isArray(J)){J=[G];}I=function(){F.apply(E,J);};D=(H)?setInterval(I,K):setTimeout(I,K);return{interval:H,cancel:function(){if(this.interval){clearInterval(D);}else{clearTimeout(D);}}};},isValue:function(D){return(A.isObject(D)||A.isString(D)||A.isNumber(D)||A.isBoolean(D));}};A.hasOwnProperty=(Object.prototype.hasOwnProperty)?function(D,E){return D&&D.hasOwnProperty(E);}:function(D,E){return !A.isUndefined(D[E])&&D.constructor.prototype[E]!==D[E];};B.augmentObject(A,B,true);YAHOO.util.Lang=A;A.augment=A.augmentProto;YAHOO.augment=A.augmentProto;YAHOO.extend=A.extend;})();YAHOO.register("yahoo",YAHOO,{version:"2.5.2",build:"1076"});YAHOO.util.Get=function(){var M={},L=0,Q=0,E=false,N=YAHOO.env.ua,R=YAHOO.lang;var J=function(V,S,W){var T=W||window,X=T.document,Y=X.createElement(V);for(var U in S){if(S[U]&&YAHOO.lang.hasOwnProperty(S,U)){Y.setAttribute(U,S[U]);}}return Y;};var H=function(S,T,V){var U=V||"utf-8";return J("link",{"id":"yui__dyn_"+(Q++),"type":"text/css","charset":U,"rel":"stylesheet","href":S},T);
};var O=function(S,T,V){var U=V||"utf-8";return J("script",{"id":"yui__dyn_"+(Q++),"type":"text/javascript","charset":U,"src":S},T);};var A=function(S,T){return{tId:S.tId,win:S.win,data:S.data,nodes:S.nodes,msg:T,purge:function(){D(this.tId);}};};var B=function(S,V){var T=M[V],U=(R.isString(S))?T.win.document.getElementById(S):S;if(!U){P(V,"target node not found: "+S);}return U;};var P=function(V,U){var S=M[V];if(S.onFailure){var T=S.scope||S.win;S.onFailure.call(T,A(S,U));}};var C=function(V){var S=M[V];S.finished=true;if(S.aborted){var U="transaction "+V+" was aborted";P(V,U);return ;}if(S.onSuccess){var T=S.scope||S.win;S.onSuccess.call(T,A(S));}};var G=function(U,Y){var T=M[U];if(T.aborted){var W="transaction "+U+" was aborted";P(U,W);return ;}if(Y){T.url.shift();if(T.varName){T.varName.shift();}}else{T.url=(R.isString(T.url))?[T.url]:T.url;if(T.varName){T.varName=(R.isString(T.varName))?[T.varName]:T.varName;}}var b=T.win,a=b.document,Z=a.getElementsByTagName("head")[0],V;if(T.url.length===0){if(T.type==="script"&&N.webkit&&N.webkit<420&&!T.finalpass&&!T.varName){var X=O(null,T.win,T.charset);X.innerHTML='YAHOO.util.Get._finalize("'+U+'");';T.nodes.push(X);Z.appendChild(X);}else{C(U);}return ;}var S=T.url[0];if(T.type==="script"){V=O(S,b,T.charset);}else{V=H(S,b,T.charset);}F(T.type,V,U,S,b,T.url.length);T.nodes.push(V);if(T.insertBefore){var c=B(T.insertBefore,U);if(c){c.parentNode.insertBefore(V,c);}}else{Z.appendChild(V);}if((N.webkit||N.gecko)&&T.type==="css"){G(U,S);}};var K=function(){if(E){return ;}E=true;for(var S in M){var T=M[S];if(T.autopurge&&T.finished){D(T.tId);delete M[S];}}E=false;};var D=function(Z){var W=M[Z];if(W){var Y=W.nodes,S=Y.length,X=W.win.document,V=X.getElementsByTagName("head")[0];if(W.insertBefore){var U=B(W.insertBefore,Z);if(U){V=U.parentNode;}}for(var T=0;T<S;T=T+1){V.removeChild(Y[T]);}}W.nodes=[];};var I=function(T,S,U){var W="q"+(L++);U=U||{};if(L%YAHOO.util.Get.PURGE_THRESH===0){K();}M[W]=R.merge(U,{tId:W,type:T,url:S,finished:false,nodes:[]});var V=M[W];V.win=V.win||window;V.scope=V.scope||V.win;V.autopurge=("autopurge" in V)?V.autopurge:(T==="script")?true:false;R.later(0,V,G,W);return{tId:W};};var F=function(b,W,V,T,X,Y,a){var Z=a||G;if(N.ie){W.onreadystatechange=function(){var c=this.readyState;if("loaded"===c||"complete"===c){Z(V,T);}};}else{if(N.webkit){if(b==="script"){if(N.webkit>=420){W.addEventListener("load",function(){Z(V,T);});}else{var S=M[V];if(S.varName){var U=YAHOO.util.Get.POLL_FREQ;S.maxattempts=YAHOO.util.Get.TIMEOUT/U;S.attempts=0;S._cache=S.varName[0].split(".");S.timer=R.later(U,S,function(h){var e=this._cache,d=e.length,c=this.win,f;for(f=0;f<d;f=f+1){c=c[e[f]];if(!c){this.attempts++;if(this.attempts++>this.maxattempts){var g="Over retry limit, giving up";S.timer.cancel();P(V,g);}else{}return ;}}S.timer.cancel();Z(V,T);},null,true);}else{R.later(YAHOO.util.Get.POLL_FREQ,null,Z,[V,T]);}}}}else{W.onload=function(){Z(V,T);};}}};return{POLL_FREQ:10,PURGE_THRESH:20,TIMEOUT:2000,_finalize:function(S){R.later(0,null,C,S);},abort:function(T){var U=(R.isString(T))?T:T.tId;var S=M[U];if(S){S.aborted=true;}},script:function(S,T){return I("script",S,T);},css:function(S,T){return I("css",S,T);}};}();YAHOO.register("get",YAHOO.util.Get,{version:"2.5.2",build:"1076"});(function(){var Y=YAHOO,util=Y.util,lang=Y.lang,env=Y.env,PROV="_provides",SUPER="_supersedes",REQ="expanded",AFTER="_after";var YUI={dupsAllowed:{"yahoo":true,"get":true},info:{"base":"http://yui.yahooapis.com/2.5.2/build/","skin":{"defaultSkin":"sam","base":"assets/skins/","path":"skin.css","after":["reset","fonts","grids","base"],"rollup":3},dupsAllowed:["yahoo","get"],"moduleInfo":{"animation":{"type":"js","path":"animation/animation-min.js","requires":["dom","event"]},"autocomplete":{"type":"js","path":"autocomplete/autocomplete-min.js","requires":["dom","event"],"optional":["connection","animation"],"skinnable":true},"base":{"type":"css","path":"base/base-min.css","after":["reset","fonts","grids"]},"button":{"type":"js","path":"button/button-min.js","requires":["element"],"optional":["menu"],"skinnable":true},"calendar":{"type":"js","path":"calendar/calendar-min.js","requires":["event","dom"],"skinnable":true},"charts":{"type":"js","path":"charts/charts-experimental-min.js","requires":["element","json","datasource"]},"colorpicker":{"type":"js","path":"colorpicker/colorpicker-min.js","requires":["slider","element"],"optional":["animation"],"skinnable":true},"connection":{"type":"js","path":"connection/connection-min.js","requires":["event"]},"container":{"type":"js","path":"container/container-min.js","requires":["dom","event"],"optional":["dragdrop","animation","connection"],"supersedes":["containercore"],"skinnable":true},"containercore":{"type":"js","path":"container/container_core-min.js","requires":["dom","event"],"pkg":"container"},"cookie":{"type":"js","path":"cookie/cookie-beta-min.js","requires":["yahoo"]},"datasource":{"type":"js","path":"datasource/datasource-beta-min.js","requires":["event"],"optional":["connection"]},"datatable":{"type":"js","path":"datatable/datatable-beta-min.js","requires":["element","datasource"],"optional":["calendar","dragdrop"],"skinnable":true},"dom":{"type":"js","path":"dom/dom-min.js","requires":["yahoo"]},"dragdrop":{"type":"js","path":"dragdrop/dragdrop-min.js","requires":["dom","event"]},"editor":{"type":"js","path":"editor/editor-beta-min.js","requires":["menu","element","button"],"optional":["animation","dragdrop"],"supersedes":["simpleeditor"],"skinnable":true},"element":{"type":"js","path":"element/element-beta-min.js","requires":["dom","event"]},"event":{"type":"js","path":"event/event-min.js","requires":["yahoo"]},"fonts":{"type":"css","path":"fonts/fonts-min.css"},"get":{"type":"js","path":"get/get-min.js","requires":["yahoo"]},"grids":{"type":"css","path":"grids/grids-min.css","requires":["fonts"],"optional":["reset"]},"history":{"type":"js","path":"history/history-min.js","requires":["event"]},"imagecropper":{"type":"js","path":"imagecropper/imagecropper-beta-min.js","requires":["dom","event","dragdrop","element","resize"],"skinnable":true},"imageloader":{"type":"js","path":"imageloader/imageloader-min.js","requires":["event","dom"]},"json":{"type":"js","path":"json/json-min.js","requires":["yahoo"]},"layout":{"type":"js","path":"layout/layout-beta-min.js","requires":["dom","event","element"],"optional":["animation","dragdrop","resize","selector"],"skinnable":true},"logger":{"type":"js","path":"logger/logger-min.js","requires":["event","dom"],"optional":["dragdrop"],"skinnable":true},"menu":{"type":"js","path":"menu/menu-min.js","requires":["containercore"],"skinnable":true},"profiler":{"type":"js","path":"profiler/profiler-beta-min.js","requires":["yahoo"]},"profilerviewer":{"type":"js","path":"profilerviewer/profilerviewer-beta-min.js","requires":["profiler","yuiloader","element"],"skinnable":true},"reset":{"type":"css","path":"reset/reset-min.css"},"reset-fonts-grids":{"type":"css","path":"reset-fonts-grids/reset-fonts-grids.css","supersedes":["reset","fonts","grids","reset-fonts"],"rollup":4},"reset-fonts":{"type":"css","path":"reset-fonts/reset-fonts.css","supersedes":["reset","fonts"],"rollup":2},"resize":{"type":"js","path":"resize/resize-beta-min.js","requires":["dom","event","dragdrop","element"],"optional":["animation"],"skinnable":true},"selector":{"type":"js","path":"selector/selector-beta-min.js","requires":["yahoo","dom"]},"simpleeditor":{"type":"js","path":"editor/simpleeditor-beta-min.js","requires":["element"],"optional":["containercore","menu","button","animation","dragdrop"],"skinnable":true,"pkg":"editor"},"slider":{"type":"js","path":"slider/slider-min.js","requires":["dragdrop"],"optional":["animation"]},"tabview":{"type":"js","path":"tabview/tabview-min.js","requires":["element"],"optional":["connection"],"skinnable":true},"treeview":{"type":"js","path":"treeview/treeview-min.js","requires":["event"],"skinnable":true},"uploader":{"type":"js","path":"uploader/uploader-experimental.js","requires":["element"]},"utilities":{"type":"js","path":"utilities/utilities.js","supersedes":["yahoo","event","dragdrop","animation","dom","connection","element","yahoo-dom-event","get","yuiloader","yuiloader-dom-event"],"rollup":8},"yahoo":{"type":"js","path":"yahoo/yahoo-min.js"},"yahoo-dom-event":{"type":"js","path":"yahoo-dom-event/yahoo-dom-event.js","supersedes":["yahoo","event","dom"],"rollup":3},"yuiloader":{"type":"js","path":"yuiloader/yuiloader-beta-min.js","supersedes":["yahoo","get"]},"yuiloader-dom-event":{"type":"js","path":"yuiloader-dom-event/yuiloader-dom-event.js","supersedes":["yahoo","dom","event","get","yuiloader","yahoo-dom-event"],"rollup":5},"yuitest":{"type":"js","path":"yuitest/yuitest-min.js","requires":["logger"],"skinnable":true}}},ObjectUtil:{appendArray:function(o,a){if(a){for(var i=0;
i<a.length;i=i+1){o[a[i]]=true;}}},keys:function(o,ordered){var a=[],i;for(i in o){if(lang.hasOwnProperty(o,i)){a.push(i);}}return a;}},ArrayUtil:{appendArray:function(a1,a2){Array.prototype.push.apply(a1,a2);},indexOf:function(a,val){for(var i=0;i<a.length;i=i+1){if(a[i]===val){return i;}}return -1;},toObject:function(a){var o={};for(var i=0;i<a.length;i=i+1){o[a[i]]=true;}return o;},uniq:function(a){return YUI.ObjectUtil.keys(YUI.ArrayUtil.toObject(a));}}};YAHOO.util.YUILoader=function(o){this._internalCallback=null;this._useYahooListener=false;this.onSuccess=null;this.onFailure=Y.log;this.onProgress=null;this.scope=this;this.data=null;this.insertBefore=null;this.charset=null;this.varName=null;this.base=YUI.info.base;this.ignore=null;this.force=null;this.allowRollup=true;this.filter=null;this.required={};this.moduleInfo=lang.merge(YUI.info.moduleInfo);this.rollups=null;this.loadOptional=false;this.sorted=[];this.loaded={};this.dirty=true;this.inserted={};var self=this;env.listeners.push(function(m){if(self._useYahooListener){self.loadNext(m.name);}});this.skin=lang.merge(YUI.info.skin);this._config(o);};Y.util.YUILoader.prototype={FILTERS:{RAW:{"searchExp":"-min\\.js","replaceStr":".js"},DEBUG:{"searchExp":"-min\\.js","replaceStr":"-debug.js"}},SKIN_PREFIX:"skin-",_config:function(o){if(o){for(var i in o){if(lang.hasOwnProperty(o,i)){if(i=="require"){this.require(o[i]);}else{this[i]=o[i];}}}}var f=this.filter;if(lang.isString(f)){f=f.toUpperCase();if(f==="DEBUG"){this.require("logger");}if(!Y.widget.LogWriter){Y.widget.LogWriter=function(){return Y;};}this.filter=this.FILTERS[f];}},addModule:function(o){if(!o||!o.name||!o.type||(!o.path&&!o.fullpath)){return false;}o.ext=("ext" in o)?o.ext:true;o.requires=o.requires||[];this.moduleInfo[o.name]=o;this.dirty=true;return true;},require:function(what){var a=(typeof what==="string")?arguments:what;this.dirty=true;YUI.ObjectUtil.appendArray(this.required,a);},_addSkin:function(skin,mod){var name=this.formatSkin(skin),info=this.moduleInfo,sinf=this.skin,ext=info[mod]&&info[mod].ext;if(!info[name]){this.addModule({"name":name,"type":"css","path":sinf.base+skin+"/"+sinf.path,"after":sinf.after,"rollup":sinf.rollup,"ext":ext});}if(mod){name=this.formatSkin(skin,mod);if(!info[name]){var mdef=info[mod],pkg=mdef.pkg||mod;this.addModule({"name":name,"type":"css","after":sinf.after,"path":pkg+"/"+sinf.base+skin+"/"+mod+".css","ext":ext});}}return name;},getRequires:function(mod){if(!mod){return[];}if(!this.dirty&&mod.expanded){return mod.expanded;}mod.requires=mod.requires||[];var i,d=[],r=mod.requires,o=mod.optional,info=this.moduleInfo,m;for(i=0;i<r.length;i=i+1){d.push(r[i]);m=info[r[i]];YUI.ArrayUtil.appendArray(d,this.getRequires(m));}if(o&&this.loadOptional){for(i=0;i<o.length;i=i+1){d.push(o[i]);YUI.ArrayUtil.appendArray(d,this.getRequires(info[o[i]]));}}mod.expanded=YUI.ArrayUtil.uniq(d);return mod.expanded;},getProvides:function(name,notMe){var addMe=!(notMe),ckey=(addMe)?PROV:SUPER,m=this.moduleInfo[name],o={};if(!m){return o;}if(m[ckey]){return m[ckey];}var s=m.supersedes,done={},me=this;var add=function(mm){if(!done[mm]){done[mm]=true;lang.augmentObject(o,me.getProvides(mm));}};if(s){for(var i=0;i<s.length;i=i+1){add(s[i]);}}m[SUPER]=o;m[PROV]=lang.merge(o);m[PROV][name]=true;return m[ckey];},calculate:function(o){if(this.dirty){this._config(o);this._setup();this._explode();if(this.allowRollup){this._rollup();}this._reduce();this._sort();this.dirty=false;}},_setup:function(){var info=this.moduleInfo,name,i,j;for(name in info){var m=info[name];if(m&&m.skinnable){var o=this.skin.overrides,smod;if(o&&o[name]){for(i=0;i<o[name].length;i=i+1){smod=this._addSkin(o[name][i],name);}}else{smod=this._addSkin(this.skin.defaultSkin,name);}m.requires.push(smod);}}var l=lang.merge(this.inserted);if(!this._sandbox){l=lang.merge(l,env.modules);}if(this.ignore){YUI.ObjectUtil.appendArray(l,this.ignore);}if(this.force){for(i=0;i<this.force.length;i=i+1){if(this.force[i] in l){delete l[this.force[i]];}}}for(j in l){if(lang.hasOwnProperty(l,j)){lang.augmentObject(l,this.getProvides(j));}}this.loaded=l;},_explode:function(){var r=this.required,i,mod;for(i in r){mod=this.moduleInfo[i];if(mod){var req=this.getRequires(mod);if(req){YUI.ObjectUtil.appendArray(r,req);}}}},_skin:function(){},formatSkin:function(skin,mod){var s=this.SKIN_PREFIX+skin;if(mod){s=s+"-"+mod;}return s;},parseSkin:function(mod){if(mod.indexOf(this.SKIN_PREFIX)===0){var a=mod.split("-");return{skin:a[1],module:a[2]};}return null;},_rollup:function(){var i,j,m,s,rollups={},r=this.required,roll;if(this.dirty||!this.rollups){for(i in this.moduleInfo){m=this.moduleInfo[i];if(m&&m.rollup){rollups[i]=m;}}this.rollups=rollups;}for(;;){var rolled=false;for(i in rollups){if(!r[i]&&!this.loaded[i]){m=this.moduleInfo[i];s=m.supersedes;roll=false;if(!m.rollup){continue;}var skin=(m.ext)?false:this.parseSkin(i),c=0;if(skin){for(j in r){if(i!==j&&this.parseSkin(j)){c++;roll=(c>=m.rollup);if(roll){break;}}}}else{for(j=0;j<s.length;j=j+1){if(this.loaded[s[j]]&&(!YUI.dupsAllowed[s[j]])){roll=false;break;}else{if(r[s[j]]){c++;roll=(c>=m.rollup);if(roll){break;}}}}}if(roll){r[i]=true;rolled=true;this.getRequires(m);}}}if(!rolled){break;}}},_reduce:function(){var i,j,s,m,r=this.required;for(i in r){if(i in this.loaded){delete r[i];}else{var skinDef=this.parseSkin(i);if(skinDef){if(!skinDef.module){var skin_pre=this.SKIN_PREFIX+skinDef.skin;for(j in r){m=this.moduleInfo[j];var ext=m&&m.ext;if(!ext&&j!==i&&j.indexOf(skin_pre)>-1){delete r[j];}}}}else{m=this.moduleInfo[i];s=m&&m.supersedes;if(s){for(j=0;j<s.length;j=j+1){if(s[j] in r){delete r[s[j]];}}}}}}},_sort:function(){var s=[],info=this.moduleInfo,loaded=this.loaded,checkOptional=!this.loadOptional,me=this;var requires=function(aa,bb){if(loaded[bb]){return false;}var ii,mm=info[aa],rr=mm&&mm.expanded,after=mm&&mm.after,other=info[bb],optional=mm&&mm.optional;if(rr&&YUI.ArrayUtil.indexOf(rr,bb)>-1){return true;}if(after&&YUI.ArrayUtil.indexOf(after,bb)>-1){return true;
}if(checkOptional&&optional&&YUI.ArrayUtil.indexOf(optional,bb)>-1){return true;}var ss=info[bb]&&info[bb].supersedes;if(ss){for(ii=0;ii<ss.length;ii=ii+1){if(requires(aa,ss[ii])){return true;}}}if(mm.ext&&mm.type=="css"&&(!other.ext)){return true;}return false;};for(var i in this.required){s.push(i);}var p=0;for(;;){var l=s.length,a,b,j,k,moved=false;for(j=p;j<l;j=j+1){a=s[j];for(k=j+1;k<l;k=k+1){if(requires(a,s[k])){b=s.splice(k,1);s.splice(j,0,b[0]);moved=true;break;}}if(moved){break;}else{p=p+1;}}if(!moved){break;}}this.sorted=s;},toString:function(){var o={type:"YUILoader",base:this.base,filter:this.filter,required:this.required,loaded:this.loaded,inserted:this.inserted};lang.dump(o,1);},insert:function(o,type){this.calculate(o);if(!type){var self=this;this._internalCallback=function(){self._internalCallback=null;self.insert(null,"js");};this.insert(null,"css");return ;}this._loading=true;this.loadType=type;this.loadNext();},sandbox:function(o,type){if(o){}else{}this._config(o);if(!this.onSuccess){throw new Error("You must supply an onSuccess handler for your sandbox");}this._sandbox=true;var self=this;if(!type||type!=="js"){this._internalCallback=function(){self._internalCallback=null;self.sandbox(null,"js");};this.insert(null,"css");return ;}if(!util.Connect){var ld=new YAHOO.util.YUILoader();ld.insert({base:this.base,filter:this.filter,require:"connection",insertBefore:this.insertBefore,charset:this.charset,onSuccess:function(){this.sandbox(null,"js");},scope:this},"js");return ;}this._scriptText=[];this._loadCount=0;this._stopCount=this.sorted.length;this._xhr=[];this.calculate();var s=this.sorted,l=s.length,i,m,url;for(i=0;i<l;i=i+1){m=this.moduleInfo[s[i]];if(!m){this.onFailure.call(this.scope,{msg:"undefined module "+m,data:this.data});for(var j=0;j<this._xhr.length;j=j+1){this._xhr[j].abort();}return ;}if(m.type!=="js"){this._loadCount++;continue;}url=m.fullpath||this._url(m.path);var xhrData={success:function(o){var idx=o.argument[0],name=o.argument[2];this._scriptText[idx]=o.responseText;if(this.onProgress){this.onProgress.call(this.scope,{name:name,scriptText:o.responseText,xhrResponse:o,data:this.data});}this._loadCount++;if(this._loadCount>=this._stopCount){var v=this.varName||"YAHOO";var t="(function() {\n";var b="\nreturn "+v+";\n})();";var ref=eval(t+this._scriptText.join("\n")+b);this._pushEvents(ref);if(ref){this.onSuccess.call(this.scope,{reference:ref,data:this.data});}else{this.onFailure.call(this.scope,{msg:this.varName+" reference failure",data:this.data});}}},failure:function(o){this.onFailure.call(this.scope,{msg:"XHR failure",xhrResponse:o,data:this.data});},scope:this,argument:[i,url,s[i]]};this._xhr.push(util.Connect.asyncRequest("GET",url,xhrData));}},loadNext:function(mname){if(!this._loading){return ;}if(mname){if(mname!==this._loading){return ;}this.inserted[mname]=true;if(this.onProgress){this.onProgress.call(this.scope,{name:mname,data:this.data});}}var s=this.sorted,len=s.length,i,m;for(i=0;i<len;i=i+1){if(s[i] in this.inserted){continue;}if(s[i]===this._loading){return ;}m=this.moduleInfo[s[i]];if(!m){this.onFailure.call(this.scope,{msg:"undefined module "+m,data:this.data});return ;}if(!this.loadType||this.loadType===m.type){this._loading=s[i];var fn=(m.type==="css")?util.Get.css:util.Get.script,url=m.fullpath||this._url(m.path),self=this,c=function(o){self.loadNext(o.data);};if(env.ua.webkit&&env.ua.webkit<420&&m.type==="js"&&!m.varName){c=null;this._useYahooListener=true;}fn(url,{data:s[i],onSuccess:c,insertBefore:this.insertBefore,charset:this.charset,varName:m.varName,scope:self});return ;}}this._loading=null;if(this._internalCallback){var f=this._internalCallback;this._internalCallback=null;f.call(this);}else{if(this.onSuccess){this._pushEvents();this.onSuccess.call(this.scope,{data:this.data});}}},_pushEvents:function(ref){var r=ref||YAHOO;if(r.util&&r.util.Event){r.util.Event._load();}},_url:function(path){var u=this.base||"",f=this.filter;u=u+path;if(f){u=u.replace(new RegExp(f.searchExp),f.replaceStr);}return u;}};})();(function(){var B=YAHOO.util,K,I,J={},F={},M=window.document;YAHOO.env._id_counter=YAHOO.env._id_counter||0;var C=YAHOO.env.ua.opera,L=YAHOO.env.ua.webkit,A=YAHOO.env.ua.gecko,G=YAHOO.env.ua.ie;var E={HYPHEN:/(-[a-z])/i,ROOT_TAG:/^body|html$/i,OP_SCROLL:/^(?:inline|table-row)$/i};var N=function(P){if(!E.HYPHEN.test(P)){return P;}if(J[P]){return J[P];}var Q=P;while(E.HYPHEN.exec(Q)){Q=Q.replace(RegExp.$1,RegExp.$1.substr(1).toUpperCase());}J[P]=Q;return Q;};var O=function(Q){var P=F[Q];if(!P){P=new RegExp("(?:^|\\s+)"+Q+"(?:\\s+|$)");F[Q]=P;}return P;};if(M.defaultView&&M.defaultView.getComputedStyle){K=function(P,S){var R=null;if(S=="float"){S="cssFloat";}var Q=P.ownerDocument.defaultView.getComputedStyle(P,"");if(Q){R=Q[N(S)];}return P.style[S]||R;};}else{if(M.documentElement.currentStyle&&G){K=function(P,R){switch(N(R)){case"opacity":var T=100;try{T=P.filters["DXImageTransform.Microsoft.Alpha"].opacity;}catch(S){try{T=P.filters("alpha").opacity;}catch(S){}}return T/100;case"float":R="styleFloat";default:var Q=P.currentStyle?P.currentStyle[R]:null;return(P.style[R]||Q);}};}else{K=function(P,Q){return P.style[Q];};}}if(G){I=function(P,Q,R){switch(Q){case"opacity":if(YAHOO.lang.isString(P.style.filter)){P.style.filter="alpha(opacity="+R*100+")";if(!P.currentStyle||!P.currentStyle.hasLayout){P.style.zoom=1;}}break;case"float":Q="styleFloat";default:P.style[Q]=R;}};}else{I=function(P,Q,R){if(Q=="float"){Q="cssFloat";}P.style[Q]=R;};}var D=function(P,Q){return P&&P.nodeType==1&&(!Q||Q(P));};YAHOO.util.Dom={get:function(R){if(R&&(R.nodeType||R.item)){return R;}if(YAHOO.lang.isString(R)||!R){return M.getElementById(R);}if(R.length!==undefined){var S=[];for(var Q=0,P=R.length;Q<P;++Q){S[S.length]=B.Dom.get(R[Q]);}return S;}return R;},getStyle:function(P,R){R=N(R);var Q=function(S){return K(S,R);};return B.Dom.batch(P,Q,B.Dom,true);},setStyle:function(P,R,S){R=N(R);var Q=function(T){I(T,R,S);};B.Dom.batch(P,Q,B.Dom,true);},getXY:function(P){var Q=function(R){if((R.parentNode===null||R.offsetParent===null||this.getStyle(R,"display")=="none")&&R!=R.ownerDocument.body){return false;}return H(R);};return B.Dom.batch(P,Q,B.Dom,true);},getX:function(P){var Q=function(R){return B.Dom.getXY(R)[0];};return B.Dom.batch(P,Q,B.Dom,true);},getY:function(P){var Q=function(R){return B.Dom.getXY(R)[1];};return B.Dom.batch(P,Q,B.Dom,true);},setXY:function(P,S,R){var Q=function(V){var U=this.getStyle(V,"position");if(U=="static"){this.setStyle(V,"position","relative");U="relative";}var X=this.getXY(V);if(X===false){return false;}var W=[parseInt(this.getStyle(V,"left"),10),parseInt(this.getStyle(V,"top"),10)];if(isNaN(W[0])){W[0]=(U=="relative")?0:V.offsetLeft;}if(isNaN(W[1])){W[1]=(U=="relative")?0:V.offsetTop;}if(S[0]!==null){V.style.left=S[0]-X[0]+W[0]+"px";}if(S[1]!==null){V.style.top=S[1]-X[1]+W[1]+"px";}if(!R){var T=this.getXY(V);if((S[0]!==null&&T[0]!=S[0])||(S[1]!==null&&T[1]!=S[1])){this.setXY(V,S,true);}}};B.Dom.batch(P,Q,B.Dom,true);},setX:function(Q,P){B.Dom.setXY(Q,[P,null]);},setY:function(P,Q){B.Dom.setXY(P,[null,Q]);},getRegion:function(P){var Q=function(R){if((R.parentNode===null||R.offsetParent===null||this.getStyle(R,"display")=="none")&&R!=R.ownerDocument.body){return false;}var S=B.Region.getRegion(R);return S;};return B.Dom.batch(P,Q,B.Dom,true);},getClientWidth:function(){return B.Dom.getViewportWidth();},getClientHeight:function(){return B.Dom.getViewportHeight();},getElementsByClassName:function(T,X,U,V){X=X||"*";U=(U)?B.Dom.get(U):null||M;if(!U){return[];}var Q=[],P=U.getElementsByTagName(X),W=O(T);for(var R=0,S=P.length;R<S;++R){if(W.test(P[R].className)){Q[Q.length]=P[R];if(V){V.call(P[R],P[R]);}}}return Q;},hasClass:function(R,Q){var P=O(Q);var S=function(T){return P.test(T.className);};return B.Dom.batch(R,S,B.Dom,true);},addClass:function(Q,P){var R=function(S){if(this.hasClass(S,P)){return false;}S.className=YAHOO.lang.trim([S.className,P].join(" "));return true;};return B.Dom.batch(Q,R,B.Dom,true);},removeClass:function(R,Q){var P=O(Q);var S=function(T){if(!Q||!this.hasClass(T,Q)){return false;}var U=T.className;T.className=U.replace(P," ");if(this.hasClass(T,Q)){this.removeClass(T,Q);}T.className=YAHOO.lang.trim(T.className);return true;};return B.Dom.batch(R,S,B.Dom,true);},replaceClass:function(S,Q,P){if(!P||Q===P){return false;}var R=O(Q);var T=function(U){if(!this.hasClass(U,Q)){this.addClass(U,P);return true;}U.className=U.className.replace(R," "+P+" ");if(this.hasClass(U,Q)){this.replaceClass(U,Q,P);}U.className=YAHOO.lang.trim(U.className);return true;};return B.Dom.batch(S,T,B.Dom,true);},generateId:function(P,R){R=R||"yui-gen";var Q=function(S){if(S&&S.id){return S.id;}var T=R+YAHOO.env._id_counter++;if(S){S.id=T;}return T;};return B.Dom.batch(P,Q,B.Dom,true)||Q.apply(B.Dom,arguments);},isAncestor:function(P,Q){P=B.Dom.get(P);Q=B.Dom.get(Q);if(!P||!Q){return false;}if(P.contains&&Q.nodeType&&!L){return P.contains(Q);}else{if(P.compareDocumentPosition&&Q.nodeType){return !!(P.compareDocumentPosition(Q)&16);}else{if(Q.nodeType){return !!this.getAncestorBy(Q,function(R){return R==P;});}}}return false;},inDocument:function(P){return this.isAncestor(M.documentElement,P);},getElementsBy:function(W,Q,R,T){Q=Q||"*";R=(R)?B.Dom.get(R):null||M;if(!R){return[];}var S=[],V=R.getElementsByTagName(Q);for(var U=0,P=V.length;U<P;++U){if(W(V[U])){S[S.length]=V[U];if(T){T(V[U]);}}}return S;},batch:function(T,W,V,R){T=(T&&(T.tagName||T.item))?T:B.Dom.get(T);if(!T||!W){return false;}var S=(R)?V:window;if(T.tagName||T.length===undefined){return W.call(S,T,V);}var U=[];for(var Q=0,P=T.length;Q<P;++Q){U[U.length]=W.call(S,T[Q],V);}return U;},getDocumentHeight:function(){var Q=(M.compatMode!="CSS1Compat")?M.body.scrollHeight:M.documentElement.scrollHeight;var P=Math.max(Q,B.Dom.getViewportHeight());return P;},getDocumentWidth:function(){var Q=(M.compatMode!="CSS1Compat")?M.body.scrollWidth:M.documentElement.scrollWidth;var P=Math.max(Q,B.Dom.getViewportWidth());return P;},getViewportHeight:function(){var P=self.innerHeight;
var Q=M.compatMode;if((Q||G)&&!C){P=(Q=="CSS1Compat")?M.documentElement.clientHeight:M.body.clientHeight;}return P;},getViewportWidth:function(){var P=self.innerWidth;var Q=M.compatMode;if(Q||G){P=(Q=="CSS1Compat")?M.documentElement.clientWidth:M.body.clientWidth;}return P;},getAncestorBy:function(P,Q){while(P=P.parentNode){if(D(P,Q)){return P;}}return null;},getAncestorByClassName:function(Q,P){Q=B.Dom.get(Q);if(!Q){return null;}var R=function(S){return B.Dom.hasClass(S,P);};return B.Dom.getAncestorBy(Q,R);},getAncestorByTagName:function(Q,P){Q=B.Dom.get(Q);if(!Q){return null;}var R=function(S){return S.tagName&&S.tagName.toUpperCase()==P.toUpperCase();};return B.Dom.getAncestorBy(Q,R);},getPreviousSiblingBy:function(P,Q){while(P){P=P.previousSibling;if(D(P,Q)){return P;}}return null;},getPreviousSibling:function(P){P=B.Dom.get(P);if(!P){return null;}return B.Dom.getPreviousSiblingBy(P);},getNextSiblingBy:function(P,Q){while(P){P=P.nextSibling;if(D(P,Q)){return P;}}return null;},getNextSibling:function(P){P=B.Dom.get(P);if(!P){return null;}return B.Dom.getNextSiblingBy(P);},getFirstChildBy:function(P,R){var Q=(D(P.firstChild,R))?P.firstChild:null;return Q||B.Dom.getNextSiblingBy(P.firstChild,R);},getFirstChild:function(P,Q){P=B.Dom.get(P);if(!P){return null;}return B.Dom.getFirstChildBy(P);},getLastChildBy:function(P,R){if(!P){return null;}var Q=(D(P.lastChild,R))?P.lastChild:null;return Q||B.Dom.getPreviousSiblingBy(P.lastChild,R);},getLastChild:function(P){P=B.Dom.get(P);return B.Dom.getLastChildBy(P);},getChildrenBy:function(Q,S){var R=B.Dom.getFirstChildBy(Q,S);var P=R?[R]:[];B.Dom.getNextSiblingBy(R,function(T){if(!S||S(T)){P[P.length]=T;}return false;});return P;},getChildren:function(P){P=B.Dom.get(P);if(!P){}return B.Dom.getChildrenBy(P);},getDocumentScrollLeft:function(P){P=P||M;return Math.max(P.documentElement.scrollLeft,P.body.scrollLeft);},getDocumentScrollTop:function(P){P=P||M;return Math.max(P.documentElement.scrollTop,P.body.scrollTop);},insertBefore:function(Q,P){Q=B.Dom.get(Q);P=B.Dom.get(P);if(!Q||!P||!P.parentNode){return null;}return P.parentNode.insertBefore(Q,P);},insertAfter:function(Q,P){Q=B.Dom.get(Q);P=B.Dom.get(P);if(!Q||!P||!P.parentNode){return null;}if(P.nextSibling){return P.parentNode.insertBefore(Q,P.nextSibling);}else{return P.parentNode.appendChild(Q);}},getClientRegion:function(){var R=B.Dom.getDocumentScrollTop(),Q=B.Dom.getDocumentScrollLeft(),S=B.Dom.getViewportWidth()+Q,P=B.Dom.getViewportHeight()+R;return new B.Region(R,S,P,Q);}};var H=function(){if(M.documentElement.getBoundingClientRect){return function(Q){var R=Q.getBoundingClientRect();var P=Q.ownerDocument;return[R.left+B.Dom.getDocumentScrollLeft(P),R.top+B.Dom.getDocumentScrollTop(P)];};}else{return function(R){var S=[R.offsetLeft,R.offsetTop];var Q=R.offsetParent;var P=(L&&B.Dom.getStyle(R,"position")=="absolute"&&R.offsetParent==R.ownerDocument.body);if(Q!=R){while(Q){S[0]+=Q.offsetLeft;S[1]+=Q.offsetTop;if(!P&&L&&B.Dom.getStyle(Q,"position")=="absolute"){P=true;}Q=Q.offsetParent;}}if(P){S[0]-=R.ownerDocument.body.offsetLeft;S[1]-=R.ownerDocument.body.offsetTop;}Q=R.parentNode;while(Q.tagName&&!E.ROOT_TAG.test(Q.tagName)){if(Q.scrollTop||Q.scrollLeft){if(!E.OP_SCROLL.test(B.Dom.getStyle(Q,"display"))){if(!C||B.Dom.getStyle(Q,"overflow")!=="visible"){S[0]-=Q.scrollLeft;S[1]-=Q.scrollTop;}}}Q=Q.parentNode;}return S;};}}();})();YAHOO.util.Region=function(C,D,A,B){this.top=C;this[1]=C;this.right=D;this.bottom=A;this.left=B;this[0]=B;};YAHOO.util.Region.prototype.contains=function(A){return(A.left>=this.left&&A.right<=this.right&&A.top>=this.top&&A.bottom<=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(E){var C=Math.max(this.top,E.top);var D=Math.min(this.right,E.right);var A=Math.min(this.bottom,E.bottom);var B=Math.max(this.left,E.left);if(A>=C&&D>=B){return new YAHOO.util.Region(C,D,A,B);}else{return null;}};YAHOO.util.Region.prototype.union=function(E){var C=Math.min(this.top,E.top);var D=Math.max(this.right,E.right);var A=Math.max(this.bottom,E.bottom);var B=Math.min(this.left,E.left);return new YAHOO.util.Region(C,D,A,B);};YAHOO.util.Region.prototype.toString=function(){return("Region {"+"top: "+this.top+", right: "+this.right+", bottom: "+this.bottom+", left: "+this.left+"}");};YAHOO.util.Region.getRegion=function(D){var F=YAHOO.util.Dom.getXY(D);var C=F[1];var E=F[0]+D.offsetWidth;var A=F[1]+D.offsetHeight;var B=F[0];return new YAHOO.util.Region(C,E,A,B);};YAHOO.util.Point=function(A,B){if(YAHOO.lang.isArray(A)){B=A[1];A=A[0];}this.x=this.right=this.left=this[0]=A;this.y=this.top=this.bottom=this[1]=B;};YAHOO.util.Point.prototype=new YAHOO.util.Region();YAHOO.register("dom",YAHOO.util.Dom,{version:"2.5.2",build:"1076"});YAHOO.util.CustomEvent=function(D,B,C,A){this.type=D;this.scope=B||window;this.silent=C;this.signature=A||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var E="_YUICEOnSubscribe";if(D!==E){this.subscribeEvent=new YAHOO.util.CustomEvent(E,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(B,C,A){if(!B){throw new Error("Invalid callback for subscriber to '"+this.type+"'");}if(this.subscribeEvent){this.subscribeEvent.fire(B,C,A);}this.subscribers.push(new YAHOO.util.Subscriber(B,C,A));},unsubscribe:function(D,F){if(!D){return this.unsubscribeAll();}var E=false;for(var B=0,A=this.subscribers.length;B<A;++B){var C=this.subscribers[B];if(C&&C.contains(D,F)){this._delete(B);E=true;}}return E;},fire:function(){this.lastError=null;var K=[],E=this.subscribers.length;if(!E&&this.silent){return true;}var I=[].slice.call(arguments,0),G=true,D,J=false;if(!this.silent){}var C=this.subscribers.slice(),A=YAHOO.util.Event.throwErrors;for(D=0;D<E;++D){var M=C[D];if(!M){J=true;}else{if(!this.silent){}var L=M.getScope(this.scope);if(this.signature==YAHOO.util.CustomEvent.FLAT){var B=null;if(I.length>0){B=I[0];}try{G=M.fn.call(L,B,M.obj);}catch(F){this.lastError=F;if(A){throw F;}}}else{try{G=M.fn.call(L,this.type,I,M.obj);}catch(H){this.lastError=H;if(A){throw H;}}}if(false===G){if(!this.silent){}break;}}}return(G!==false);},unsubscribeAll:function(){for(var A=this.subscribers.length-1;A>-1;A--){this._delete(A);}this.subscribers=[];return A;},_delete:function(A){var B=this.subscribers[A];if(B){delete B.fn;delete B.obj;}this.subscribers.splice(A,1);},toString:function(){return"CustomEvent: "+"'"+this.type+"', "+"scope: "+this.scope;}};YAHOO.util.Subscriber=function(B,C,A){this.fn=B;this.obj=YAHOO.lang.isUndefined(C)?null:C;this.override=A;};YAHOO.util.Subscriber.prototype.getScope=function(A){if(this.override){if(this.override===true){return this.obj;}else{return this.override;}}return A;};YAHOO.util.Subscriber.prototype.contains=function(A,B){if(B){return(this.fn==A&&this.obj==B);}else{return(this.fn==A);}};YAHOO.util.Subscriber.prototype.toString=function(){return"Subscriber { obj: "+this.obj+", override: "+(this.override||"no")+" }";};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var H=false;var I=[];var J=[];var G=[];var E=[];var C=0;var F=[];var B=[];var A=0;var D={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9};return{POLL_RETRYS:2000,POLL_INTERVAL:20,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:YAHOO.env.ua.ie,_interval:null,_dri:null,DOMReady:false,throwErrors:false,startInterval:function(){if(!this._interval){var K=this;var L=function(){K._tryPreloadAttach();};this._interval=setInterval(L,this.POLL_INTERVAL);}},onAvailable:function(P,M,Q,O,N){var K=(YAHOO.lang.isString(P))?[P]:P;for(var L=0;L<K.length;L=L+1){F.push({id:K[L],fn:M,obj:Q,override:O,checkReady:N});}C=this.POLL_RETRYS;this.startInterval();},onContentReady:function(M,K,N,L){this.onAvailable(M,K,N,L,true);},onDOMReady:function(K,M,L){if(this.DOMReady){setTimeout(function(){var N=window;if(L){if(L===true){N=M;}else{N=L;}}K.call(N,"DOMReady",[],M);},0);}else{this.DOMReadyEvent.subscribe(K,M,L);}},addListener:function(M,K,V,Q,L){if(!V||!V.call){return false;}if(this._isValidCollection(M)){var W=true;for(var R=0,T=M.length;R<T;++R){W=this.on(M[R],K,V,Q,L)&&W;}return W;}else{if(YAHOO.lang.isString(M)){var P=this.getEl(M);if(P){M=P;}else{this.onAvailable(M,function(){YAHOO.util.Event.on(M,K,V,Q,L);});return true;}}}if(!M){return false;}if("unload"==K&&Q!==this){J[J.length]=[M,K,V,Q,L];return true;}var Y=M;if(L){if(L===true){Y=Q;}else{Y=L;}}var N=function(Z){return V.call(Y,YAHOO.util.Event.getEvent(Z,M),Q);};var X=[M,K,V,N,Y,Q,L];var S=I.length;I[S]=X;if(this.useLegacyEvent(M,K)){var O=this.getLegacyIndex(M,K);if(O==-1||M!=G[O][0]){O=G.length;B[M.id+K]=O;G[O]=[M,K,M["on"+K]];E[O]=[];M["on"+K]=function(Z){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(Z),O);};}E[O].push(X);}else{try{this._simpleAdd(M,K,N,false);}catch(U){this.lastError=U;this.removeListener(M,K,V);return false;}}return true;},fireLegacyEvent:function(O,M){var Q=true,K,S,R,T,P;S=E[M].slice();for(var L=0,N=S.length;L<N;++L){R=S[L];if(R&&R[this.WFN]){T=R[this.ADJ_SCOPE];P=R[this.WFN].call(T,O);Q=(Q&&P);}}K=G[M];if(K&&K[2]){K[2](O);}return Q;},getLegacyIndex:function(L,M){var K=this.generateId(L)+M;if(typeof B[K]=="undefined"){return -1;}else{return B[K];}},useLegacyEvent:function(L,M){if(this.webkit&&("click"==M||"dblclick"==M)){var K=parseInt(this.webkit,10);if(!isNaN(K)&&K<418){return true;}}return false;},removeListener:function(L,K,T){var O,R,V;if(typeof L=="string"){L=this.getEl(L);}else{if(this._isValidCollection(L)){var U=true;for(O=L.length-1;O>-1;O--){U=(this.removeListener(L[O],K,T)&&U);}return U;}}if(!T||!T.call){return this.purgeElement(L,false,K);}if("unload"==K){for(O=J.length-1;O>-1;O--){V=J[O];if(V&&V[0]==L&&V[1]==K&&V[2]==T){J.splice(O,1);return true;}}return false;}var P=null;var Q=arguments[3];if("undefined"===typeof Q){Q=this._getCacheIndex(L,K,T);}if(Q>=0){P=I[Q];}if(!L||!P){return false;}if(this.useLegacyEvent(L,K)){var N=this.getLegacyIndex(L,K);var M=E[N];if(M){for(O=0,R=M.length;O<R;++O){V=M[O];if(V&&V[this.EL]==L&&V[this.TYPE]==K&&V[this.FN]==T){M.splice(O,1);break;}}}}else{try{this._simpleRemove(L,K,P[this.WFN],false);}catch(S){this.lastError=S;return false;}}delete I[Q][this.WFN];delete I[Q][this.FN];I.splice(Q,1);return true;},getTarget:function(M,L){var K=M.target||M.srcElement;return this.resolveTextNode(K);},resolveTextNode:function(L){try{if(L&&3==L.nodeType){return L.parentNode;}}catch(K){}return L;},getPageX:function(L){var K=L.pageX;if(!K&&0!==K){K=L.clientX||0;if(this.isIE){K+=this._getScrollLeft();}}return K;},getPageY:function(K){var L=K.pageY;if(!L&&0!==L){L=K.clientY||0;if(this.isIE){L+=this._getScrollTop();}}return L;
},getXY:function(K){return[this.getPageX(K),this.getPageY(K)];},getRelatedTarget:function(L){var K=L.relatedTarget;if(!K){if(L.type=="mouseout"){K=L.toElement;}else{if(L.type=="mouseover"){K=L.fromElement;}}}return this.resolveTextNode(K);},getTime:function(M){if(!M.time){var L=new Date().getTime();try{M.time=L;}catch(K){this.lastError=K;return L;}}return M.time;},stopEvent:function(K){this.stopPropagation(K);this.preventDefault(K);},stopPropagation:function(K){if(K.stopPropagation){K.stopPropagation();}else{K.cancelBubble=true;}},preventDefault:function(K){if(K.preventDefault){K.preventDefault();}else{K.returnValue=false;}},getEvent:function(M,K){var L=M||window.event;if(!L){var N=this.getEvent.caller;while(N){L=N.arguments[0];if(L&&Event==L.constructor){break;}N=N.caller;}}return L;},getCharCode:function(L){var K=L.keyCode||L.charCode||0;if(YAHOO.env.ua.webkit&&(K in D)){K=D[K];}return K;},_getCacheIndex:function(O,P,N){for(var M=0,L=I.length;M<L;M=M+1){var K=I[M];if(K&&K[this.FN]==N&&K[this.EL]==O&&K[this.TYPE]==P){return M;}}return -1;},generateId:function(K){var L=K.id;if(!L){L="yuievtautoid-"+A;++A;K.id=L;}return L;},_isValidCollection:function(L){try{return(L&&typeof L!=="string"&&L.length&&!L.tagName&&!L.alert&&typeof L[0]!=="undefined");}catch(K){return false;}},elCache:{},getEl:function(K){return(typeof K==="string")?document.getElementById(K):K;},clearCache:function(){},DOMReadyEvent:new YAHOO.util.CustomEvent("DOMReady",this),_load:function(L){if(!H){H=true;var K=YAHOO.util.Event;K._ready();K._tryPreloadAttach();}},_ready:function(L){var K=YAHOO.util.Event;if(!K.DOMReady){K.DOMReady=true;K.DOMReadyEvent.fire();K._simpleRemove(document,"DOMContentLoaded",K._ready);}},_tryPreloadAttach:function(){if(F.length===0){C=0;clearInterval(this._interval);this._interval=null;return ;}if(this.locked){return ;}if(this.isIE){if(!this.DOMReady){this.startInterval();return ;}}this.locked=true;var Q=!H;if(!Q){Q=(C>0&&F.length>0);}var P=[];var R=function(T,U){var S=T;if(U.override){if(U.override===true){S=U.obj;}else{S=U.override;}}U.fn.call(S,U.obj);};var L,K,O,N,M=[];for(L=0,K=F.length;L<K;L=L+1){O=F[L];if(O){N=this.getEl(O.id);if(N){if(O.checkReady){if(H||N.nextSibling||!Q){M.push(O);F[L]=null;}}else{R(N,O);F[L]=null;}}else{P.push(O);}}}for(L=0,K=M.length;L<K;L=L+1){O=M[L];R(this.getEl(O.id),O);}C--;if(Q){for(L=F.length-1;L>-1;L--){O=F[L];if(!O||!O.id){F.splice(L,1);}}this.startInterval();}else{clearInterval(this._interval);this._interval=null;}this.locked=false;},purgeElement:function(O,P,R){var M=(YAHOO.lang.isString(O))?this.getEl(O):O;var Q=this.getListeners(M,R),N,K;if(Q){for(N=Q.length-1;N>-1;N--){var L=Q[N];this.removeListener(M,L.type,L.fn);}}if(P&&M&&M.childNodes){for(N=0,K=M.childNodes.length;N<K;++N){this.purgeElement(M.childNodes[N],P,R);}}},getListeners:function(M,K){var P=[],L;if(!K){L=[I,J];}else{if(K==="unload"){L=[J];}else{L=[I];}}var R=(YAHOO.lang.isString(M))?this.getEl(M):M;for(var O=0;O<L.length;O=O+1){var T=L[O];if(T){for(var Q=0,S=T.length;Q<S;++Q){var N=T[Q];if(N&&N[this.EL]===R&&(!K||K===N[this.TYPE])){P.push({type:N[this.TYPE],fn:N[this.FN],obj:N[this.OBJ],adjust:N[this.OVERRIDE],scope:N[this.ADJ_SCOPE],index:Q});}}}}return(P.length)?P:null;},_unload:function(Q){var K=YAHOO.util.Event,N,M,L,P,O,R=J.slice();for(N=0,P=J.length;N<P;++N){L=R[N];if(L){var S=window;if(L[K.ADJ_SCOPE]){if(L[K.ADJ_SCOPE]===true){S=L[K.UNLOAD_OBJ];}else{S=L[K.ADJ_SCOPE];}}L[K.FN].call(S,K.getEvent(Q,L[K.EL]),L[K.UNLOAD_OBJ]);R[N]=null;L=null;S=null;}}J=null;if(I){for(M=I.length-1;M>-1;M--){L=I[M];if(L){K.removeListener(L[K.EL],L[K.TYPE],L[K.FN],M);}}L=null;}G=null;K._simpleRemove(window,"unload",K._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var K=document.documentElement,L=document.body;if(K&&(K.scrollTop||K.scrollLeft)){return[K.scrollTop,K.scrollLeft];}else{if(L){return[L.scrollTop,L.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(M,N,L,K){M.addEventListener(N,L,(K));};}else{if(window.attachEvent){return function(M,N,L,K){M.attachEvent("on"+N,L);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(M,N,L,K){M.removeEventListener(N,L,(K));};}else{if(window.detachEvent){return function(L,M,K){L.detachEvent("on"+M,K);};}else{return function(){};}}}()};}();(function(){var EU=YAHOO.util.Event;EU.on=EU.addListener;
/* DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller */
if(EU.isIE){YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var n=document.createElement("p");EU._dri=setInterval(function(){try{n.doScroll("left");clearInterval(EU._dri);EU._dri=null;EU._ready();n=null;}catch(ex){}},EU.POLL_INTERVAL);}else{if(EU.webkit&&EU.webkit<525){EU._dri=setInterval(function(){var rs=document.readyState;if("loaded"==rs||"complete"==rs){clearInterval(EU._dri);EU._dri=null;EU._ready();}},EU.POLL_INTERVAL);}else{EU._simpleAdd(document,"DOMContentLoaded",EU._ready);}}EU._simpleAdd(window,"load",EU._load);EU._simpleAdd(window,"unload",EU._unload);EU._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(A,C,F,E){this.__yui_events=this.__yui_events||{};var D=this.__yui_events[A];if(D){D.subscribe(C,F,E);}else{this.__yui_subscribers=this.__yui_subscribers||{};var B=this.__yui_subscribers;if(!B[A]){B[A]=[];}B[A].push({fn:C,obj:F,override:E});}},unsubscribe:function(C,E,G){this.__yui_events=this.__yui_events||{};var A=this.__yui_events;if(C){var F=A[C];if(F){return F.unsubscribe(E,G);}}else{var B=true;for(var D in A){if(YAHOO.lang.hasOwnProperty(A,D)){B=B&&A[D].unsubscribe(E,G);}}return B;}return false;},unsubscribeAll:function(A){return this.unsubscribe(A);},createEvent:function(G,D){this.__yui_events=this.__yui_events||{};var A=D||{};var I=this.__yui_events;
if(I[G]){}else{var H=A.scope||this;var E=(A.silent);var B=new YAHOO.util.CustomEvent(G,H,E,YAHOO.util.CustomEvent.FLAT);I[G]=B;if(A.onSubscribeCallback){B.subscribeEvent.subscribe(A.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var F=this.__yui_subscribers[G];if(F){for(var C=0;C<F.length;++C){B.subscribe(F[C].fn,F[C].obj,F[C].override);}}}return I[G];},fireEvent:function(E,D,A,C){this.__yui_events=this.__yui_events||{};var G=this.__yui_events[E];if(!G){return null;}var B=[];for(var F=1;F<arguments.length;++F){B.push(arguments[F]);}return G.fire.apply(G,B);},hasEvent:function(A){if(this.__yui_events){if(this.__yui_events[A]){return true;}}return false;}};YAHOO.util.KeyListener=function(A,F,B,C){if(!A){}else{if(!F){}else{if(!B){}}}if(!C){C=YAHOO.util.KeyListener.KEYDOWN;}var D=new YAHOO.util.CustomEvent("keyPressed");this.enabledEvent=new YAHOO.util.CustomEvent("enabled");this.disabledEvent=new YAHOO.util.CustomEvent("disabled");if(typeof A=="string"){A=document.getElementById(A);}if(typeof B=="function"){D.subscribe(B);}else{D.subscribe(B.fn,B.scope,B.correctScope);}function E(J,I){if(!F.shift){F.shift=false;}if(!F.alt){F.alt=false;}if(!F.ctrl){F.ctrl=false;}if(J.shiftKey==F.shift&&J.altKey==F.alt&&J.ctrlKey==F.ctrl){var G;if(F.keys instanceof Array){for(var H=0;H<F.keys.length;H++){G=F.keys[H];if(G==J.charCode){D.fire(J.charCode,J);break;}else{if(G==J.keyCode){D.fire(J.keyCode,J);break;}}}}else{G=F.keys;if(G==J.charCode){D.fire(J.charCode,J);}else{if(G==J.keyCode){D.fire(J.keyCode,J);}}}}}this.enable=function(){if(!this.enabled){YAHOO.util.Event.addListener(A,C,E);this.enabledEvent.fire(F);}this.enabled=true;};this.disable=function(){if(this.enabled){YAHOO.util.Event.removeListener(A,C,E);this.disabledEvent.fire(F);}this.enabled=false;};this.toString=function(){return"KeyListener ["+F.keys+"] "+A.tagName+(A.id?"["+A.id+"]":"");};};YAHOO.util.KeyListener.KEYDOWN="keydown";YAHOO.util.KeyListener.KEYUP="keyup";YAHOO.util.KeyListener.KEY={ALT:18,BACK_SPACE:8,CAPS_LOCK:20,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,META:224,NUM_LOCK:144,PAGE_DOWN:34,PAGE_UP:33,PAUSE:19,PRINTSCREEN:44,RIGHT:39,SCROLL_LOCK:145,SHIFT:16,SPACE:32,TAB:9,UP:38};YAHOO.register("event",YAHOO.util.Event,{version:"2.5.2",build:"1076"});YAHOO.util.Connect={_msxml_progid:["Microsoft.XMLHTTP","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP"],_http_headers:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:"application/x-www-form-urlencoded; charset=UTF-8",_default_form_header:"application/x-www-form-urlencoded",_use_default_xhr_header:true,_default_xhr_header:"XMLHttpRequest",_has_default_headers:true,_default_headers:{},_isFormSubmit:false,_isFileUpload:false,_formNode:null,_sFormData:null,_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,_submitElementValue:null,_hasSubmitListener:(function(){if(YAHOO.util.Event){YAHOO.util.Event.addListener(document,"click",function(B){var A=YAHOO.util.Event.getTarget(B);if(A.nodeName.toLowerCase()=="input"&&(A.type&&A.type.toLowerCase()=="submit")){YAHOO.util.Connect._submitElementValue=encodeURIComponent(A.name)+"="+encodeURIComponent(A.value);}});return true;}return false;})(),startEvent:new YAHOO.util.CustomEvent("start"),completeEvent:new YAHOO.util.CustomEvent("complete"),successEvent:new YAHOO.util.CustomEvent("success"),failureEvent:new YAHOO.util.CustomEvent("failure"),uploadEvent:new YAHOO.util.CustomEvent("upload"),abortEvent:new YAHOO.util.CustomEvent("abort"),_customEvents:{onStart:["startEvent","start"],onComplete:["completeEvent","complete"],onSuccess:["successEvent","success"],onFailure:["failureEvent","failure"],onUpload:["uploadEvent","upload"],onAbort:["abortEvent","abort"]},setProgId:function(A){this._msxml_progid.unshift(A);YAHOO.log("ActiveX Program Id  "+A+" added to _msxml_progid.","info","Connection");},setDefaultPostHeader:function(A){if(typeof A=="string"){this._default_post_header=A;YAHOO.log("Default POST header set to  "+A,"info","Connection");}else{if(typeof A=="boolean"){this._use_default_post_header=A;}}},setDefaultXhrHeader:function(A){if(typeof A=="string"){this._default_xhr_header=A;YAHOO.log("Default XHR header set to  "+A,"info","Connection");}else{this._use_default_xhr_header=A;}},setPollingInterval:function(A){if(typeof A=="number"&&isFinite(A)){this._polling_interval=A;YAHOO.log("Default polling interval set to "+A+"ms","info","Connection");}},createXhrObject:function(E){var D,A;try{A=new XMLHttpRequest();D={conn:A,tId:E};YAHOO.log("XHR object created for transaction "+E,"info","Connection");}catch(C){for(var B=0;B<this._msxml_progid.length;++B){try{A=new ActiveXObject(this._msxml_progid[B]);D={conn:A,tId:E};YAHOO.log("ActiveX XHR object created for transaction "+E,"info","Connection");break;}catch(C){}}}finally{return D;}},getConnectionObject:function(A){var C;var D=this._transaction_id;try{if(!A){C=this.createXhrObject(D);}else{C={};C.tId=D;C.isUpload=true;}if(C){this._transaction_id++;}}catch(B){}finally{return C;}},asyncRequest:function(F,C,E,A){var D=(this._isFileUpload)?this.getConnectionObject(true):this.getConnectionObject();var B=(E&&E.argument)?E.argument:null;if(!D){YAHOO.log("Unable to create connection object.","error","Connection");return null;}else{if(E&&E.customevents){this.initCustomEvents(D,E);}if(this._isFormSubmit){if(this._isFileUpload){this.uploadFile(D,E,C,A);return D;}if(F.toUpperCase()=="GET"){if(this._sFormData.length!==0){C+=((C.indexOf("?")==-1)?"?":"&")+this._sFormData;}}else{if(F.toUpperCase()=="POST"){A=A?this._sFormData+"&"+A:this._sFormData;}}}if(F.toUpperCase()=="GET"&&(E&&E.cache===false)){C+=((C.indexOf("?")==-1)?"?":"&")+"rnd="+new Date().valueOf().toString();}D.conn.open(F,C,true);if(this._use_default_xhr_header){if(!this._default_headers["X-Requested-With"]){this.initHeader("X-Requested-With",this._default_xhr_header,true);YAHOO.log("Initialize transaction header X-Request-Header to XMLHttpRequest.","info","Connection");}}if((F.toUpperCase()=="POST"&&this._use_default_post_header)&&this._isFormSubmit===false){this.initHeader("Content-Type",this._default_post_header);YAHOO.log("Initialize header Content-Type to application/x-www-form-urlencoded; UTF-8 for POST transaction.","info","Connection");}if(this._has_default_headers||this._has_http_headers){this.setHeader(D);}this.handleReadyState(D,E);D.conn.send(A||"");YAHOO.log("Transaction "+D.tId+" sent.","info","Connection");if(this._isFormSubmit===true){this.resetFormState();}this.startEvent.fire(D,B);if(D.startEvent){D.startEvent.fire(D,B);}return D;}},initCustomEvents:function(A,C){for(var B in C.customevents){if(this._customEvents[B][0]){A[this._customEvents[B][0]]=new YAHOO.util.CustomEvent(this._customEvents[B][1],(C.scope)?C.scope:null);YAHOO.log("Transaction-specific Custom Event "+A[this._customEvents[B][1]]+" created.","info","Connection");A[this._customEvents[B][0]].subscribe(C.customevents[B]);YAHOO.log("Transaction-specific Custom Event "+A[this._customEvents[B][1]]+" subscribed.","info","Connection");}}},handleReadyState:function(C,D){var B=this;var A=(D&&D.argument)?D.argument:null;if(D&&D.timeout){this._timeOut[C.tId]=window.setTimeout(function(){B.abort(C,D,true);},D.timeout);}this._poll[C.tId]=window.setInterval(function(){if(C.conn&&C.conn.readyState===4){window.clearInterval(B._poll[C.tId]);delete B._poll[C.tId];if(D&&D.timeout){window.clearTimeout(B._timeOut[C.tId]);delete B._timeOut[C.tId];}B.completeEvent.fire(C,A);if(C.completeEvent){C.completeEvent.fire(C,A);}B.handleTransactionResponse(C,D);}},this._polling_interval);},handleTransactionResponse:function(F,G,A){var D,C;var B=(G&&G.argument)?G.argument:null;try{if(F.conn.status!==undefined&&F.conn.status!==0){D=F.conn.status;}else{D=13030;}}catch(E){D=13030;}if(D>=200&&D<300||D===1223){C=this.createResponseObject(F,B);if(G&&G.success){if(!G.scope){G.success(C);YAHOO.log("Success callback. HTTP code is "+D,"info","Connection");}else{G.success.apply(G.scope,[C]);YAHOO.log("Success callback with scope. HTTP code is "+D,"info","Connection");}}this.successEvent.fire(C);if(F.successEvent){F.successEvent.fire(C);}}else{switch(D){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:C=this.createExceptionObject(F.tId,B,(A?A:false));if(G&&G.failure){if(!G.scope){G.failure(C);
YAHOO.log("Failure callback. Exception detected. Status code is "+D,"warn","Connection");}else{G.failure.apply(G.scope,[C]);YAHOO.log("Failure callback with scope. Exception detected. Status code is "+D,"warn","Connection");}}break;default:C=this.createResponseObject(F,B);if(G&&G.failure){if(!G.scope){G.failure(C);YAHOO.log("Failure callback. HTTP status code is "+D,"warn","Connection");}else{G.failure.apply(G.scope,[C]);YAHOO.log("Failure callback with scope. HTTP status code is "+D,"warn","Connection");}}}this.failureEvent.fire(C);if(F.failureEvent){F.failureEvent.fire(C);}}this.releaseObject(F);C=null;},createResponseObject:function(A,G){var D={};var I={};try{var C=A.conn.getAllResponseHeaders();var F=C.split("\n");for(var E=0;E<F.length;E++){var B=F[E].indexOf(":");if(B!=-1){I[F[E].substring(0,B)]=F[E].substring(B+2);}}}catch(H){}D.tId=A.tId;D.status=(A.conn.status==1223)?204:A.conn.status;D.statusText=(A.conn.status==1223)?"No Content":A.conn.statusText;D.getResponseHeader=I;D.getAllResponseHeaders=C;D.responseText=A.conn.responseText;D.responseXML=A.conn.responseXML;if(G){D.argument=G;}return D;},createExceptionObject:function(H,D,A){var F=0;var G="communication failure";var C=-1;var B="transaction aborted";var E={};E.tId=H;if(A){E.status=C;E.statusText=B;}else{E.status=F;E.statusText=G;}if(D){E.argument=D;}return E;},initHeader:function(A,D,C){var B=(C)?this._default_headers:this._http_headers;B[A]=D;if(C){this._has_default_headers=true;}else{this._has_http_headers=true;}},setHeader:function(A){if(this._has_default_headers){for(var B in this._default_headers){if(YAHOO.lang.hasOwnProperty(this._default_headers,B)){A.conn.setRequestHeader(B,this._default_headers[B]);YAHOO.log("Default HTTP header "+B+" set with value of "+this._default_headers[B],"info","Connection");}}}if(this._has_http_headers){for(var B in this._http_headers){if(YAHOO.lang.hasOwnProperty(this._http_headers,B)){A.conn.setRequestHeader(B,this._http_headers[B]);YAHOO.log("HTTP header "+B+" set with value of "+this._http_headers[B],"info","Connection");}}delete this._http_headers;this._http_headers={};this._has_http_headers=false;}},resetDefaultHeaders:function(){delete this._default_headers;this._default_headers={};this._has_default_headers=false;},setForm:function(K,E,B){this.resetFormState();var J;if(typeof K=="string"){J=(document.getElementById(K)||document.forms[K]);}else{if(typeof K=="object"){J=K;}else{YAHOO.log("Unable to create form object "+K,"warn","Connection");return ;}}if(E){var F=this.createFrame((window.location.href.toLowerCase().indexOf("https")===0||B)?true:false);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=J;return ;}var A,I,G,L;var H=false;for(var D=0;D<J.elements.length;D++){A=J.elements[D];L=A.disabled;I=A.name;G=A.value;if(!L&&I){switch(A.type){case"select-one":case"select-multiple":for(var C=0;C<A.options.length;C++){if(A.options[C].selected){if(window.ActiveXObject){this._sFormData+=encodeURIComponent(I)+"="+encodeURIComponent(A.options[C].attributes["value"].specified?A.options[C].value:A.options[C].text)+"&";}else{this._sFormData+=encodeURIComponent(I)+"="+encodeURIComponent(A.options[C].hasAttribute("value")?A.options[C].value:A.options[C].text)+"&";}}}break;case"radio":case"checkbox":if(A.checked){this._sFormData+=encodeURIComponent(I)+"="+encodeURIComponent(G)+"&";}break;case"file":case undefined:case"reset":case"button":break;case"submit":if(H===false){if(this._hasSubmitListener&&this._submitElementValue){this._sFormData+=this._submitElementValue+"&";}else{this._sFormData+=encodeURIComponent(I)+"="+encodeURIComponent(G)+"&";}H=true;}break;default:this._sFormData+=encodeURIComponent(I)+"="+encodeURIComponent(G)+"&";}}}this._isFormSubmit=true;this._sFormData=this._sFormData.substr(0,this._sFormData.length-1);YAHOO.log("Form initialized for transaction. HTML form POST message is: "+this._sFormData,"info","Connection");this.initHeader("Content-Type",this._default_form_header);YAHOO.log("Initialize header Content-Type to application/x-www-form-urlencoded for setForm() transaction.","info","Connection");return this._sFormData;},resetFormState:function(){this._isFormSubmit=false;this._isFileUpload=false;this._formNode=null;this._sFormData="";},createFrame:function(A){var B="yuiIO"+this._transaction_id;var C;if(window.ActiveXObject){C=document.createElement('<iframe id="'+B+'" name="'+B+'" />');if(typeof A=="boolean"){C.src="javascript:false";}}else{C=document.createElement("iframe");C.id=B;C.name=B;}C.style.position="absolute";C.style.top="-1000px";C.style.left="-1000px";document.body.appendChild(C);YAHOO.log("File upload iframe created. Id is:"+B,"info","Connection");},appendPostData:function(A){var D=[];var B=A.split("&");for(var C=0;C<B.length;C++){var E=B[C].indexOf("=");if(E!=-1){D[C]=document.createElement("input");D[C].type="hidden";D[C].name=B[C].substring(0,E);D[C].value=B[C].substring(E+1);this._formNode.appendChild(D[C]);}}return D;},uploadFile:function(D,M,E,C){var N=this;var H="yuiIO"+D.tId;var I="multipart/form-data";var K=document.getElementById(H);var J=(M&&M.argument)?M.argument:null;var B={action:this._formNode.getAttribute("action"),method:this._formNode.getAttribute("method"),target:this._formNode.getAttribute("target")};this._formNode.setAttribute("action",E);this._formNode.setAttribute("method","POST");this._formNode.setAttribute("target",H);if(YAHOO.env.ua.ie){this._formNode.setAttribute("encoding",I);}else{this._formNode.setAttribute("enctype",I);}if(C){var L=this.appendPostData(C);}this._formNode.submit();this.startEvent.fire(D,J);if(D.startEvent){D.startEvent.fire(D,J);}if(M&&M.timeout){this._timeOut[D.tId]=window.setTimeout(function(){N.abort(D,M,true);},M.timeout);}if(L&&L.length>0){for(var G=0;G<L.length;G++){this._formNode.removeChild(L[G]);}}for(var A in B){if(YAHOO.lang.hasOwnProperty(B,A)){if(B[A]){this._formNode.setAttribute(A,B[A]);}else{this._formNode.removeAttribute(A);}}}this.resetFormState();var F=function(){if(M&&M.timeout){window.clearTimeout(N._timeOut[D.tId]);
delete N._timeOut[D.tId];}N.completeEvent.fire(D,J);if(D.completeEvent){D.completeEvent.fire(D,J);}var P={};P.tId=D.tId;P.argument=M.argument;try{P.responseText=K.contentWindow.document.body?K.contentWindow.document.body.innerHTML:K.contentWindow.document.documentElement.textContent;P.responseXML=K.contentWindow.document.XMLDocument?K.contentWindow.document.XMLDocument:K.contentWindow.document;}catch(O){}if(M&&M.upload){if(!M.scope){M.upload(P);YAHOO.log("Upload callback.","info","Connection");}else{M.upload.apply(M.scope,[P]);YAHOO.log("Upload callback with scope.","info","Connection");}}N.uploadEvent.fire(P);if(D.uploadEvent){D.uploadEvent.fire(P);}YAHOO.util.Event.removeListener(K,"load",F);setTimeout(function(){document.body.removeChild(K);N.releaseObject(D);YAHOO.log("File upload iframe destroyed. Id is:"+H,"info","Connection");},100);};YAHOO.util.Event.addListener(K,"load",F);},abort:function(E,G,A){var D;var B=(G&&G.argument)?G.argument:null;if(E&&E.conn){if(this.isCallInProgress(E)){E.conn.abort();window.clearInterval(this._poll[E.tId]);delete this._poll[E.tId];if(A){window.clearTimeout(this._timeOut[E.tId]);delete this._timeOut[E.tId];}D=true;}}else{if(E&&E.isUpload===true){var C="yuiIO"+E.tId;var F=document.getElementById(C);if(F){YAHOO.util.Event.removeListener(F,"load");document.body.removeChild(F);YAHOO.log("File upload iframe destroyed. Id is:"+C,"info","Connection");if(A){window.clearTimeout(this._timeOut[E.tId]);delete this._timeOut[E.tId];}D=true;}}else{D=false;}}if(D===true){this.abortEvent.fire(E,B);if(E.abortEvent){E.abortEvent.fire(E,B);}this.handleTransactionResponse(E,G,true);YAHOO.log("Transaction "+E.tId+" aborted.","info","Connection");}return D;},isCallInProgress:function(B){if(B&&B.conn){return B.conn.readyState!==4&&B.conn.readyState!==0;}else{if(B&&B.isUpload===true){var A="yuiIO"+B.tId;return document.getElementById(A)?true:false;}else{return false;}}},releaseObject:function(A){if(A&&A.conn){A.conn=null;YAHOO.log("Connection object for transaction "+A.tId+" destroyed.","info","Connection");A=null;}}};YAHOO.register("connection",YAHOO.util.Connect,{version:"2.5.2",build:"1076"});(function(){var B=YAHOO.util;var A=function(D,C,E,F){if(!D){}this.init(D,C,E,F);};A.NAME="Anim";A.prototype={toString:function(){var C=this.getEl()||{};var D=C.id||C.tagName;return(this.constructor.NAME+": "+D);},patterns:{noNegatives:/width|height|opacity|padding/i,offsetAttribute:/^((width|height)|(top|left))$/,defaultUnit:/width|height|top$|bottom$|left$|right$/i,offsetUnit:/\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i},doMethod:function(C,E,D){return this.method(this.currentFrame,E,D-E,this.totalFrames);},setAttribute:function(C,E,D){if(this.patterns.noNegatives.test(C)){E=(E>0)?E:0;}B.Dom.setStyle(this.getEl(),C,E+D);},getAttribute:function(C){var E=this.getEl();var G=B.Dom.getStyle(E,C);if(G!=="auto"&&!this.patterns.offsetUnit.test(G)){return parseFloat(G);}var D=this.patterns.offsetAttribute.exec(C)||[];var H=!!(D[3]);var F=!!(D[2]);if(F||(B.Dom.getStyle(E,"position")=="absolute"&&H)){G=E["offset"+D[0].charAt(0).toUpperCase()+D[0].substr(1)];}else{G=0;}return G;},getDefaultUnit:function(C){if(this.patterns.defaultUnit.test(C)){return"px";}return"";},setRuntimeAttribute:function(D){var I;var E;var F=this.attributes;this.runtimeAttributes[D]={};var H=function(J){return(typeof J!=="undefined");};if(!H(F[D]["to"])&&!H(F[D]["by"])){return false;}I=(H(F[D]["from"]))?F[D]["from"]:this.getAttribute(D);if(H(F[D]["to"])){E=F[D]["to"];}else{if(H(F[D]["by"])){if(I.constructor==Array){E=[];for(var G=0,C=I.length;G<C;++G){E[G]=I[G]+F[D]["by"][G]*1;}}else{E=I+F[D]["by"]*1;}}}this.runtimeAttributes[D].start=I;this.runtimeAttributes[D].end=E;this.runtimeAttributes[D].unit=(H(F[D].unit))?F[D]["unit"]:this.getDefaultUnit(D);return true;},init:function(E,J,I,C){var D=false;var F=null;var H=0;E=B.Dom.get(E);this.attributes=J||{};this.duration=!YAHOO.lang.isUndefined(I)?I:1;this.method=C||B.Easing.easeNone;this.useSeconds=true;this.currentFrame=0;this.totalFrames=B.AnimMgr.fps;this.setEl=function(M){E=B.Dom.get(M);};this.getEl=function(){return E;};this.isAnimated=function(){return D;};this.getStartTime=function(){return F;};this.runtimeAttributes={};this.animate=function(){if(this.isAnimated()){return false;}this.currentFrame=0;this.totalFrames=(this.useSeconds)?Math.ceil(B.AnimMgr.fps*this.duration):this.duration;if(this.duration===0&&this.useSeconds){this.totalFrames=1;}B.AnimMgr.registerElement(this);return true;};this.stop=function(M){if(!this.isAnimated()){return false;}if(M){this.currentFrame=this.totalFrames;this._onTween.fire();}B.AnimMgr.stop(this);};var L=function(){this.onStart.fire();this.runtimeAttributes={};for(var M in this.attributes){this.setRuntimeAttribute(M);}D=true;H=0;F=new Date();};var K=function(){var O={duration:new Date()-this.getStartTime(),currentFrame:this.currentFrame};O.toString=function(){return("duration: "+O.duration+", currentFrame: "+O.currentFrame);};this.onTween.fire(O);var N=this.runtimeAttributes;for(var M in N){this.setAttribute(M,this.doMethod(M,N[M].start,N[M].end),N[M].unit);}H+=1;};var G=function(){var M=(new Date()-F)/1000;var N={duration:M,frames:H,fps:H/M};N.toString=function(){return("duration: "+N.duration+", frames: "+N.frames+", fps: "+N.fps);};D=false;H=0;this.onComplete.fire(N);};this._onStart=new B.CustomEvent("_start",this,true);this.onStart=new B.CustomEvent("start",this);this.onTween=new B.CustomEvent("tween",this);this._onTween=new B.CustomEvent("_tween",this,true);this.onComplete=new B.CustomEvent("complete",this);this._onComplete=new B.CustomEvent("_complete",this,true);this._onStart.subscribe(L);this._onTween.subscribe(K);this._onComplete.subscribe(G);}};B.Anim=A;})();YAHOO.util.AnimMgr=new function(){var C=null;var B=[];var A=0;this.fps=1000;this.delay=1;this.registerElement=function(F){B[B.length]=F;A+=1;F._onStart.fire();this.start();};this.unRegister=function(G,F){F=F||E(G);if(!G.isAnimated()||F==-1){return false;}G._onComplete.fire();B.splice(F,1);A-=1;if(A<=0){this.stop();}return true;};this.start=function(){if(C===null){C=setInterval(this.run,this.delay);}};this.stop=function(H){if(!H){clearInterval(C);for(var G=0,F=B.length;G<F;++G){this.unRegister(B[0],0);}B=[];C=null;A=0;}else{this.unRegister(H);}};this.run=function(){for(var H=0,F=B.length;H<F;++H){var G=B[H];if(!G||!G.isAnimated()){continue;}if(G.currentFrame<G.totalFrames||G.totalFrames===null){G.currentFrame+=1;if(G.useSeconds){D(G);}G._onTween.fire();}else{YAHOO.util.AnimMgr.stop(G,H);}}};var E=function(H){for(var G=0,F=B.length;G<F;++G){if(B[G]==H){return G;}}return -1;};var D=function(G){var J=G.totalFrames;var I=G.currentFrame;var H=(G.currentFrame*G.duration*1000/G.totalFrames);var F=(new Date()-G.getStartTime());var K=0;if(F<G.duration*1000){K=Math.round((F/H-1)*G.currentFrame);}else{K=J-(I+1);}if(K>0&&isFinite(K)){if(G.currentFrame+K>=J){K=J-(I+1);}G.currentFrame+=K;}};};YAHOO.util.Bezier=new function(){this.getPosition=function(E,D){var F=E.length;var C=[];for(var B=0;B<F;++B){C[B]=[E[B][0],E[B][1]];}for(var A=1;A<F;++A){for(B=0;B<F-A;++B){C[B][0]=(1-D)*C[B][0]+D*C[parseInt(B+1,10)][0];C[B][1]=(1-D)*C[B][1]+D*C[parseInt(B+1,10)][1];}}return[C[0][0],C[0][1]];};};(function(){var A=function(F,E,G,H){A.superclass.constructor.call(this,F,E,G,H);};A.NAME="ColorAnim";var C=YAHOO.util;YAHOO.extend(A,C.Anim);var D=A.superclass;var B=A.prototype;B.patterns.color=/color$/i;B.patterns.rgb=/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;B.patterns.hex=/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;B.patterns.hex3=/^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;B.patterns.transparent=/^transparent|rgba\(0, 0, 0, 0\)$/;B.parseColor=function(E){if(E.length==3){return E;}var F=this.patterns.hex.exec(E);if(F&&F.length==4){return[parseInt(F[1],16),parseInt(F[2],16),parseInt(F[3],16)];}F=this.patterns.rgb.exec(E);if(F&&F.length==4){return[parseInt(F[1],10),parseInt(F[2],10),parseInt(F[3],10)];}F=this.patterns.hex3.exec(E);if(F&&F.length==4){return[parseInt(F[1]+F[1],16),parseInt(F[2]+F[2],16),parseInt(F[3]+F[3],16)];}return null;};B.getAttribute=function(E){var G=this.getEl();if(this.patterns.color.test(E)){var H=YAHOO.util.Dom.getStyle(G,E);
if(this.patterns.transparent.test(H)){var F=G.parentNode;H=C.Dom.getStyle(F,E);while(F&&this.patterns.transparent.test(H)){F=F.parentNode;H=C.Dom.getStyle(F,E);if(F.tagName.toUpperCase()=="HTML"){H="#fff";}}}}else{H=D.getAttribute.call(this,E);}return H;};B.doMethod=function(F,J,G){var I;if(this.patterns.color.test(F)){I=[];for(var H=0,E=J.length;H<E;++H){I[H]=D.doMethod.call(this,F,J[H],G[H]);}I="rgb("+Math.floor(I[0])+","+Math.floor(I[1])+","+Math.floor(I[2])+")";}else{I=D.doMethod.call(this,F,J,G);}return I;};B.setRuntimeAttribute=function(F){D.setRuntimeAttribute.call(this,F);if(this.patterns.color.test(F)){var H=this.attributes;var J=this.parseColor(this.runtimeAttributes[F].start);var G=this.parseColor(this.runtimeAttributes[F].end);if(typeof H[F]["to"]==="undefined"&&typeof H[F]["by"]!=="undefined"){G=this.parseColor(H[F].by);for(var I=0,E=J.length;I<E;++I){G[I]=J[I]+G[I];}}this.runtimeAttributes[F].start=J;this.runtimeAttributes[F].end=G;}};C.ColorAnim=A;})();
/*
TERMS OF USE - EASING EQUATIONS
Open source under the BSD License.
Copyright 2001 Robert Penner All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
YAHOO.util.Easing={easeNone:function(B,A,D,C){return D*B/C+A;},easeIn:function(B,A,D,C){return D*(B/=C)*B+A;},easeOut:function(B,A,D,C){return -D*(B/=C)*(B-2)+A;},easeBoth:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B+A;}return -D/2*((--B)*(B-2)-1)+A;},easeInStrong:function(B,A,D,C){return D*(B/=C)*B*B*B+A;},easeOutStrong:function(B,A,D,C){return -D*((B=B/C-1)*B*B*B-1)+A;},easeBothStrong:function(B,A,D,C){if((B/=C/2)<1){return D/2*B*B*B*B+A;}return -D/2*((B-=2)*B*B*B-2)+A;},elasticIn:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F)==1){return A+G;}if(!E){E=F*0.3;}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}return -(B*Math.pow(2,10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E))+A;},elasticOut:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F)==1){return A+G;}if(!E){E=F*0.3;}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}return B*Math.pow(2,-10*C)*Math.sin((C*F-D)*(2*Math.PI)/E)+G+A;},elasticBoth:function(C,A,G,F,B,E){if(C==0){return A;}if((C/=F/2)==2){return A+G;}if(!E){E=F*(0.3*1.5);}if(!B||B<Math.abs(G)){B=G;var D=E/4;}else{var D=E/(2*Math.PI)*Math.asin(G/B);}if(C<1){return -0.5*(B*Math.pow(2,10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E))+A;}return B*Math.pow(2,-10*(C-=1))*Math.sin((C*F-D)*(2*Math.PI)/E)*0.5+G+A;},backIn:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}return E*(B/=D)*B*((C+1)*B-C)+A;},backOut:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}return E*((B=B/D-1)*B*((C+1)*B+C)+1)+A;},backBoth:function(B,A,E,D,C){if(typeof C=="undefined"){C=1.70158;}if((B/=D/2)<1){return E/2*(B*B*(((C*=(1.525))+1)*B-C))+A;}return E/2*((B-=2)*B*(((C*=(1.525))+1)*B+C)+2)+A;},bounceIn:function(B,A,D,C){return D-YAHOO.util.Easing.bounceOut(C-B,0,D,C)+A;},bounceOut:function(B,A,D,C){if((B/=C)<(1/2.75)){return D*(7.5625*B*B)+A;}else{if(B<(2/2.75)){return D*(7.5625*(B-=(1.5/2.75))*B+0.75)+A;}else{if(B<(2.5/2.75)){return D*(7.5625*(B-=(2.25/2.75))*B+0.9375)+A;}}}return D*(7.5625*(B-=(2.625/2.75))*B+0.984375)+A;},bounceBoth:function(B,A,D,C){if(B<C/2){return YAHOO.util.Easing.bounceIn(B*2,0,D,C)*0.5+A;}return YAHOO.util.Easing.bounceOut(B*2-C,0,D,C)*0.5+D*0.5+A;}};(function(){var A=function(H,G,I,J){if(H){A.superclass.constructor.call(this,H,G,I,J);}};A.NAME="Motion";var E=YAHOO.util;YAHOO.extend(A,E.ColorAnim);var F=A.superclass;var C=A.prototype;C.patterns.points=/^points$/i;C.setAttribute=function(G,I,H){if(this.patterns.points.test(G)){H=H||"px";F.setAttribute.call(this,"left",I[0],H);F.setAttribute.call(this,"top",I[1],H);}else{F.setAttribute.call(this,G,I,H);}};C.getAttribute=function(G){if(this.patterns.points.test(G)){var H=[F.getAttribute.call(this,"left"),F.getAttribute.call(this,"top")];}else{H=F.getAttribute.call(this,G);}return H;};C.doMethod=function(G,K,H){var J=null;if(this.patterns.points.test(G)){var I=this.method(this.currentFrame,0,100,this.totalFrames)/100;J=E.Bezier.getPosition(this.runtimeAttributes[G],I);}else{J=F.doMethod.call(this,G,K,H);}return J;};C.setRuntimeAttribute=function(P){if(this.patterns.points.test(P)){var H=this.getEl();var J=this.attributes;var G;var L=J["points"]["control"]||[];var I;var M,O;if(L.length>0&&!(L[0] instanceof Array)){L=[L];}else{var K=[];for(M=0,O=L.length;M<O;++M){K[M]=L[M];}L=K;}if(E.Dom.getStyle(H,"position")=="static"){E.Dom.setStyle(H,"position","relative");}if(D(J["points"]["from"])){E.Dom.setXY(H,J["points"]["from"]);}else{E.Dom.setXY(H,E.Dom.getXY(H));}G=this.getAttribute("points");if(D(J["points"]["to"])){I=B.call(this,J["points"]["to"],G);
var N=E.Dom.getXY(this.getEl());for(M=0,O=L.length;M<O;++M){L[M]=B.call(this,L[M],G);}}else{if(D(J["points"]["by"])){I=[G[0]+J["points"]["by"][0],G[1]+J["points"]["by"][1]];for(M=0,O=L.length;M<O;++M){L[M]=[G[0]+L[M][0],G[1]+L[M][1]];}}}this.runtimeAttributes[P]=[G];if(L.length>0){this.runtimeAttributes[P]=this.runtimeAttributes[P].concat(L);}this.runtimeAttributes[P][this.runtimeAttributes[P].length]=I;}else{F.setRuntimeAttribute.call(this,P);}};var B=function(G,I){var H=E.Dom.getXY(this.getEl());G=[G[0]-H[0]+I[0],G[1]-H[1]+I[1]];return G;};var D=function(G){return(typeof G!=="undefined");};E.Motion=A;})();(function(){var D=function(F,E,G,H){if(F){D.superclass.constructor.call(this,F,E,G,H);}};D.NAME="Scroll";var B=YAHOO.util;YAHOO.extend(D,B.ColorAnim);var C=D.superclass;var A=D.prototype;A.doMethod=function(E,H,F){var G=null;if(E=="scroll"){G=[this.method(this.currentFrame,H[0],F[0]-H[0],this.totalFrames),this.method(this.currentFrame,H[1],F[1]-H[1],this.totalFrames)];}else{G=C.doMethod.call(this,E,H,F);}return G;};A.getAttribute=function(E){var G=null;var F=this.getEl();if(E=="scroll"){G=[F.scrollLeft,F.scrollTop];}else{G=C.getAttribute.call(this,E);}return G;};A.setAttribute=function(E,H,G){var F=this.getEl();if(E=="scroll"){F.scrollLeft=H[0];F.scrollTop=H[1];}else{C.setAttribute.call(this,E,H,G);}};B.Scroll=D;})();YAHOO.register("animation",YAHOO.util.Anim,{version:"2.5.2",build:"1076"});if(!YAHOO.util.DragDropMgr){YAHOO.util.DragDropMgr=function(){var A=YAHOO.util.Event;return{ids:{},handleIds:{},dragCurrent:null,dragOvers:{},deltaX:0,deltaY:0,preventDefault:true,stopPropagation:true,initialized:false,locked:false,interactionInfo:null,init:function(){this.initialized=true;},POINT:0,INTERSECT:1,STRICT_INTERSECT:2,mode:0,_execOnAll:function(D,C){for(var E in this.ids){for(var B in this.ids[E]){var F=this.ids[E][B];if(!this.isTypeOfDD(F)){continue;}F[D].apply(F,C);}}},_onLoad:function(){this.init();A.on(document,"mouseup",this.handleMouseUp,this,true);A.on(document,"mousemove",this.handleMouseMove,this,true);A.on(window,"unload",this._onUnload,this,true);A.on(window,"resize",this._onResize,this,true);},_onResize:function(B){this._execOnAll("resetConstraints",[]);},lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isLocked:function(){return this.locked;},locationCache:{},useCache:true,clickPixelThresh:3,clickTimeThresh:1000,dragThreshMet:false,clickTimeout:null,startX:0,startY:0,fromTimeout:false,regDragDrop:function(C,B){if(!this.initialized){this.init();}if(!this.ids[B]){this.ids[B]={};}this.ids[B][C.id]=C;},removeDDFromGroup:function(D,B){if(!this.ids[B]){this.ids[B]={};}var C=this.ids[B];if(C&&C[D.id]){delete C[D.id];}},_remove:function(C){for(var B in C.groups){if(B&&this.ids[B][C.id]){delete this.ids[B][C.id];}}delete this.handleIds[C.id];},regHandle:function(C,B){if(!this.handleIds[C]){this.handleIds[C]={};}this.handleIds[C][B]=B;},isDragDrop:function(B){return(this.getDDById(B))?true:false;},getRelated:function(G,C){var F=[];for(var E in G.groups){for(var D in this.ids[E]){var B=this.ids[E][D];if(!this.isTypeOfDD(B)){continue;}if(!C||B.isTarget){F[F.length]=B;}}}return F;},isLegalTarget:function(F,E){var C=this.getRelated(F,true);for(var D=0,B=C.length;D<B;++D){if(C[D].id==E.id){return true;}}return false;},isTypeOfDD:function(B){return(B&&B.__ygDragDrop);},isHandle:function(C,B){return(this.handleIds[C]&&this.handleIds[C][B]);},getDDById:function(C){for(var B in this.ids){if(this.ids[B][C]){return this.ids[B][C];}}return null;},handleMouseDown:function(D,C){this.currentTarget=YAHOO.util.Event.getTarget(D);this.dragCurrent=C;var B=C.getEl();this.startX=YAHOO.util.Event.getPageX(D);this.startY=YAHOO.util.Event.getPageY(D);this.deltaX=this.startX-B.offsetLeft;this.deltaY=this.startY-B.offsetTop;this.dragThreshMet=false;this.clickTimeout=setTimeout(function(){var E=YAHOO.util.DDM;E.startDrag(E.startX,E.startY);E.fromTimeout=true;},this.clickTimeThresh);},startDrag:function(B,D){clearTimeout(this.clickTimeout);var C=this.dragCurrent;if(C&&C.events.b4StartDrag){C.b4StartDrag(B,D);C.fireEvent("b4StartDragEvent",{x:B,y:D});}if(C&&C.events.startDrag){C.startDrag(B,D);C.fireEvent("startDragEvent",{x:B,y:D});}this.dragThreshMet=true;},handleMouseUp:function(B){if(this.dragCurrent){clearTimeout(this.clickTimeout);if(this.dragThreshMet){if(this.fromTimeout){this.fromTimeout=false;this.handleMouseMove(B);}this.fromTimeout=false;this.fireEvents(B,true);}else{}this.stopDrag(B);this.stopEvent(B);}},stopEvent:function(B){if(this.stopPropagation){YAHOO.util.Event.stopPropagation(B);}if(this.preventDefault){YAHOO.util.Event.preventDefault(B);}},stopDrag:function(D,C){var B=this.dragCurrent;if(B&&!C){if(this.dragThreshMet){if(B.events.b4EndDrag){B.b4EndDrag(D);B.fireEvent("b4EndDragEvent",{e:D});}if(B.events.endDrag){B.endDrag(D);B.fireEvent("endDragEvent",{e:D});}}if(B.events.mouseUp){B.onMouseUp(D);B.fireEvent("mouseUpEvent",{e:D});}}this.dragCurrent=null;this.dragOvers={};},handleMouseMove:function(E){var B=this.dragCurrent;if(B){if(YAHOO.util.Event.isIE&&!E.button){this.stopEvent(E);return this.handleMouseUp(E);}else{if(E.clientX<0||E.clientY<0){}}if(!this.dragThreshMet){var D=Math.abs(this.startX-YAHOO.util.Event.getPageX(E));var C=Math.abs(this.startY-YAHOO.util.Event.getPageY(E));if(D>this.clickPixelThresh||C>this.clickPixelThresh){this.startDrag(this.startX,this.startY);}}if(this.dragThreshMet){if(B&&B.events.b4Drag){B.b4Drag(E);B.fireEvent("b4DragEvent",{e:E});}if(B&&B.events.drag){B.onDrag(E);B.fireEvent("dragEvent",{e:E});}if(B){this.fireEvents(E,false);}}this.stopEvent(E);}},fireEvents:function(U,K){var Z=this.dragCurrent;if(!Z||Z.isLocked()||Z.dragOnly){return ;}var M=YAHOO.util.Event.getPageX(U),L=YAHOO.util.Event.getPageY(U),O=new YAHOO.util.Point(M,L),J=Z.getTargetCoord(O.x,O.y),E=Z.getDragEl(),D=["out","over","drop","enter"],T=new YAHOO.util.Region(J.y,J.x+E.offsetWidth,J.y+E.offsetHeight,J.x),H=[],C={},P=[],a={outEvts:[],overEvts:[],dropEvts:[],enterEvts:[]};for(var R in this.dragOvers){var c=this.dragOvers[R];if(!this.isTypeOfDD(c)){continue;}if(!this.isOverTarget(O,c,this.mode,T)){a.outEvts.push(c);}H[R]=true;delete this.dragOvers[R];}for(var Q in Z.groups){if("string"!=typeof Q){continue;}for(R in this.ids[Q]){var F=this.ids[Q][R];if(!this.isTypeOfDD(F)){continue;}if(F.isTarget&&!F.isLocked()&&F!=Z){if(this.isOverTarget(O,F,this.mode,T)){C[Q]=true;if(K){a.dropEvts.push(F);}else{if(!H[F.id]){a.enterEvts.push(F);}else{a.overEvts.push(F);}this.dragOvers[F.id]=F;}}}}}this.interactionInfo={out:a.outEvts,enter:a.enterEvts,over:a.overEvts,drop:a.dropEvts,point:O,draggedRegion:T,sourceRegion:this.locationCache[Z.id],validDrop:K};for(var B in C){P.push(B);}if(K&&!a.dropEvts.length){this.interactionInfo.validDrop=false;if(Z.events.invalidDrop){Z.onInvalidDrop(U);Z.fireEvent("invalidDropEvent",{e:U});}}for(R=0;R<D.length;R++){var X=null;if(a[D[R]+"Evts"]){X=a[D[R]+"Evts"];}if(X&&X.length){var G=D[R].charAt(0).toUpperCase()+D[R].substr(1),W="onDrag"+G,I="b4Drag"+G,N="drag"+G+"Event",V="drag"+G;if(this.mode){if(Z.events[I]){Z[I](U,X,P);Z.fireEvent(I+"Event",{event:U,info:X,group:P});}if(Z.events[V]){Z[W](U,X,P);Z.fireEvent(N,{event:U,info:X,group:P});}}else{for(var Y=0,S=X.length;Y<S;++Y){if(Z.events[I]){Z[I](U,X[Y].id,P[0]);Z.fireEvent(I+"Event",{event:U,info:X[Y].id,group:P[0]});}if(Z.events[V]){Z[W](U,X[Y].id,P[0]);Z.fireEvent(N,{event:U,info:X[Y].id,group:P[0]});
}}}}}},getBestMatch:function(D){var F=null;var C=D.length;if(C==1){F=D[0];}else{for(var E=0;E<C;++E){var B=D[E];if(this.mode==this.INTERSECT&&B.cursorIsOver){F=B;break;}else{if(!F||!F.overlap||(B.overlap&&F.overlap.getArea()<B.overlap.getArea())){F=B;}}}}return F;},refreshCache:function(C){var E=C||this.ids;for(var B in E){if("string"!=typeof B){continue;}for(var D in this.ids[B]){var F=this.ids[B][D];if(this.isTypeOfDD(F)){var G=this.getLocation(F);if(G){this.locationCache[F.id]=G;}else{delete this.locationCache[F.id];}}}}},verifyEl:function(C){try{if(C){var B=C.offsetParent;if(B){return true;}}}catch(D){}return false;},getLocation:function(G){if(!this.isTypeOfDD(G)){return null;}var E=G.getEl(),J,D,C,L,K,M,B,I,F;try{J=YAHOO.util.Dom.getXY(E);}catch(H){}if(!J){return null;}D=J[0];C=D+E.offsetWidth;L=J[1];K=L+E.offsetHeight;M=L-G.padding[0];B=C+G.padding[1];I=K+G.padding[2];F=D-G.padding[3];return new YAHOO.util.Region(M,B,I,F);},isOverTarget:function(J,B,D,E){var F=this.locationCache[B.id];if(!F||!this.useCache){F=this.getLocation(B);this.locationCache[B.id]=F;}if(!F){return false;}B.cursorIsOver=F.contains(J);var I=this.dragCurrent;if(!I||(!D&&!I.constrainX&&!I.constrainY)){return B.cursorIsOver;}B.overlap=null;if(!E){var G=I.getTargetCoord(J.x,J.y);var C=I.getDragEl();E=new YAHOO.util.Region(G.y,G.x+C.offsetWidth,G.y+C.offsetHeight,G.x);}var H=E.intersect(F);if(H){B.overlap=H;return(D)?true:B.cursorIsOver;}else{return false;}},_onUnload:function(C,B){this.unregAll();},unregAll:function(){if(this.dragCurrent){this.stopDrag();this.dragCurrent=null;}this._execOnAll("unreg",[]);this.ids={};},elementCache:{},getElWrapper:function(C){var B=this.elementCache[C];if(!B||!B.el){B=this.elementCache[C]=new this.ElementWrapper(YAHOO.util.Dom.get(C));}return B;},getElement:function(B){return YAHOO.util.Dom.get(B);},getCss:function(C){var B=YAHOO.util.Dom.get(C);return(B)?B.style:null;},ElementWrapper:function(B){this.el=B||null;this.id=this.el&&B.id;this.css=this.el&&B.style;},getPosX:function(B){return YAHOO.util.Dom.getX(B);},getPosY:function(B){return YAHOO.util.Dom.getY(B);},swapNode:function(D,B){if(D.swapNode){D.swapNode(B);}else{var E=B.parentNode;var C=B.nextSibling;if(C==D){E.insertBefore(D,B);}else{if(B==D.nextSibling){E.insertBefore(B,D);}else{D.parentNode.replaceChild(B,D);E.insertBefore(D,C);}}}},getScroll:function(){var D,B,E=document.documentElement,C=document.body;if(E&&(E.scrollTop||E.scrollLeft)){D=E.scrollTop;B=E.scrollLeft;}else{if(C){D=C.scrollTop;B=C.scrollLeft;}else{}}return{top:D,left:B};},getStyle:function(C,B){return YAHOO.util.Dom.getStyle(C,B);},getScrollTop:function(){return this.getScroll().top;},getScrollLeft:function(){return this.getScroll().left;},moveToEl:function(B,D){var C=YAHOO.util.Dom.getXY(D);YAHOO.util.Dom.setXY(B,C);},getClientHeight:function(){return YAHOO.util.Dom.getViewportHeight();},getClientWidth:function(){return YAHOO.util.Dom.getViewportWidth();},numericSort:function(C,B){return(C-B);},_timeoutCount:0,_addListeners:function(){var B=YAHOO.util.DDM;if(YAHOO.util.Event&&document){B._onLoad();}else{if(B._timeoutCount>2000){}else{setTimeout(B._addListeners,10);if(document&&document.body){B._timeoutCount+=1;}}}},handleWasClicked:function(B,D){if(this.isHandle(D,B.id)){return true;}else{var C=B.parentNode;while(C){if(this.isHandle(D,C.id)){return true;}else{C=C.parentNode;}}}return false;}};}();YAHOO.util.DDM=YAHOO.util.DragDropMgr;YAHOO.util.DDM._addListeners();}(function(){var A=YAHOO.util.Event;var B=YAHOO.util.Dom;YAHOO.util.DragDrop=function(E,C,D){if(E){this.init(E,C,D);}};YAHOO.util.DragDrop.prototype={events:null,on:function(){this.subscribe.apply(this,arguments);},id:null,config:null,dragElId:null,handleElId:null,invalidHandleTypes:null,invalidHandleIds:null,invalidHandleClasses:null,startPageX:0,startPageY:0,groups:null,locked:false,lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isTarget:true,padding:null,dragOnly:false,_domRef:null,__ygDragDrop:true,constrainX:false,constrainY:false,minX:0,maxX:0,minY:0,maxY:0,deltaX:0,deltaY:0,maintainOffset:false,xTicks:null,yTicks:null,primaryButtonOnly:true,available:false,hasOuterHandles:false,cursorIsOver:false,overlap:null,b4StartDrag:function(C,D){},startDrag:function(C,D){},b4Drag:function(C){},onDrag:function(C){},onDragEnter:function(C,D){},b4DragOver:function(C){},onDragOver:function(C,D){},b4DragOut:function(C){},onDragOut:function(C,D){},b4DragDrop:function(C){},onDragDrop:function(C,D){},onInvalidDrop:function(C){},b4EndDrag:function(C){},endDrag:function(C){},b4MouseDown:function(C){},onMouseDown:function(C){},onMouseUp:function(C){},onAvailable:function(){},getEl:function(){if(!this._domRef){this._domRef=B.get(this.id);}return this._domRef;},getDragEl:function(){return B.get(this.dragElId);},init:function(F,C,D){this.initTarget(F,C,D);A.on(this._domRef||this.id,"mousedown",this.handleMouseDown,this,true);for(var E in this.events){this.createEvent(E+"Event");}},initTarget:function(E,C,D){this.config=D||{};this.events={};this.DDM=YAHOO.util.DDM;this.groups={};if(typeof E!=="string"){this._domRef=E;E=B.generateId(E);}this.id=E;this.addToGroup((C)?C:"default");this.handleElId=E;A.onAvailable(E,this.handleOnAvailable,this,true);this.setDragElId(E);this.invalidHandleTypes={A:"A"};this.invalidHandleIds={};this.invalidHandleClasses=[];this.applyConfig();},applyConfig:function(){this.events={mouseDown:true,b4MouseDown:true,mouseUp:true,b4StartDrag:true,startDrag:true,b4EndDrag:true,endDrag:true,drag:true,b4Drag:true,invalidDrop:true,b4DragOut:true,dragOut:true,dragEnter:true,b4DragOver:true,dragOver:true,b4DragDrop:true,dragDrop:true};if(this.config.events){for(var C in this.config.events){if(this.config.events[C]===false){this.events[C]=false;}}}this.padding=this.config.padding||[0,0,0,0];this.isTarget=(this.config.isTarget!==false);this.maintainOffset=(this.config.maintainOffset);this.primaryButtonOnly=(this.config.primaryButtonOnly!==false);this.dragOnly=((this.config.dragOnly===true)?true:false);
},handleOnAvailable:function(){this.available=true;this.resetConstraints();this.onAvailable();},setPadding:function(E,C,F,D){if(!C&&0!==C){this.padding=[E,E,E,E];}else{if(!F&&0!==F){this.padding=[E,C,E,C];}else{this.padding=[E,C,F,D];}}},setInitPosition:function(F,E){var G=this.getEl();if(!this.DDM.verifyEl(G)){if(G&&G.style&&(G.style.display=="none")){}else{}return ;}var D=F||0;var C=E||0;var H=B.getXY(G);this.initPageX=H[0]-D;this.initPageY=H[1]-C;this.lastPageX=H[0];this.lastPageY=H[1];this.setStartPosition(H);},setStartPosition:function(D){var C=D||B.getXY(this.getEl());this.deltaSetXY=null;this.startPageX=C[0];this.startPageY=C[1];},addToGroup:function(C){this.groups[C]=true;this.DDM.regDragDrop(this,C);},removeFromGroup:function(C){if(this.groups[C]){delete this.groups[C];}this.DDM.removeDDFromGroup(this,C);},setDragElId:function(C){this.dragElId=C;},setHandleElId:function(C){if(typeof C!=="string"){C=B.generateId(C);}this.handleElId=C;this.DDM.regHandle(this.id,C);},setOuterHandleElId:function(C){if(typeof C!=="string"){C=B.generateId(C);}A.on(C,"mousedown",this.handleMouseDown,this,true);this.setHandleElId(C);this.hasOuterHandles=true;},unreg:function(){A.removeListener(this.id,"mousedown",this.handleMouseDown);this._domRef=null;this.DDM._remove(this);},isLocked:function(){return(this.DDM.isLocked()||this.locked);},handleMouseDown:function(H,G){var D=H.which||H.button;if(this.primaryButtonOnly&&D>1){return ;}if(this.isLocked()){return ;}var C=this.b4MouseDown(H);if(this.events.b4MouseDown){C=this.fireEvent("b4MouseDownEvent",H);}var E=this.onMouseDown(H);if(this.events.mouseDown){E=this.fireEvent("mouseDownEvent",H);}if((C===false)||(E===false)){return ;}this.DDM.refreshCache(this.groups);var F=new YAHOO.util.Point(A.getPageX(H),A.getPageY(H));if(!this.hasOuterHandles&&!this.DDM.isOverTarget(F,this)){}else{if(this.clickValidator(H)){this.setStartPosition();this.DDM.handleMouseDown(H,this);this.DDM.stopEvent(H);}else{}}},clickValidator:function(D){var C=YAHOO.util.Event.getTarget(D);return(this.isValidHandleChild(C)&&(this.id==this.handleElId||this.DDM.handleWasClicked(C,this.id)));},getTargetCoord:function(E,D){var C=E-this.deltaX;var F=D-this.deltaY;if(this.constrainX){if(C<this.minX){C=this.minX;}if(C>this.maxX){C=this.maxX;}}if(this.constrainY){if(F<this.minY){F=this.minY;}if(F>this.maxY){F=this.maxY;}}C=this.getTick(C,this.xTicks);F=this.getTick(F,this.yTicks);return{x:C,y:F};},addInvalidHandleType:function(C){var D=C.toUpperCase();this.invalidHandleTypes[D]=D;},addInvalidHandleId:function(C){if(typeof C!=="string"){C=B.generateId(C);}this.invalidHandleIds[C]=C;},addInvalidHandleClass:function(C){this.invalidHandleClasses.push(C);},removeInvalidHandleType:function(C){var D=C.toUpperCase();delete this.invalidHandleTypes[D];},removeInvalidHandleId:function(C){if(typeof C!=="string"){C=B.generateId(C);}delete this.invalidHandleIds[C];},removeInvalidHandleClass:function(D){for(var E=0,C=this.invalidHandleClasses.length;E<C;++E){if(this.invalidHandleClasses[E]==D){delete this.invalidHandleClasses[E];}}},isValidHandleChild:function(F){var E=true;var H;try{H=F.nodeName.toUpperCase();}catch(G){H=F.nodeName;}E=E&&!this.invalidHandleTypes[H];E=E&&!this.invalidHandleIds[F.id];for(var D=0,C=this.invalidHandleClasses.length;E&&D<C;++D){E=!B.hasClass(F,this.invalidHandleClasses[D]);}return E;},setXTicks:function(F,C){this.xTicks=[];this.xTickSize=C;var E={};for(var D=this.initPageX;D>=this.minX;D=D-C){if(!E[D]){this.xTicks[this.xTicks.length]=D;E[D]=true;}}for(D=this.initPageX;D<=this.maxX;D=D+C){if(!E[D]){this.xTicks[this.xTicks.length]=D;E[D]=true;}}this.xTicks.sort(this.DDM.numericSort);},setYTicks:function(F,C){this.yTicks=[];this.yTickSize=C;var E={};for(var D=this.initPageY;D>=this.minY;D=D-C){if(!E[D]){this.yTicks[this.yTicks.length]=D;E[D]=true;}}for(D=this.initPageY;D<=this.maxY;D=D+C){if(!E[D]){this.yTicks[this.yTicks.length]=D;E[D]=true;}}this.yTicks.sort(this.DDM.numericSort);},setXConstraint:function(E,D,C){this.leftConstraint=parseInt(E,10);this.rightConstraint=parseInt(D,10);this.minX=this.initPageX-this.leftConstraint;this.maxX=this.initPageX+this.rightConstraint;if(C){this.setXTicks(this.initPageX,C);}this.constrainX=true;},clearConstraints:function(){this.constrainX=false;this.constrainY=false;this.clearTicks();},clearTicks:function(){this.xTicks=null;this.yTicks=null;this.xTickSize=0;this.yTickSize=0;},setYConstraint:function(C,E,D){this.topConstraint=parseInt(C,10);this.bottomConstraint=parseInt(E,10);this.minY=this.initPageY-this.topConstraint;this.maxY=this.initPageY+this.bottomConstraint;if(D){this.setYTicks(this.initPageY,D);}this.constrainY=true;},resetConstraints:function(){if(this.initPageX||this.initPageX===0){var D=(this.maintainOffset)?this.lastPageX-this.initPageX:0;var C=(this.maintainOffset)?this.lastPageY-this.initPageY:0;this.setInitPosition(D,C);}else{this.setInitPosition();}if(this.constrainX){this.setXConstraint(this.leftConstraint,this.rightConstraint,this.xTickSize);}if(this.constrainY){this.setYConstraint(this.topConstraint,this.bottomConstraint,this.yTickSize);}},getTick:function(I,F){if(!F){return I;}else{if(F[0]>=I){return F[0];}else{for(var D=0,C=F.length;D<C;++D){var E=D+1;if(F[E]&&F[E]>=I){var H=I-F[D];var G=F[E]-I;return(G>H)?F[D]:F[E];}}return F[F.length-1];}}},toString:function(){return("DragDrop "+this.id);}};YAHOO.augment(YAHOO.util.DragDrop,YAHOO.util.EventProvider);})();YAHOO.util.DD=function(C,A,B){if(C){this.init(C,A,B);}};YAHOO.extend(YAHOO.util.DD,YAHOO.util.DragDrop,{scroll:true,autoOffset:function(C,B){var A=C-this.startPageX;var D=B-this.startPageY;this.setDelta(A,D);},setDelta:function(B,A){this.deltaX=B;this.deltaY=A;},setDragElPos:function(C,B){var A=this.getDragEl();this.alignElWithMouse(A,C,B);},alignElWithMouse:function(C,G,F){var E=this.getTargetCoord(G,F);if(!this.deltaSetXY){var H=[E.x,E.y];YAHOO.util.Dom.setXY(C,H);var D=parseInt(YAHOO.util.Dom.getStyle(C,"left"),10);var B=parseInt(YAHOO.util.Dom.getStyle(C,"top"),10);this.deltaSetXY=[D-E.x,B-E.y];
}else{YAHOO.util.Dom.setStyle(C,"left",(E.x+this.deltaSetXY[0])+"px");YAHOO.util.Dom.setStyle(C,"top",(E.y+this.deltaSetXY[1])+"px");}this.cachePosition(E.x,E.y);var A=this;setTimeout(function(){A.autoScroll.call(A,E.x,E.y,C.offsetHeight,C.offsetWidth);},0);},cachePosition:function(B,A){if(B){this.lastPageX=B;this.lastPageY=A;}else{var C=YAHOO.util.Dom.getXY(this.getEl());this.lastPageX=C[0];this.lastPageY=C[1];}},autoScroll:function(J,I,E,K){if(this.scroll){var L=this.DDM.getClientHeight();var B=this.DDM.getClientWidth();var N=this.DDM.getScrollTop();var D=this.DDM.getScrollLeft();var H=E+I;var M=K+J;var G=(L+N-I-this.deltaY);var F=(B+D-J-this.deltaX);var C=40;var A=(document.all)?80:30;if(H>L&&G<C){window.scrollTo(D,N+A);}if(I<N&&N>0&&I-N<C){window.scrollTo(D,N-A);}if(M>B&&F<C){window.scrollTo(D+A,N);}if(J<D&&D>0&&J-D<C){window.scrollTo(D-A,N);}}},applyConfig:function(){YAHOO.util.DD.superclass.applyConfig.call(this);this.scroll=(this.config.scroll!==false);},b4MouseDown:function(A){this.setStartPosition();this.autoOffset(YAHOO.util.Event.getPageX(A),YAHOO.util.Event.getPageY(A));},b4Drag:function(A){this.setDragElPos(YAHOO.util.Event.getPageX(A),YAHOO.util.Event.getPageY(A));},toString:function(){return("DD "+this.id);}});YAHOO.util.DDProxy=function(C,A,B){if(C){this.init(C,A,B);this.initFrame();}};YAHOO.util.DDProxy.dragElId="ygddfdiv";YAHOO.extend(YAHOO.util.DDProxy,YAHOO.util.DD,{resizeFrame:true,centerFrame:false,createFrame:function(){var B=this,A=document.body;if(!A||!A.firstChild){setTimeout(function(){B.createFrame();},50);return ;}var G=this.getDragEl(),E=YAHOO.util.Dom;if(!G){G=document.createElement("div");G.id=this.dragElId;var D=G.style;D.position="absolute";D.visibility="hidden";D.cursor="move";D.border="2px solid #aaa";D.zIndex=999;D.height="25px";D.width="25px";var C=document.createElement("div");E.setStyle(C,"height","100%");E.setStyle(C,"width","100%");E.setStyle(C,"background-color","#ccc");E.setStyle(C,"opacity","0");G.appendChild(C);if(YAHOO.env.ua.ie){var F=document.createElement("iframe");F.setAttribute("src","javascript:");F.setAttribute("scrolling","no");F.setAttribute("frameborder","0");G.insertBefore(F,G.firstChild);E.setStyle(F,"height","100%");E.setStyle(F,"width","100%");E.setStyle(F,"position","absolute");E.setStyle(F,"top","0");E.setStyle(F,"left","0");E.setStyle(F,"opacity","0");E.setStyle(F,"zIndex","-1");E.setStyle(F.nextSibling,"zIndex","2");}A.insertBefore(G,A.firstChild);}},initFrame:function(){this.createFrame();},applyConfig:function(){YAHOO.util.DDProxy.superclass.applyConfig.call(this);this.resizeFrame=(this.config.resizeFrame!==false);this.centerFrame=(this.config.centerFrame);this.setDragElId(this.config.dragElId||YAHOO.util.DDProxy.dragElId);},showFrame:function(E,D){var C=this.getEl();var A=this.getDragEl();var B=A.style;this._resizeProxy();if(this.centerFrame){this.setDelta(Math.round(parseInt(B.width,10)/2),Math.round(parseInt(B.height,10)/2));}this.setDragElPos(E,D);YAHOO.util.Dom.setStyle(A,"visibility","visible");},_resizeProxy:function(){if(this.resizeFrame){var H=YAHOO.util.Dom;var B=this.getEl();var C=this.getDragEl();var G=parseInt(H.getStyle(C,"borderTopWidth"),10);var I=parseInt(H.getStyle(C,"borderRightWidth"),10);var F=parseInt(H.getStyle(C,"borderBottomWidth"),10);var D=parseInt(H.getStyle(C,"borderLeftWidth"),10);if(isNaN(G)){G=0;}if(isNaN(I)){I=0;}if(isNaN(F)){F=0;}if(isNaN(D)){D=0;}var E=Math.max(0,B.offsetWidth-I-D);var A=Math.max(0,B.offsetHeight-G-F);H.setStyle(C,"width",E+"px");H.setStyle(C,"height",A+"px");}},b4MouseDown:function(B){this.setStartPosition();var A=YAHOO.util.Event.getPageX(B);var C=YAHOO.util.Event.getPageY(B);this.autoOffset(A,C);},b4StartDrag:function(A,B){this.showFrame(A,B);},b4EndDrag:function(A){YAHOO.util.Dom.setStyle(this.getDragEl(),"visibility","hidden");},endDrag:function(D){var C=YAHOO.util.Dom;var B=this.getEl();var A=this.getDragEl();C.setStyle(A,"visibility","");C.setStyle(B,"visibility","hidden");YAHOO.util.DDM.moveToEl(B,A);C.setStyle(A,"visibility","hidden");C.setStyle(B,"visibility","");},toString:function(){return("DDProxy "+this.id);}});YAHOO.util.DDTarget=function(C,A,B){if(C){this.initTarget(C,A,B);}};YAHOO.extend(YAHOO.util.DDTarget,YAHOO.util.DragDrop,{toString:function(){return("DDTarget "+this.id);}});YAHOO.register("dragdrop",YAHOO.util.DragDropMgr,{version:"2.5.2",build:"1076"});YAHOO.util.Attribute=function(B,A){if(A){this.owner=A;this.configure(B,true);}};YAHOO.util.Attribute.prototype={name:undefined,value:null,owner:null,readOnly:false,writeOnce:false,_initialConfig:null,_written:false,method:null,validator:null,getValue:function(){return this.value;},setValue:function(F,B){var E;var A=this.owner;var C=this.name;var D={type:C,prevValue:this.getValue(),newValue:F};if(this.readOnly||(this.writeOnce&&this._written)){return false;}if(this.validator&&!this.validator.call(A,F)){return false;}if(!B){E=A.fireBeforeChangeEvent(D);if(E===false){return false;}}if(this.method){this.method.call(A,F);}this.value=F;this._written=true;D.type=C;if(!B){this.owner.fireChangeEvent(D);}return true;},configure:function(B,C){B=B||{};this._written=false;this._initialConfig=this._initialConfig||{};for(var A in B){if(A&&YAHOO.lang.hasOwnProperty(B,A)){this[A]=B[A];if(C){this._initialConfig[A]=B[A];}}}},resetValue:function(){return this.setValue(this._initialConfig.value);},resetConfig:function(){this.configure(this._initialConfig);},refresh:function(A){this.setValue(this.value,A);}};(function(){var A=YAHOO.util.Lang;YAHOO.util.AttributeProvider=function(){};YAHOO.util.AttributeProvider.prototype={_configs:null,get:function(C){this._configs=this._configs||{};var B=this._configs[C];if(!B){return undefined;}return B.value;},set:function(D,E,B){this._configs=this._configs||{};var C=this._configs[D];if(!C){return false;}return C.setValue(E,B);},getAttributeKeys:function(){this._configs=this._configs;var D=[];var B;for(var C in this._configs){B=this._configs[C];if(A.hasOwnProperty(this._configs,C)&&!A.isUndefined(B)){D[D.length]=C;}}return D;},setAttributes:function(D,B){for(var C in D){if(A.hasOwnProperty(D,C)){this.set(C,D[C],B);}}},resetValue:function(C,B){this._configs=this._configs||{};if(this._configs[C]){this.set(C,this._configs[C]._initialConfig.value,B);return true;}return false;},refresh:function(E,C){this._configs=this._configs;E=((A.isString(E))?[E]:E)||this.getAttributeKeys();for(var D=0,B=E.length;D<B;++D){if(this._configs[E[D]]&&!A.isUndefined(this._configs[E[D]].value)&&!A.isNull(this._configs[E[D]].value)){this._configs[E[D]].refresh(C);}}},register:function(B,C){this.setAttributeConfig(B,C);},getAttributeConfig:function(C){this._configs=this._configs||{};var B=this._configs[C]||{};var D={};for(C in B){if(A.hasOwnProperty(B,C)){D[C]=B[C];}}return D;},setAttributeConfig:function(B,C,D){this._configs=this._configs||{};C=C||{};if(!this._configs[B]){C.name=B;this._configs[B]=this.createAttribute(C);}else{this._configs[B].configure(C,D);}},configureAttribute:function(B,C,D){this.setAttributeConfig(B,C,D);},resetAttributeConfig:function(B){this._configs=this._configs||{};this._configs[B].resetConfig();},subscribe:function(B,C){this._events=this._events||{};if(!(B in this._events)){this._events[B]=this.createEvent(B);}YAHOO.util.EventProvider.prototype.subscribe.apply(this,arguments);},on:function(){this.subscribe.apply(this,arguments);},addListener:function(){this.subscribe.apply(this,arguments);},fireBeforeChangeEvent:function(C){var B="before";B+=C.type.charAt(0).toUpperCase()+C.type.substr(1)+"Change";C.type=B;return this.fireEvent(C.type,C);},fireChangeEvent:function(B){B.type+="Change";return this.fireEvent(B.type,B);},createAttribute:function(B){return new YAHOO.util.Attribute(B,this);}};YAHOO.augment(YAHOO.util.AttributeProvider,YAHOO.util.EventProvider);})();(function(){var D=YAHOO.util.Dom,F=YAHOO.util.AttributeProvider;YAHOO.util.Element=function(G,H){if(arguments.length){this.init(G,H);}};YAHOO.util.Element.prototype={DOM_EVENTS:null,appendChild:function(G){G=G.get?G.get("element"):G;this.get("element").appendChild(G);},getElementsByTagName:function(G){return this.get("element").getElementsByTagName(G);},hasChildNodes:function(){return this.get("element").hasChildNodes();},insertBefore:function(G,H){G=G.get?G.get("element"):G;H=(H&&H.get)?H.get("element"):H;this.get("element").insertBefore(G,H);},removeChild:function(G){G=G.get?G.get("element"):G;this.get("element").removeChild(G);return true;},replaceChild:function(G,H){G=G.get?G.get("element"):G;H=H.get?H.get("element"):H;return this.get("element").replaceChild(G,H);},initAttributes:function(G){},addListener:function(K,J,L,I){var H=this.get("element");I=I||this;H=this.get("id")||H;var G=this;if(!this._events[K]){if(this.DOM_EVENTS[K]){YAHOO.util.Event.addListener(H,K,function(M){if(M.srcElement&&!M.target){M.target=M.srcElement;}G.fireEvent(K,M);},L,I);}this.createEvent(K,this);}YAHOO.util.EventProvider.prototype.subscribe.apply(this,arguments);},on:function(){this.addListener.apply(this,arguments);},subscribe:function(){this.addListener.apply(this,arguments);},removeListener:function(H,G){this.unsubscribe.apply(this,arguments);},addClass:function(G){D.addClass(this.get("element"),G);},getElementsByClassName:function(H,G){return D.getElementsByClassName(H,G,this.get("element"));},hasClass:function(G){return D.hasClass(this.get("element"),G);},removeClass:function(G){return D.removeClass(this.get("element"),G);},replaceClass:function(H,G){return D.replaceClass(this.get("element"),H,G);},setStyle:function(I,H){var G=this.get("element");if(!G){return this._queue[this._queue.length]=["setStyle",arguments];}return D.setStyle(G,I,H);},getStyle:function(G){return D.getStyle(this.get("element"),G);},fireQueue:function(){var H=this._queue;for(var I=0,G=H.length;I<G;++I){this[H[I][0]].apply(this,H[I][1]);}},appendTo:function(H,I){H=(H.get)?H.get("element"):D.get(H);this.fireEvent("beforeAppendTo",{type:"beforeAppendTo",target:H});I=(I&&I.get)?I.get("element"):D.get(I);var G=this.get("element");if(!G){return false;}if(!H){return false;}if(G.parent!=H){if(I){H.insertBefore(G,I);}else{H.appendChild(G);}}this.fireEvent("appendTo",{type:"appendTo",target:H});},get:function(G){var I=this._configs||{};var H=I.element;if(H&&!I[G]&&!YAHOO.lang.isUndefined(H.value[G])){return H.value[G];}return F.prototype.get.call(this,G);},setAttributes:function(L,H){var K=this.get("element");
for(var J in L){if(!this._configs[J]&&!YAHOO.lang.isUndefined(K[J])){this.setAttributeConfig(J);}}for(var I=0,G=this._configOrder.length;I<G;++I){if(L[this._configOrder[I]]!==undefined){this.set(this._configOrder[I],L[this._configOrder[I]],H);}}},set:function(H,J,G){var I=this.get("element");if(!I){this._queue[this._queue.length]=["set",arguments];if(this._configs[H]){this._configs[H].value=J;}return ;}if(!this._configs[H]&&!YAHOO.lang.isUndefined(I[H])){C.call(this,H);}return F.prototype.set.apply(this,arguments);},setAttributeConfig:function(G,I,J){var H=this.get("element");if(H&&!this._configs[G]&&!YAHOO.lang.isUndefined(H[G])){C.call(this,G,I);}else{F.prototype.setAttributeConfig.apply(this,arguments);}this._configOrder.push(G);},getAttributeKeys:function(){var H=this.get("element");var I=F.prototype.getAttributeKeys.call(this);for(var G in H){if(!this._configs[G]){I[G]=I[G]||H[G];}}return I;},createEvent:function(H,G){this._events[H]=true;F.prototype.createEvent.apply(this,arguments);},init:function(H,G){A.apply(this,arguments);}};var A=function(H,G){this._queue=this._queue||[];this._events=this._events||{};this._configs=this._configs||{};this._configOrder=[];G=G||{};G.element=G.element||H||null;this.DOM_EVENTS={"click":true,"dblclick":true,"keydown":true,"keypress":true,"keyup":true,"mousedown":true,"mousemove":true,"mouseout":true,"mouseover":true,"mouseup":true,"focus":true,"blur":true,"submit":true};var I=false;if(YAHOO.lang.isString(H)){C.call(this,"id",{value:G.element});}if(D.get(H)){I=true;E.call(this,G);B.call(this,G);}YAHOO.util.Event.onAvailable(G.element,function(){if(!I){E.call(this,G);}this.fireEvent("available",{type:"available",target:G.element});},this,true);YAHOO.util.Event.onContentReady(G.element,function(){if(!I){B.call(this,G);}this.fireEvent("contentReady",{type:"contentReady",target:G.element});},this,true);};var E=function(G){this.setAttributeConfig("element",{value:D.get(G.element),readOnly:true});};var B=function(G){this.initAttributes(G);this.setAttributes(G,true);this.fireQueue();};var C=function(G,I){var H=this.get("element");I=I||{};I.name=G;I.method=I.method||function(J){H[G]=J;};I.value=I.value||H[G];this._configs[G]=new YAHOO.util.Attribute(I,this);};YAHOO.augment(YAHOO.util.Element,F);})();YAHOO.register("element",YAHOO.util.Element,{version:"2.5.2",build:"1076"});YAHOO.register("utilities", YAHOO, {version: "2.5.2", build: "1076"});
/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.5.2
*/
(function () {

    /**
    * Config is a utility used within an Object to allow the implementer to
    * maintain a list of local configuration properties and listen for changes 
    * to those properties dynamically using CustomEvent. The initial values are 
    * also maintained so that the configuration can be reset at any given point 
    * to its initial state.
    * @namespace YAHOO.util
    * @class Config
    * @constructor
    * @param {Object} owner The owner Object to which this Config Object belongs
    */
    YAHOO.util.Config = function (owner) {

        if (owner) {
            this.init(owner);
        }


    };


    var Lang = YAHOO.lang,
        CustomEvent = YAHOO.util.CustomEvent,
        Config = YAHOO.util.Config;


    /**
     * Constant representing the CustomEvent type for the config changed event.
     * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
     * @private
     * @static
     * @final
     */
    Config.CONFIG_CHANGED_EVENT = "configChanged";
    
    /**
     * Constant representing the boolean type string
     * @property YAHOO.util.Config.BOOLEAN_TYPE
     * @private
     * @static
     * @final
     */
    Config.BOOLEAN_TYPE = "boolean";
    
    Config.prototype = {
     
        /**
        * Object reference to the owner of this Config Object
        * @property owner
        * @type Object
        */
        owner: null,
        
        /**
        * Boolean flag that specifies whether a queue is currently 
        * being executed
        * @property queueInProgress
        * @type Boolean
        */
        queueInProgress: false,
        
        /**
        * Maintains the local collection of configuration property objects and 
        * their specified values
        * @property config
        * @private
        * @type Object
        */ 
        config: null,
        
        /**
        * Maintains the local collection of configuration property objects as 
        * they were initially applied.
        * This object is used when resetting a property.
        * @property initialConfig
        * @private
        * @type Object
        */ 
        initialConfig: null,
        
        /**
        * Maintains the local, normalized CustomEvent queue
        * @property eventQueue
        * @private
        * @type Object
        */ 
        eventQueue: null,
        
        /**
        * Custom Event, notifying subscribers when Config properties are set 
        * (setProperty is called without the silent flag
        * @event configChangedEvent
        */
        configChangedEvent: null,
    
        /**
        * Initializes the configuration Object and all of its local members.
        * @method init
        * @param {Object} owner The owner Object to which this Config 
        * Object belongs
        */
        init: function (owner) {
    
            this.owner = owner;
    
            this.configChangedEvent = 
                this.createEvent(Config.CONFIG_CHANGED_EVENT);
    
            this.configChangedEvent.signature = CustomEvent.LIST;
            this.queueInProgress = false;
            this.config = {};
            this.initialConfig = {};
            this.eventQueue = [];
        
        },
        
        /**
        * Validates that the value passed in is a Boolean.
        * @method checkBoolean
        * @param {Object} val The value to validate
        * @return {Boolean} true, if the value is valid
        */ 
        checkBoolean: function (val) {
            return (typeof val == Config.BOOLEAN_TYPE);
        },
        
        /**
        * Validates that the value passed in is a number.
        * @method checkNumber
        * @param {Object} val The value to validate
        * @return {Boolean} true, if the value is valid
        */
        checkNumber: function (val) {
            return (!isNaN(val));
        },
        
        /**
        * Fires a configuration property event using the specified value. 
        * @method fireEvent
        * @private
        * @param {String} key The configuration property's name
        * @param {value} Object The value of the correct type for the property
        */ 
        fireEvent: function ( key, value ) {
            var property = this.config[key];
        
            if (property && property.event) {
                property.event.fire(value);
            } 
        },
        
        /**
        * Adds a property to the Config Object's private config hash.
        * @method addProperty
        * @param {String} key The configuration property's name
        * @param {Object} propertyObject The Object containing all of this 
        * property's arguments
        */
        addProperty: function ( key, propertyObject ) {
            key = key.toLowerCase();
        
            this.config[key] = propertyObject;
        
            propertyObject.event = this.createEvent(key, { scope: this.owner });
            propertyObject.event.signature = CustomEvent.LIST;
            
            
            propertyObject.key = key;
        
            if (propertyObject.handler) {
                propertyObject.event.subscribe(propertyObject.handler, 
                    this.owner);
            }
        
            this.setProperty(key, propertyObject.value, true);
            
            if (! propertyObject.suppressEvent) {
                this.queueProperty(key, propertyObject.value);
            }
            
        },
        
        /**
        * Returns a key-value configuration map of the values currently set in  
        * the Config Object.
        * @method getConfig
        * @return {Object} The current config, represented in a key-value map
        */
        getConfig: function () {
        
            var cfg = {},
                prop,
                property;
                
            for (prop in this.config) {
                property = this.config[prop];
                if (property && property.event) {
                    cfg[prop] = property.value;
                }
            }
            
            return cfg;
        },
        
        /**
        * Returns the value of specified property.
        * @method getProperty
        * @param {String} key The name of the property
        * @return {Object}  The value of the specified property
        */
        getProperty: function (key) {
            var property = this.config[key.toLowerCase()];
            if (property && property.event) {
                return property.value;
            } else {
                return undefined;
            }
        },
        
        /**
        * Resets the specified property's value to its initial value.
        * @method resetProperty
        * @param {String} key The name of the property
        * @return {Boolean} True is the property was reset, false if not
        */
        resetProperty: function (key) {
    
            key = key.toLowerCase();
        
            var property = this.config[key];
    
            if (property && property.event) {
    
                if (this.initialConfig[key] && 
                    !Lang.isUndefined(this.initialConfig[key])) {
    
                    this.setProperty(key, this.initialConfig[key]);

                    return true;
    
                }
    
            } else {
    
                return false;
            }
    
        },
        
        /**
        * Sets the value of a property. If the silent property is passed as 
        * true, the property's event will not be fired.
        * @method setProperty
        * @param {String} key The name of the property
        * @param {String} value The value to set the property to
        * @param {Boolean} silent Whether the value should be set silently, 
        * without firing the property event.
        * @return {Boolean} True, if the set was successful, false if it failed.
        */
        setProperty: function (key, value, silent) {
        
            var property;
        
            key = key.toLowerCase();
        
            if (this.queueInProgress && ! silent) {
                // Currently running through a queue... 
                this.queueProperty(key,value);
                return true;
    
            } else {
                property = this.config[key];
                if (property && property.event) {
                    if (property.validator && !property.validator(value)) {
                        return false;
                    } else {
                        property.value = value;
                        if (! silent) {
                            this.fireEvent(key, value);
                            this.configChangedEvent.fire([key, value]);
                        }
                        return true;
                    }
                } else {
                    return false;
                }
            }
        },
        
        /**
        * Sets the value of a property and queues its event to execute. If the 
        * event is already scheduled to execute, it is
        * moved from its current position to the end of the queue.
        * @method queueProperty
        * @param {String} key The name of the property
        * @param {String} value The value to set the property to
        * @return {Boolean}  true, if the set was successful, false if 
        * it failed.
        */ 
        queueProperty: function (key, value) {
        
            key = key.toLowerCase();
        
            var property = this.config[key],
                foundDuplicate = false,
                iLen,
                queueItem,
                queueItemKey,
                queueItemValue,
                sLen,
                supercedesCheck,
                qLen,
                queueItemCheck,
                queueItemCheckKey,
                queueItemCheckValue,
                i,
                s,
                q;
                                
            if (property && property.event) {
    
                if (!Lang.isUndefined(value) && property.validator && 
                    !property.validator(value)) { // validator
                    return false;
                } else {
        
                    if (!Lang.isUndefined(value)) {
                        property.value = value;
                    } else {
                        value = property.value;
                    }
        
                    foundDuplicate = false;
                    iLen = this.eventQueue.length;
        
                    for (i = 0; i < iLen; i++) {
                        queueItem = this.eventQueue[i];
        
                        if (queueItem) {
                            queueItemKey = queueItem[0];
                            queueItemValue = queueItem[1];

                            if (queueItemKey == key) {
    
                                /*
                                    found a dupe... push to end of queue, null 
                                    current item, and break
                                */
    
                                this.eventQueue[i] = null;
    
                                this.eventQueue.push(
                                    [key, (!Lang.isUndefined(value) ? 
                                    value : queueItemValue)]);
    
                                foundDuplicate = true;
                                break;
                            }
                        }
                    }
                    
                    // this is a refire, or a new property in the queue
    
                    if (! foundDuplicate && !Lang.isUndefined(value)) { 
                        this.eventQueue.push([key, value]);
                    }
                }
        
                if (property.supercedes) {

                    sLen = property.supercedes.length;

                    for (s = 0; s < sLen; s++) {

                        supercedesCheck = property.supercedes[s];
                        qLen = this.eventQueue.length;

                        for (q = 0; q < qLen; q++) {
                            queueItemCheck = this.eventQueue[q];

                            if (queueItemCheck) {
                                queueItemCheckKey = queueItemCheck[0];
                                queueItemCheckValue = queueItemCheck[1];

                                if (queueItemCheckKey == 
                                    supercedesCheck.toLowerCase() ) {

                                    this.eventQueue.push([queueItemCheckKey, 
                                        queueItemCheckValue]);

                                    this.eventQueue[q] = null;
                                    break;

                                }
                            }
                        }
                    }
                }


                return true;
            } else {
                return false;
            }
        },
        
        /**
        * Fires the event for a property using the property's current value.
        * @method refireEvent
        * @param {String} key The name of the property
        */
        refireEvent: function (key) {
    
            key = key.toLowerCase();
        
            var property = this.config[key];
    
            if (property && property.event && 
    
                !Lang.isUndefined(property.value)) {
    
                if (this.queueInProgress) {
    
                    this.queueProperty(key);
    
                } else {
    
                    this.fireEvent(key, property.value);
    
                }
    
            }
        },
        
        /**
        * Applies a key-value Object literal to the configuration, replacing  
        * any existing values, and queueing the property events.
        * Although the values will be set, fireQueue() must be called for their 
        * associated events to execute.
        * @method applyConfig
        * @param {Object} userConfig The configuration Object literal
        * @param {Boolean} init  When set to true, the initialConfig will 
        * be set to the userConfig passed in, so that calling a reset will 
        * reset the properties to the passed values.
        */
        applyConfig: function (userConfig, init) {
        
            var sKey,
                oConfig;

            if (init) {
                oConfig = {};
                for (sKey in userConfig) {
                    if (Lang.hasOwnProperty(userConfig, sKey)) {
                        oConfig[sKey.toLowerCase()] = userConfig[sKey];
                    }
                }
                this.initialConfig = oConfig;
            }

            for (sKey in userConfig) {
                if (Lang.hasOwnProperty(userConfig, sKey)) {
                    this.queueProperty(sKey, userConfig[sKey]);
                }
            }
        },
        
        /**
        * Refires the events for all configuration properties using their 
        * current values.
        * @method refresh
        */
        refresh: function () {
        
            var prop;
        
            for (prop in this.config) {
                this.refireEvent(prop);
            }
        },
        
        /**
        * Fires the normalized list of queued property change events
        * @method fireQueue
        */
        fireQueue: function () {
        
            var i, 
                queueItem,
                key,
                value,
                property;
        
            this.queueInProgress = true;
            for (i = 0;i < this.eventQueue.length; i++) {
                queueItem = this.eventQueue[i];
                if (queueItem) {
        
                    key = queueItem[0];
                    value = queueItem[1];
                    property = this.config[key];
        
                    property.value = value;
        
                    this.fireEvent(key,value);
                }
            }
            
            this.queueInProgress = false;
            this.eventQueue = [];
        },
        
        /**
        * Subscribes an external handler to the change event for any 
        * given property. 
        * @method subscribeToConfigEvent
        * @param {String} key The property name
        * @param {Function} handler The handler function to use subscribe to 
        * the property's event
        * @param {Object} obj The Object to use for scoping the event handler 
        * (see CustomEvent documentation)
        * @param {Boolean} override Optional. If true, will override "this"  
        * within the handler to map to the scope Object passed into the method.
        * @return {Boolean} True, if the subscription was successful, 
        * otherwise false.
        */ 
        subscribeToConfigEvent: function (key, handler, obj, override) {
    
            var property = this.config[key.toLowerCase()];
    
            if (property && property.event) {
                if (!Config.alreadySubscribed(property.event, handler, obj)) {
                    property.event.subscribe(handler, obj, override);
                }
                return true;
            } else {
                return false;
            }
    
        },
        
        /**
        * Unsubscribes an external handler from the change event for any 
        * given property. 
        * @method unsubscribeFromConfigEvent
        * @param {String} key The property name
        * @param {Function} handler The handler function to use subscribe to 
        * the property's event
        * @param {Object} obj The Object to use for scoping the event 
        * handler (see CustomEvent documentation)
        * @return {Boolean} True, if the unsubscription was successful, 
        * otherwise false.
        */
        unsubscribeFromConfigEvent: function (key, handler, obj) {
            var property = this.config[key.toLowerCase()];
            if (property && property.event) {
                return property.event.unsubscribe(handler, obj);
            } else {
                return false;
            }
        },
        
        /**
        * Returns a string representation of the Config object
        * @method toString
        * @return {String} The Config object in string format.
        */
        toString: function () {
            var output = "Config";
            if (this.owner) {
                output += " [" + this.owner.toString() + "]";
            }
            return output;
        },
        
        /**
        * Returns a string representation of the Config object's current 
        * CustomEvent queue
        * @method outputEventQueue
        * @return {String} The string list of CustomEvents currently queued 
        * for execution
        */
        outputEventQueue: function () {

            var output = "",
                queueItem,
                q,
                nQueue = this.eventQueue.length;
              
            for (q = 0; q < nQueue; q++) {
                queueItem = this.eventQueue[q];
                if (queueItem) {
                    output += queueItem[0] + "=" + queueItem[1] + ", ";
                }
            }
            return output;
        },

        /**
        * Sets all properties to null, unsubscribes all listeners from each 
        * property's change event and all listeners from the configChangedEvent.
        * @method destroy
        */
        destroy: function () {

            var oConfig = this.config,
                sProperty,
                oProperty;


            for (sProperty in oConfig) {
            
                if (Lang.hasOwnProperty(oConfig, sProperty)) {

                    oProperty = oConfig[sProperty];

                    oProperty.event.unsubscribeAll();
                    oProperty.event = null;

                }
            
            }
            
            this.configChangedEvent.unsubscribeAll();
            
            this.configChangedEvent = null;
            this.owner = null;
            this.config = null;
            this.initialConfig = null;
            this.eventQueue = null;
        
        }

    };
    
    
    
    /**
    * Checks to determine if a particular function/Object pair are already 
    * subscribed to the specified CustomEvent
    * @method YAHOO.util.Config.alreadySubscribed
    * @static
    * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check 
    * the subscriptions
    * @param {Function} fn The function to look for in the subscribers list
    * @param {Object} obj The execution scope Object for the subscription
    * @return {Boolean} true, if the function/Object pair is already subscribed 
    * to the CustomEvent passed in
    */
    Config.alreadySubscribed = function (evt, fn, obj) {
    
        var nSubscribers = evt.subscribers.length,
            subsc,
            i;

        if (nSubscribers > 0) {
            i = nSubscribers - 1;
            do {
                subsc = evt.subscribers[i];
                if (subsc && subsc.obj == obj && subsc.fn == fn) {
                    return true;
                }
            }
            while (i--);
        }

        return false;

    };

    YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);

}());

(function () {

    /**
    * The Container family of components is designed to enable developers to 
    * create different kinds of content-containing modules on the web. Module 
    * and Overlay are the most basic containers, and they can be used directly 
    * or extended to build custom containers. Also part of the Container family 
    * are four UI controls that extend Module and Overlay: Tooltip, Panel, 
    * Dialog, and SimpleDialog.
    * @module container
    * @title Container
    * @requires yahoo, dom, event 
    * @optional dragdrop, animation, button
    */
    
    /**
    * Module is a JavaScript representation of the Standard Module Format. 
    * Standard Module Format is a simple standard for markup containers where 
    * child nodes representing the header, body, and footer of the content are 
    * denoted using the CSS classes "hd", "bd", and "ft" respectively. 
    * Module is the base class for all other classes in the YUI 
    * Container package.
    * @namespace YAHOO.widget
    * @class Module
    * @constructor
    * @param {String} el The element ID representing the Module <em>OR</em>
    * @param {HTMLElement} el The element representing the Module
    * @param {Object} userConfig The configuration Object literal containing 
    * the configuration that should be set for this module. See configuration 
    * documentation for more details.
    */
    YAHOO.widget.Module = function (el, userConfig) {
        if (el) {
            this.init(el, userConfig);
        } else {
        }
    };

    var Dom = YAHOO.util.Dom,
        Config = YAHOO.util.Config,
        Event = YAHOO.util.Event,
        CustomEvent = YAHOO.util.CustomEvent,
        Module = YAHOO.widget.Module,

        m_oModuleTemplate,
        m_oHeaderTemplate,
        m_oBodyTemplate,
        m_oFooterTemplate,

        /**
        * Constant representing the name of the Module's events
        * @property EVENT_TYPES
        * @private
        * @final
        * @type Object
        */
        EVENT_TYPES = {
            "BEFORE_INIT": "beforeInit",
            "INIT": "init",
            "APPEND": "append",
            "BEFORE_RENDER": "beforeRender",
            "RENDER": "render",
            "CHANGE_HEADER": "changeHeader",
            "CHANGE_BODY": "changeBody",
            "CHANGE_FOOTER": "changeFooter",
            "CHANGE_CONTENT": "changeContent",
            "DESTORY": "destroy",
            "BEFORE_SHOW": "beforeShow",
            "SHOW": "show",
            "BEFORE_HIDE": "beforeHide",
            "HIDE": "hide"
        },
            
        /**
        * Constant representing the Module's configuration properties
        * @property DEFAULT_CONFIG
        * @private
        * @final
        * @type Object
        */
        DEFAULT_CONFIG = {
        
            "VISIBLE": { 
                key: "visible", 
                value: true, 
                validator: YAHOO.lang.isBoolean 
            },
        
            "EFFECT": { 
                key: "effect", 
                suppressEvent: true, 
                supercedes: ["visible"] 
            },

            "MONITOR_RESIZE": { 
                key: "monitorresize", 
                value: true  
            },

            "APPEND_TO_DOCUMENT_BODY": { 
                key: "appendtodocumentbody", 
                value: false
            }
        };
    
    /**
    * Constant representing the prefix path to use for non-secure images
    * @property YAHOO.widget.Module.IMG_ROOT
    * @static
    * @final
    * @type String
    */
    Module.IMG_ROOT = null;
    
    /**
    * Constant representing the prefix path to use for securely served images
    * @property YAHOO.widget.Module.IMG_ROOT_SSL
    * @static
    * @final
    * @type String
    */
    Module.IMG_ROOT_SSL = null;
    
    /**
    * Constant for the default CSS class name that represents a Module
    * @property YAHOO.widget.Module.CSS_MODULE
    * @static
    * @final
    * @type String
    */
    Module.CSS_MODULE = "yui-module";
    
    /**
    * Constant representing the module header
    * @property YAHOO.widget.Module.CSS_HEADER
    * @static
    * @final
    * @type String
    */
    Module.CSS_HEADER = "hd";

    /**
    * Constant representing the module body
    * @property YAHOO.widget.Module.CSS_BODY
    * @static
    * @final
    * @type String
    */
    Module.CSS_BODY = "bd";
    
    /**
    * Constant representing the module footer
    * @property YAHOO.widget.Module.CSS_FOOTER
    * @static
    * @final
    * @type String
    */
    Module.CSS_FOOTER = "ft";
    
    /**
    * Constant representing the url for the "src" attribute of the iframe 
    * used to monitor changes to the browser's base font size
    * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
    * @static
    * @final
    * @type String
    */
    Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
    
    /**
    * Singleton CustomEvent fired when the font size is changed in the browser.
    * Opera's "zoom" functionality currently does not support text 
    * size detection.
    * @event YAHOO.widget.Module.textResizeEvent
    */
    Module.textResizeEvent = new CustomEvent("textResize");

    function createModuleTemplate() {

        if (!m_oModuleTemplate) {
            m_oModuleTemplate = document.createElement("div");
            
            m_oModuleTemplate.innerHTML = ("<div class=\"" + 
                Module.CSS_HEADER + "\"></div>" + "<div class=\"" + 
                Module.CSS_BODY + "\"></div><div class=\"" + 
                Module.CSS_FOOTER + "\"></div>");

            m_oHeaderTemplate = m_oModuleTemplate.firstChild;
            m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
            m_oFooterTemplate = m_oBodyTemplate.nextSibling;
        }

        return m_oModuleTemplate;
    }

    function createHeader() {
        if (!m_oHeaderTemplate) {
            createModuleTemplate();
        }
        return (m_oHeaderTemplate.cloneNode(false));
    }

    function createBody() {
        if (!m_oBodyTemplate) {
            createModuleTemplate();
        }
        return (m_oBodyTemplate.cloneNode(false));
    }

    function createFooter() {
        if (!m_oFooterTemplate) {
            createModuleTemplate();
        }
        return (m_oFooterTemplate.cloneNode(false));
    }

    Module.prototype = {

        /**
        * The class's constructor function
        * @property contructor
        * @type Function
        */
        constructor: Module,
        
        /**
        * The main module element that contains the header, body, and footer
        * @property element
        * @type HTMLElement
        */
        element: null,

        /**
        * The header element, denoted with CSS class "hd"
        * @property header
        * @type HTMLElement
        */
        header: null,

        /**
        * The body element, denoted with CSS class "bd"
        * @property body
        * @type HTMLElement
        */
        body: null,

        /**
        * The footer element, denoted with CSS class "ft"
        * @property footer
        * @type HTMLElement
        */
        footer: null,

        /**
        * The id of the element
        * @property id
        * @type String
        */
        id: null,

        /**
        * A string representing the root path for all images created by
        * a Module instance.
        * @deprecated It is recommend that any images for a Module be applied
        * via CSS using the "background-image" property.
        * @property imageRoot
        * @type String
        */
        imageRoot: Module.IMG_ROOT,

        /**
        * Initializes the custom events for Module which are fired 
        * automatically at appropriate times by the Module class.
        * @method initEvents
        */
        initEvents: function () {

            var SIGNATURE = CustomEvent.LIST;

            /**
            * CustomEvent fired prior to class initalization.
            * @event beforeInitEvent
            * @param {class} classRef class reference of the initializing 
            * class, such as this.beforeInitEvent.fire(Module)
            */
            this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
            this.beforeInitEvent.signature = SIGNATURE;

            /**
            * CustomEvent fired after class initalization.
            * @event initEvent
            * @param {class} classRef class reference of the initializing 
            * class, such as this.beforeInitEvent.fire(Module)
            */  
            this.initEvent = this.createEvent(EVENT_TYPES.INIT);
            this.initEvent.signature = SIGNATURE;

            /**
            * CustomEvent fired when the Module is appended to the DOM
            * @event appendEvent
            */
            this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
            this.appendEvent.signature = SIGNATURE;

            /**
            * CustomEvent fired before the Module is rendered
            * @event beforeRenderEvent
            */
            this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
            this.beforeRenderEvent.signature = SIGNATURE;
        
            /**
            * CustomEvent fired after the Module is rendered
            * @event renderEvent
            */
            this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
            this.renderEvent.signature = SIGNATURE;
        
            /**
            * CustomEvent fired when the header content of the Module 
            * is modified
            * @event changeHeaderEvent
            * @param {String/HTMLElement} content String/element representing 
            * the new header content
            */
            this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
            this.changeHeaderEvent.signature = SIGNATURE;
            
            /**
            * CustomEvent fired when the body content of the Module is modified
            * @event changeBodyEvent
            * @param {String/HTMLElement} content String/element representing 
            * the new body content
            */  
            this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
            this.changeBodyEvent.signature = SIGNATURE;
            
            /**
            * CustomEvent fired when the footer content of the Module 
            * is modified
            * @event changeFooterEvent
            * @param {String/HTMLElement} content String/element representing 
            * the new footer content
            */
            this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
            this.changeFooterEvent.signature = SIGNATURE;
        
            /**
            * CustomEvent fired when the content of the Module is modified
            * @event changeContentEvent
            */
            this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
            this.changeContentEvent.signature = SIGNATURE;

            /**
            * CustomEvent fired when the Module is destroyed
            * @event destroyEvent
            */
            this.destroyEvent = this.createEvent(EVENT_TYPES.DESTORY);
            this.destroyEvent.signature = SIGNATURE;

            /**
            * CustomEvent fired before the Module is shown
            * @event beforeShowEvent
            */
            this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
            this.beforeShowEvent.signature = SIGNATURE;

            /**
            * CustomEvent fired after the Module is shown
            * @event showEvent
            */
            this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
            this.showEvent.signature = SIGNATURE;

            /**
            * CustomEvent fired before the Module is hidden
            * @event beforeHideEvent
            */
            this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
            this.beforeHideEvent.signature = SIGNATURE;

            /**
            * CustomEvent fired after the Module is hidden
            * @event hideEvent
            */
            this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
            this.hideEvent.signature = SIGNATURE;
        }, 

        /**
        * String representing the current user-agent platform
        * @property platform
        * @type String
        */
        platform: function () {
            var ua = navigator.userAgent.toLowerCase();

            if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
                return "windows";
            } else if (ua.indexOf("macintosh") != -1) {
                return "mac";
            } else {
                return false;
            }
        }(),
        
        /**
        * String representing the user-agent of the browser
        * @deprecated Use YAHOO.env.ua
        * @property browser
        * @type String
        */
        browser: function () {
            var ua = navigator.userAgent.toLowerCase();
            /*
                 Check Opera first in case of spoof and check Safari before
                 Gecko since Safari's user agent string includes "like Gecko"
            */
            if (ua.indexOf('opera') != -1) { 
                return 'opera';
            } else if (ua.indexOf('msie 7') != -1) {
                return 'ie7';
            } else if (ua.indexOf('msie') != -1) {
                return 'ie';
            } else if (ua.indexOf('safari') != -1) { 
                return 'safari';
            } else if (ua.indexOf('gecko') != -1) {
                return 'gecko';
            } else {
                return false;
            }
        }(),
        
        /**
        * Boolean representing whether or not the current browsing context is 
        * secure (https)
        * @property isSecure
        * @type Boolean
        */
        isSecure: function () {
            if (window.location.href.toLowerCase().indexOf("https") === 0) {
                return true;
            } else {
                return false;
            }
        }(),
        
        /**
        * Initializes the custom events for Module which are fired 
        * automatically at appropriate times by the Module class.
        */
        initDefaultConfig: function () {
            // Add properties //
            /**
            * Specifies whether the Module is visible on the page.
            * @config visible
            * @type Boolean
            * @default true
            */
            this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
                handler: this.configVisible, 
                value: DEFAULT_CONFIG.VISIBLE.value, 
                validator: DEFAULT_CONFIG.VISIBLE.validator
            });

            /**
            * Object or array of objects representing the ContainerEffect 
            * classes that are active for animating the container.
            * @config effect
            * @type Object
            * @default null
            */
            this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
                suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent, 
                supercedes: DEFAULT_CONFIG.EFFECT.supercedes
            });

            /**
            * Specifies whether to create a special proxy iframe to monitor 
            * for user font resizing in the document
            * @config monitorresize
            * @type Boolean
            * @default true
            */
            this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
                handler: this.configMonitorResize,
                value: DEFAULT_CONFIG.MONITOR_RESIZE.value
            });

            /**
            * Specifies if the module should be rendered as the first child 
            * of document.body or appended as the last child when render is called
            * with document.body as the "appendToNode".
            * <p>
            * Appending to the body while the DOM is still being constructed can 
            * lead to Operation Aborted errors in IE hence this flag is set to 
            * false by default.
            * </p>
            * 
            * @config appendtodocumentbody
            * @type Boolean
            * @default false
            */
            this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
                value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
            });
        },

        /**
        * The Module class's initialization method, which is executed for
        * Module and all of its subclasses. This method is automatically 
        * called by the constructor, and  sets up all DOM references for 
        * pre-existing markup, and creates required markup if it is not 
        * already present.
        * @method init
        * @param {String} el The element ID representing the Module <em>OR</em>
        * @param {HTMLElement} el The element representing the Module
        * @param {Object} userConfig The configuration Object literal 
        * containing the configuration that should be set for this module. 
        * See configuration documentation for more details.
        */
        init: function (el, userConfig) {

            var elId, child;

            this.initEvents();
            this.beforeInitEvent.fire(Module);

            /**
            * The Module's Config object used for monitoring 
            * configuration properties.
            * @property cfg
            * @type YAHOO.util.Config
            */
            this.cfg = new Config(this);

            if (this.isSecure) {
                this.imageRoot = Module.IMG_ROOT_SSL;
            }

            if (typeof el == "string") {
                elId = el;
                el = document.getElementById(el);
                if (! el) {
                    el = (createModuleTemplate()).cloneNode(false);
                    el.id = elId;
                }
            }

            this.element = el;

            if (el.id) {
                this.id = el.id;
            }

            child = this.element.firstChild;

            if (child) {
                var fndHd = false, fndBd = false, fndFt = false;
                do {
                    // We're looking for elements
                    if (1 == child.nodeType) {
                        if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
                            this.header = child;
                            fndHd = true;
                        } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
                            this.body = child;
                            fndBd = true;
                        } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
                            this.footer = child;
                            fndFt = true;
                        }
                    }
                } while ((child = child.nextSibling));
            }

            this.initDefaultConfig();

            Dom.addClass(this.element, Module.CSS_MODULE);

            if (userConfig) {
                this.cfg.applyConfig(userConfig, true);
            }

            /*
                Subscribe to the fireQueue() method of Config so that any 
                queued configuration changes are excecuted upon render of 
                the Module
            */ 

            if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
                this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
            }

            this.initEvent.fire(Module);
        },

        /**
        * Initialize an empty IFRAME that is placed out of the visible area 
        * that can be used to detect text resize.
        * @method initResizeMonitor
        */
        initResizeMonitor: function () {

            var isGeckoWin = (YAHOO.env.ua.gecko && this.platform == "windows");
            if (isGeckoWin) {
                // Help prevent spinning loading icon which 
                // started with FireFox 2.0.0.8/Win
                var self = this;
                setTimeout(function(){self._initResizeMonitor();}, 0);
            } else {
                this._initResizeMonitor();
            }
        },

        /**
         * Create and initialize the text resize monitoring iframe.
         * 
         * @protected
         * @method _initResizeMonitor
         */
        _initResizeMonitor : function() {

            var oDoc, 
                oIFrame, 
                sHTML;

            function fireTextResize() {
                Module.textResizeEvent.fire();
            }

            if (!YAHOO.env.ua.opera) {
                oIFrame = Dom.get("_yuiResizeMonitor");

                var supportsCWResize = this._supportsCWResize();

                if (!oIFrame) {
                    oIFrame = document.createElement("iframe");

                    if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && YAHOO.env.ua.ie) {
                        oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
                    }

                    if (!supportsCWResize) {
                        // Can't monitor on contentWindow, so fire from inside iframe
                        sHTML = ["<html><head><script ",
                                 "type=\"text/javascript\">",
                                 "window.onresize=function(){window.parent.",
                                 "YAHOO.widget.Module.textResizeEvent.",
                                 "fire();};<",
                                 "\/script></head>",
                                 "<body></body></html>"].join('');

                        oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
                    }

                    oIFrame.id = "_yuiResizeMonitor";
                    /*
                        Need to set "position" property before inserting the 
                        iframe into the document or Safari's status bar will 
                        forever indicate the iframe is loading 
                        (See SourceForge bug #1723064)
                    */
                    oIFrame.style.position = "absolute";
                    oIFrame.style.visibility = "hidden";

                    var db = document.body,
                        fc = db.firstChild;
                    if (fc) {
                        db.insertBefore(oIFrame, fc);
                    } else {
                        db.appendChild(oIFrame);
                    }

                    oIFrame.style.width = "10em";
                    oIFrame.style.height = "10em";
                    oIFrame.style.top = (-1 * oIFrame.offsetHeight) + "px";
                    oIFrame.style.left = (-1 * oIFrame.offsetWidth) + "px";
                    oIFrame.style.borderWidth = "0";
                    oIFrame.style.visibility = "visible";

                    /*
                       Don't open/close the document for Gecko like we used to, since it
                       leads to duplicate cookies. (See SourceForge bug #1721755)
                    */
                    if (YAHOO.env.ua.webkit) {
                        oDoc = oIFrame.contentWindow.document;
                        oDoc.open();
                        oDoc.close();
                    }
                }

                if (oIFrame && oIFrame.contentWindow) {
                    Module.textResizeEvent.subscribe(this.onDomResize, this, true);

                    if (!Module.textResizeInitialized) {
                        if (supportsCWResize) {
                            if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
                                /*
                                     This will fail in IE if document.domain has 
                                     changed, so we must change the listener to 
                                     use the oIFrame element instead
                                */
                                Event.on(oIFrame, "resize", fireTextResize);
                            }
                        }
                        Module.textResizeInitialized = true;
                    }
                    this.resizeMonitor = oIFrame;
                }
            }
        },

        /**
         * Text resize monitor helper method.
         * Determines if the browser supports resize events on iframe content windows.
         * 
         * @private
         * @method _supportsCWResize
         */
        _supportsCWResize : function() {
            /*
                Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
                Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.

                We don't want to start sniffing for patch versions, so fire textResize the same
                way on all FF, until 1.9 (3.x) is out
             */
            var bSupported = true;
            if (YAHOO.env.ua.gecko && YAHOO.env.ua.gecko <= 1.8) {
                bSupported = false;
                /*
                var v = navigator.userAgent.match(/rv:([^\s\)]*)/); // From YAHOO.env.ua
                if (v && v[0]) {
                    var sv = v[0].match(/\d\.\d\.(\d)/);
                    if (sv && sv[1]) {
                        if (parseInt(sv[1], 10) > 0) {
                            bSupported = true;
                        }
                    }
                }
                */
            }
            return bSupported;
        },

        /**
        * Event handler fired when the resize monitor element is resized.
        * @method onDomResize
        * @param {DOMEvent} e The DOM resize event
        * @param {Object} obj The scope object passed to the handler
        */
        onDomResize: function (e, obj) {

            var nLeft = -1 * this.resizeMonitor.offsetWidth,
                nTop = -1 * this.resizeMonitor.offsetHeight;
        
            this.resizeMonitor.style.top = nTop + "px";
            this.resizeMonitor.style.left =  nLeft + "px";

        },

        /**
        * Sets the Module's header content to the string specified, or appends 
        * the passed element to the header. If no header is present, one will 
        * be automatically created. An empty string can be passed to the method
        * to clear the contents of the header.
        * 
        * @method setHeader
        * @param {String} headerContent The string used to set the header.
        * As a convenience, non HTMLElement objects can also be passed into 
        * the method, and will be treated as strings, with the header innerHTML
        * set to their default toString implementations.
        * <em>OR</em>
        * @param {HTMLElement} headerContent The HTMLElement to append to 
        * <em>OR</em>
        * @param {DocumentFragment} headerContent The document fragment 
        * containing elements which are to be added to the header
        */
        setHeader: function (headerContent) {
            var oHeader = this.header || (this.header = createHeader());

            if (headerContent.nodeName) {
                oHeader.innerHTML = "";
                oHeader.appendChild(headerContent);
            } else {
                oHeader.innerHTML = headerContent;
            }

            this.changeHeaderEvent.fire(headerContent);
            this.changeContentEvent.fire();

        },

        /**
        * Appends the passed element to the header. If no header is present, 
        * one will be automatically created.
        * @method appendToHeader
        * @param {HTMLElement | DocumentFragment} element The element to 
        * append to the header. In the case of a document fragment, the
        * children of the fragment will be appended to the header.
        */
        appendToHeader: function (element) {
            var oHeader = this.header || (this.header = createHeader());

            oHeader.appendChild(element);

            this.changeHeaderEvent.fire(element);
            this.changeContentEvent.fire();

        },

        /**
        * Sets the Module's body content to the HTML specified, or appends the
        * passed element to the body. If no body is present, one will be 
        * automatically created. An empty string can be passed to the method
        * to clear the contents of the body.
        * @method setBody
        * @param {String} bodyContent The HTML used to set the body. 
        * As a convenience, non HTMLElement objects can also be passed into 
        * the method, and will be treated as strings, with the body innerHTML
        * set to their default toString implementations.
        * <em>OR</em>
        * @param {HTMLElement} bodyContent The HTMLElement to append to the body
        * <em>OR</em>
        * @param {DocumentFragment} bodyContent The document fragment 
        * containing elements which are to be added to the body
        */
        setBody: function (bodyContent) {
            var oBody = this.body || (this.body = createBody());

            if (bodyContent.nodeName) {
                oBody.innerHTML = "";
                oBody.appendChild(bodyContent);
            } else {
                oBody.innerHTML = bodyContent;
            }

            this.changeBodyEvent.fire(bodyContent);
            this.changeContentEvent.fire();
        },

        /**
        * Appends the passed element to the body. If no body is present, one 
        * will be automatically created.
        * @method appendToBody
        * @param {HTMLElement | DocumentFragment} element The element to 
        * append to the body. In the case of a document fragment, the
        * children of the fragment will be appended to the body.
        * 
        */
        appendToBody: function (element) {
            var oBody = this.body || (this.body = createBody());
        
            oBody.appendChild(element);

            this.changeBodyEvent.fire(element);
            this.changeContentEvent.fire();

        },
        
        /**
        * Sets the Module's footer content to the HTML specified, or appends 
        * the passed element to the footer. If no footer is present, one will 
        * be automatically created. An empty string can be passed to the method
        * to clear the contents of the footer.
        * @method setFooter
        * @param {String} footerContent The HTML used to set the footer 
        * As a convenience, non HTMLElement objects can also be passed into 
        * the method, and will be treated as strings, with the footer innerHTML
        * set to their default toString implementations.
        * <em>OR</em>
        * @param {HTMLElement} footerContent The HTMLElement to append to 
        * the footer
        * <em>OR</em>
        * @param {DocumentFragment} footerContent The document fragment containing 
        * elements which are to be added to the footer
        */
        setFooter: function (footerContent) {

            var oFooter = this.footer || (this.footer = createFooter());

            if (footerContent.nodeName) {
                oFooter.innerHTML = "";
                oFooter.appendChild(footerContent);
            } else {
                oFooter.innerHTML = footerContent;
            }

            this.changeFooterEvent.fire(footerContent);
            this.changeContentEvent.fire();
        },

        /**
        * Appends the passed element to the footer. If no footer is present, 
        * one will be automatically created.
        * @method appendToFooter
        * @param {HTMLElement | DocumentFragment} element The element to 
        * append to the footer. In the case of a document fragment, the
        * children of the fragment will be appended to the footer
        */
        appendToFooter: function (element) {

            var oFooter = this.footer || (this.footer = createFooter());

            oFooter.appendChild(element);

            this.changeFooterEvent.fire(element);
            this.changeContentEvent.fire();

        },

        /**
        * Renders the Module by inserting the elements that are not already 
        * in the main Module into their correct places. Optionally appends 
        * the Module to the specified node prior to the render's execution. 
        * <p>
        * For Modules without existing markup, the appendToNode argument 
        * is REQUIRED. If this argument is ommitted and the current element is 
        * not present in the document, the function will return false, 
        * indicating that the render was a failure.
        * </p>
        * <p>
        * NOTE: As of 2.3.1, if the appendToNode is the document's body element
        * then the module is rendered as the first child of the body element, 
        * and not appended to it, to avoid Operation Aborted errors in IE when 
        * rendering the module before window's load event is fired. You can 
        * use the appendtodocumentbody configuration property to change this 
        * to append to document.body if required.
        * </p>
        * @method render
        * @param {String} appendToNode The element id to which the Module 
        * should be appended to prior to rendering <em>OR</em>
        * @param {HTMLElement} appendToNode The element to which the Module 
        * should be appended to prior to rendering
        * @param {HTMLElement} moduleElement OPTIONAL. The element that 
        * represents the actual Standard Module container.
        * @return {Boolean} Success or failure of the render
        */
        render: function (appendToNode, moduleElement) {

            var me = this,
                firstChild;

            function appendTo(parentNode) {
                if (typeof parentNode == "string") {
                    parentNode = document.getElementById(parentNode);
                }

                if (parentNode) {
                    me._addToParent(parentNode, me.element);
                    me.appendEvent.fire();
                }
            }

            this.beforeRenderEvent.fire();

            if (! moduleElement) {
                moduleElement = this.element;
            }

            if (appendToNode) {
                appendTo(appendToNode);
            } else { 
                // No node was passed in. If the element is not already in the Dom, this fails
                if (! Dom.inDocument(this.element)) {
                    return false;
                }
            }

            // Need to get everything into the DOM if it isn't already
            if (this.header && ! Dom.inDocument(this.header)) {
                // There is a header, but it's not in the DOM yet. Need to add it.
                firstChild = moduleElement.firstChild;
                if (firstChild) {
                    moduleElement.insertBefore(this.header, firstChild);
                } else {
                    moduleElement.appendChild(this.header);
                }
            }

            if (this.body && ! Dom.inDocument(this.body)) {
                // There is a body, but it's not in the DOM yet. Need to add it.		
                if (this.footer && Dom.isAncestor(this.moduleElement, this.footer)) {
                    moduleElement.insertBefore(this.body, this.footer);
                } else {
                    moduleElement.appendChild(this.body);
                }
            }

            if (this.footer && ! Dom.inDocument(this.footer)) {
                // There is a footer, but it's not in the DOM yet. Need to add it.
                moduleElement.appendChild(this.footer);
            }

            this.renderEvent.fire();
            return true;
        },

        /**
        * Removes the Module element from the DOM and sets all child elements 
        * to null.
        * @method destroy
        */
        destroy: function () {

            var parent,
                e;

            if (this.element) {
                Event.purgeElement(this.element, true);
                parent = this.element.parentNode;
            }

            if (parent) {
                parent.removeChild(this.element);
            }
        
            this.element = null;
            this.header = null;
            this.body = null;
            this.footer = null;

            Module.textResizeEvent.unsubscribe(this.onDomResize, this);

            this.cfg.destroy();
            this.cfg = null;

            this.destroyEvent.fire();
        
            for (e in this) {
                if (e instanceof CustomEvent) {
                    e.unsubscribeAll();
                }
            }

        },

        /**
        * Shows the Module element by setting the visible configuration 
        * property to true. Also fires two events: beforeShowEvent prior to 
        * the visibility change, and showEvent after.
        * @method show
        */
        show: function () {
            this.cfg.setProperty("visible", true);
        },

        /**
        * Hides the Module element by setting the visible configuration 
        * property to false. Also fires two events: beforeHideEvent prior to 
        * the visibility change, and hideEvent after.
        * @method hide
        */
        hide: function () {
            this.cfg.setProperty("visible", false);
        },
        
        // BUILT-IN EVENT HANDLERS FOR MODULE //
        /**
        * Default event handler for changing the visibility property of a 
        * Module. By default, this is achieved by switching the "display" style 
        * between "block" and "none".
        * This method is responsible for firing showEvent and hideEvent.
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        * @method configVisible
        */
        configVisible: function (type, args, obj) {
            var visible = args[0];
            if (visible) {
                this.beforeShowEvent.fire();
                Dom.setStyle(this.element, "display", "block");
                this.showEvent.fire();
            } else {
                this.beforeHideEvent.fire();
                Dom.setStyle(this.element, "display", "none");
                this.hideEvent.fire();
            }
        },
        
        /**
        * Default event handler for the "monitorresize" configuration property
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        * @method configMonitorResize
        */
        configMonitorResize: function (type, args, obj) {
            var monitor = args[0];
            if (monitor) {
                this.initResizeMonitor();
            } else {
                Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
                this.resizeMonitor = null;
            }
        },

        /**
         * This method is a protected helper, used when constructing the DOM structure for the module 
         * to account for situations which may cause Operation Aborted errors in IE. It should not 
         * be used for general DOM construction.
         * <p>
         * If the parentNode is not document.body, the element is appended as the last element.
         * </p>
         * <p>
         * If the parentNode is document.body the element is added as the first child to help
         * prevent Operation Aborted errors in IE.
         * </p>
         *
         * @param {parentNode} The HTML element to which the element will be added
         * @param {element} The HTML element to be added to parentNode's children
         * @method _addToParent
         * @protected
         */
        _addToParent: function(parentNode, element) {
            if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
                parentNode.insertBefore(element, parentNode.firstChild);
            } else {
                parentNode.appendChild(element);
            }
        },

        /**
        * Returns a String representation of the Object.
        * @method toString
        * @return {String} The string representation of the Module
        */
        toString: function () {
            return "Module " + this.id;
        }
    };

    YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);

}());

(function () {

    /**
    * Overlay is a Module that is absolutely positioned above the page flow. It 
    * has convenience methods for positioning and sizing, as well as options for 
    * controlling zIndex and constraining the Overlay's position to the current 
    * visible viewport. Overlay also contains a dynamicly generated IFRAME which 
    * is placed beneath it for Internet Explorer 6 and 5.x so that it will be 
    * properly rendered above SELECT elements.
    * @namespace YAHOO.widget
    * @class Overlay
    * @extends YAHOO.widget.Module
    * @param {String} el The element ID representing the Overlay <em>OR</em>
    * @param {HTMLElement} el The element representing the Overlay
    * @param {Object} userConfig The configuration object literal containing 
    * the configuration that should be set for this Overlay. See configuration 
    * documentation for more details.
    * @constructor
    */
    YAHOO.widget.Overlay = function (el, userConfig) {
        YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
    };

    var Lang = YAHOO.lang,
        CustomEvent = YAHOO.util.CustomEvent,
        Module = YAHOO.widget.Module,
        Event = YAHOO.util.Event,
        Dom = YAHOO.util.Dom,
        Config = YAHOO.util.Config,
        Overlay = YAHOO.widget.Overlay,

        m_oIFrameTemplate,

        /**
        * Constant representing the name of the Overlay's events
        * @property EVENT_TYPES
        * @private
        * @final
        * @type Object
        */
        EVENT_TYPES = {
            "BEFORE_MOVE": "beforeMove",
            "MOVE": "move"
        },

        /**
        * Constant representing the Overlay's configuration properties
        * @property DEFAULT_CONFIG
        * @private
        * @final
        * @type Object
        */
        DEFAULT_CONFIG = {

            "X": { 
                key: "x", 
                validator: Lang.isNumber, 
                suppressEvent: true, 
                supercedes: ["iframe"]
            },

            "Y": { 
                key: "y", 
                validator: Lang.isNumber, 
                suppressEvent: true, 
                supercedes: ["iframe"]
            },

            "XY": { 
                key: "xy", 
                suppressEvent: true, 
                supercedes: ["iframe"] 
            },

            "CONTEXT": { 
                key: "context", 
                suppressEvent: true, 
                supercedes: ["iframe"] 
            },

            "FIXED_CENTER": { 
                key: "fixedcenter", 
                value: false, 
                validator: Lang.isBoolean, 
                supercedes: ["iframe", "visible"] 
            },

            "WIDTH": { 
                key: "width", 
                suppressEvent: true, 
                supercedes: ["context", "fixedcenter", "iframe"] 
            }, 

            "HEIGHT": { 
                key: "height", 
                suppressEvent: true, 
                supercedes: ["context", "fixedcenter", "iframe"] 
            },

            "ZINDEX": { 
                key: "zindex", 
                value: null 
            },

            "CONSTRAIN_TO_VIEWPORT": { 
                key: "constraintoviewport", 
                value: false, 
                validator: Lang.isBoolean, 
                supercedes: ["iframe", "x", "y", "xy"]
            }, 

            "IFRAME": { 
                key: "iframe", 
                value: (YAHOO.env.ua.ie == 6 ? true : false), 
                validator: Lang.isBoolean, 
                supercedes: ["zindex"] 
            }
        };

    /**
    * The URL that will be placed in the iframe
    * @property YAHOO.widget.Overlay.IFRAME_SRC
    * @static
    * @final
    * @type String
    */
    Overlay.IFRAME_SRC = "javascript:false;";

    /**
    * Number representing how much the iframe shim should be offset from each 
    * side of an Overlay instance, in pixels.
    * @property YAHOO.widget.Overlay.IFRAME_SRC
    * @default 3
    * @static
    * @final
    * @type Number
    */
    Overlay.IFRAME_OFFSET = 3;

    /**
    * Number representing the minimum distance an Overlay instance should be 
    * positioned relative to the boundaries of the browser's viewport, in pixels.
    * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
    * @default 10
    * @static
    * @final
    * @type Number
    */
    Overlay.VIEWPORT_OFFSET = 10;

    /**
    * Constant representing the top left corner of an element, used for 
    * configuring the context element alignment
    * @property YAHOO.widget.Overlay.TOP_LEFT
    * @static
    * @final
    * @type String
    */
    Overlay.TOP_LEFT = "tl";

    /**
    * Constant representing the top right corner of an element, used for 
    * configuring the context element alignment
    * @property YAHOO.widget.Overlay.TOP_RIGHT
    * @static
    * @final
    * @type String
    */
    Overlay.TOP_RIGHT = "tr";

    /**
    * Constant representing the top bottom left corner of an element, used for 
    * configuring the context element alignment
    * @property YAHOO.widget.Overlay.BOTTOM_LEFT
    * @static
    * @final
    * @type String
    */
    Overlay.BOTTOM_LEFT = "bl";

    /**
    * Constant representing the bottom right corner of an element, used for 
    * configuring the context element alignment
    * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
    * @static
    * @final
    * @type String
    */
    Overlay.BOTTOM_RIGHT = "br";

    /**
    * Constant representing the default CSS class used for an Overlay
    * @property YAHOO.widget.Overlay.CSS_OVERLAY
    * @static
    * @final
    * @type String
    */
    Overlay.CSS_OVERLAY = "yui-overlay";

    /**
    * A singleton CustomEvent used for reacting to the DOM event for 
    * window scroll
    * @event YAHOO.widget.Overlay.windowScrollEvent
    */
    Overlay.windowScrollEvent = new CustomEvent("windowScroll");

    /**
    * A singleton CustomEvent used for reacting to the DOM event for
    * window resize
    * @event YAHOO.widget.Overlay.windowResizeEvent
    */
    Overlay.windowResizeEvent = new CustomEvent("windowResize");

    /**
    * The DOM event handler used to fire the CustomEvent for window scroll
    * @method YAHOO.widget.Overlay.windowScrollHandler
    * @static
    * @param {DOMEvent} e The DOM scroll event
    */
    Overlay.windowScrollHandler = function (e) {

        if (YAHOO.env.ua.ie) {

            if (! window.scrollEnd) {
                window.scrollEnd = -1;
            }

            clearTimeout(window.scrollEnd);
    
            window.scrollEnd = setTimeout(function () { 
                Overlay.windowScrollEvent.fire(); 
            }, 1);
    
        } else {
            Overlay.windowScrollEvent.fire();
        }
    };

    /**
    * The DOM event handler used to fire the CustomEvent for window resize
    * @method YAHOO.widget.Overlay.windowResizeHandler
    * @static
    * @param {DOMEvent} e The DOM resize event
    */
    Overlay.windowResizeHandler = function (e) {

        if (YAHOO.env.ua.ie) {
            if (! window.resizeEnd) {
                window.resizeEnd = -1;
            }

            clearTimeout(window.resizeEnd);

            window.resizeEnd = setTimeout(function () {
                Overlay.windowResizeEvent.fire(); 
            }, 100);
        } else {
            Overlay.windowResizeEvent.fire();
        }
    };

    /**
    * A boolean that indicated whether the window resize and scroll events have 
    * already been subscribed to.
    * @property YAHOO.widget.Overlay._initialized
    * @private
    * @type Boolean
    */
    Overlay._initialized = null;

    if (Overlay._initialized === null) {
        Event.on(window, "scroll", Overlay.windowScrollHandler);
        Event.on(window, "resize", Overlay.windowResizeHandler);
    
        Overlay._initialized = true;
    }

    YAHOO.extend(Overlay, Module, {

        /**
        * The Overlay initialization method, which is executed for Overlay and  
        * all of its subclasses. This method is automatically called by the 
        * constructor, and  sets up all DOM references for pre-existing markup, 
        * and creates required markup if it is not already present.
        * @method init
        * @param {String} el The element ID representing the Overlay <em>OR</em>
        * @param {HTMLElement} el The element representing the Overlay
        * @param {Object} userConfig The configuration object literal 
        * containing the configuration that should be set for this Overlay. 
        * See configuration documentation for more details.
        */
        init: function (el, userConfig) {
    
            /*
                 Note that we don't pass the user config in here yet because we
                 only want it executed once, at the lowest subclass level
            */
    
            Overlay.superclass.init.call(this, el/*, userConfig*/);  

            this.beforeInitEvent.fire(Overlay);
            
            Dom.addClass(this.element, Overlay.CSS_OVERLAY);
            
            if (userConfig) {
                this.cfg.applyConfig(userConfig, true);
            }

            if (this.platform == "mac" && YAHOO.env.ua.gecko) {

                if (! Config.alreadySubscribed(this.showEvent,
                    this.showMacGeckoScrollbars, this)) {

                    this.showEvent.subscribe(this.showMacGeckoScrollbars, 
                        this, true);

                }

                if (! Config.alreadySubscribed(this.hideEvent, 
                    this.hideMacGeckoScrollbars, this)) {

                    this.hideEvent.subscribe(this.hideMacGeckoScrollbars, 
                        this, true);

                }
            }

            this.initEvent.fire(Overlay);
        },
        
        /**
        * Initializes the custom events for Overlay which are fired  
        * automatically at appropriate times by the Overlay class.
        * @method initEvents
        */
        initEvents: function () {
    
            Overlay.superclass.initEvents.call(this);
            
            var SIGNATURE = CustomEvent.LIST;
            
            /**
            * CustomEvent fired before the Overlay is moved.
            * @event beforeMoveEvent
            * @param {Number} x x coordinate
            * @param {Number} y y coordinate
            */
            this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
            this.beforeMoveEvent.signature = SIGNATURE;
            
            /**
            * CustomEvent fired after the Overlay is moved.
            * @event moveEvent
            * @param {Number} x x coordinate
            * @param {Number} y y coordinate
            */
            this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
            this.moveEvent.signature = SIGNATURE;
        
        },
        
        /**
        * Initializes the class's configurable properties which can be changed 
        * using the Overlay's Config object (cfg).
        * @method initDefaultConfig
        */
        initDefaultConfig: function () {
    
            Overlay.superclass.initDefaultConfig.call(this);
            
            
            // Add overlay config properties //
            
            /**
            * The absolute x-coordinate position of the Overlay
            * @config x
            * @type Number
            * @default null
            */
            this.cfg.addProperty(DEFAULT_CONFIG.X.key, { 
    
                handler: this.configX, 
                validator: DEFAULT_CONFIG.X.validator, 
                suppressEvent: DEFAULT_CONFIG.X.suppressEvent, 
                supercedes: DEFAULT_CONFIG.X.supercedes
    
            });

            /**
            * The absolute y-coordinate position of the Overlay
            * @config y
            * @type Number
            * @default null
            */
            this.cfg.addProperty(DEFAULT_CONFIG.Y.key, {

                handler: this.configY, 
                validator: DEFAULT_CONFIG.Y.validator, 
                suppressEvent: DEFAULT_CONFIG.Y.suppressEvent, 
                supercedes: DEFAULT_CONFIG.Y.supercedes

            });
    
            /**
            * An array with the absolute x and y positions of the Overlay
            * @config xy
            * @type Number[]
            * @default null
            */
            this.cfg.addProperty(DEFAULT_CONFIG.XY.key, {
            
                handler: this.configXY, 
                suppressEvent: DEFAULT_CONFIG.XY.suppressEvent, 
                supercedes: DEFAULT_CONFIG.XY.supercedes
            
            });
    
            /**
            * The array of context arguments for context-sensitive positioning.  
            * The format is: [id or element, element corner, context corner]. 
            * For example, setting this property to ["img1", "tl", "bl"] would 
            * align the Overlay's top left corner to the context element's 
            * bottom left corner.
            * @config context
            * @type Array
            * @default null
            */
            this.cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
            
                handler: this.configContext, 
                suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent, 
                supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
            
            });

            /**
            * True if the Overlay should be anchored to the center of 
            * the viewport.
            * @config fixedcenter
            * @type Boolean
            * @default false
            */
            this.cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
            
                handler: this.configFixedCenter,
                value: DEFAULT_CONFIG.FIXED_CENTER.value, 
                validator: DEFAULT_CONFIG.FIXED_CENTER.validator, 
                supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
            
            });
    
            /**
            * CSS width of the Overlay.
            * @config width
            * @type String
            * @default null
            */
            this.cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {

                handler: this.configWidth, 
                suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent, 
                supercedes: DEFAULT_CONFIG.WIDTH.supercedes

            });

            /**
            * CSS height of the Overlay.
            * @config height
            * @type String
            * @default null
            */
            this.cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {

                handler: this.configHeight, 
                suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent, 
                supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
            
            });
            
            /**
            * CSS z-index of the Overlay.
            * @config zIndex
            * @type Number
            * @default null
            */
            this.cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {

                handler: this.configzIndex,
                value: DEFAULT_CONFIG.ZINDEX.value

            });

            /**
            * True if the Overlay should be prevented from being positioned 
            * out of the viewport.
            * @config constraintoviewport
            * @type Boolean
            * @default false
            */
            this.cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {

                handler: this.configConstrainToViewport, 
                value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value, 
                validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator, 
                supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes

            });

            /**
            * @config iframe
            * @description Boolean indicating whether or not the Overlay should 
            * have an IFRAME shim; used to prevent SELECT elements from 
            * poking through an Overlay instance in IE6.  When set to "true", 
            * the iframe shim is created when the Overlay instance is intially
            * made visible.
            * @type Boolean
            * @default true for IE6 and below, false for all other browsers.
            */
            this.cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {

                handler: this.configIframe, 
                value: DEFAULT_CONFIG.IFRAME.value, 
                validator: DEFAULT_CONFIG.IFRAME.validator, 
                supercedes: DEFAULT_CONFIG.IFRAME.supercedes

            });
        },

        /**
        * Moves the Overlay to the specified position. This function is  
        * identical to calling this.cfg.setProperty("xy", [x,y]);
        * @method moveTo
        * @param {Number} x The Overlay's new x position
        * @param {Number} y The Overlay's new y position
        */
        moveTo: function (x, y) {
            this.cfg.setProperty("xy", [x, y]);
        },

        /**
        * Adds a CSS class ("hide-scrollbars") and removes a CSS class 
        * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X 
        * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
        * @method hideMacGeckoScrollbars
        */
        hideMacGeckoScrollbars: function () {
    
            Dom.removeClass(this.element, "show-scrollbars");
            Dom.addClass(this.element, "hide-scrollbars");
    
        },

        /**
        * Adds a CSS class ("show-scrollbars") and removes a CSS class 
        * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X 
        * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
        * @method showMacGeckoScrollbars
        */
        showMacGeckoScrollbars: function () {
    
            Dom.removeClass(this.element, "hide-scrollbars");
            Dom.addClass(this.element, "show-scrollbars");
    
        },

        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
        /**
        * The default event handler fired when the "visible" property is 
        * changed.  This method is responsible for firing showEvent
        * and hideEvent.
        * @method configVisible
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configVisible: function (type, args, obj) {

            var visible = args[0],
                currentVis = Dom.getStyle(this.element, "visibility"),
                effect = this.cfg.getProperty("effect"),
                effectInstances = [],
                isMacGecko = (this.platform == "mac" && YAHOO.env.ua.gecko),
                alreadySubscribed = Config.alreadySubscribed,
                eff, ei, e, i, j, k, h,
                nEffects,
                nEffectInstances;

            if (currentVis == "inherit") {
                e = this.element.parentNode;

                while (e.nodeType != 9 && e.nodeType != 11) {
                    currentVis = Dom.getStyle(e, "visibility");

                    if (currentVis != "inherit") { 
                        break; 
                    }

                    e = e.parentNode;
                }

                if (currentVis == "inherit") {
                    currentVis = "visible";
                }
            }

            if (effect) {
                if (effect instanceof Array) {
                    nEffects = effect.length;

                    for (i = 0; i < nEffects; i++) {
                        eff = effect[i];
                        effectInstances[effectInstances.length] = 
                            eff.effect(this, eff.duration);

                    }
                } else {
                    effectInstances[effectInstances.length] = 
                        effect.effect(this, effect.duration);
                }
            }


            if (visible) { // Show
                if (isMacGecko) {
                    this.showMacGeckoScrollbars();
                }

                if (effect) { // Animate in
                    if (visible) { // Animate in if not showing
                        if (currentVis != "visible" || currentVis === "") {
                            this.beforeShowEvent.fire();
                            nEffectInstances = effectInstances.length;

                            for (j = 0; j < nEffectInstances; j++) {
                                ei = effectInstances[j];
                                if (j === 0 && !alreadySubscribed(
                                        ei.animateInCompleteEvent, 
                                        this.showEvent.fire, this.showEvent)) {

                                    /*
                                         Delegate showEvent until end 
                                         of animateInComplete
                                    */

                                    ei.animateInCompleteEvent.subscribe(
                                     this.showEvent.fire, this.showEvent, true);
                                }
                                ei.animateIn();
                            }
                        }
                    }
                } else { // Show
                    if (currentVis != "visible" || currentVis === "") {
                        this.beforeShowEvent.fire();

                        Dom.setStyle(this.element, "visibility", "visible");

                        this.cfg.refireEvent("iframe");
                        this.showEvent.fire();
                    }
                }
            } else { // Hide

                if (isMacGecko) {
                    this.hideMacGeckoScrollbars();
                }
                    
                if (effect) { // Animate out if showing
                    if (currentVis == "visible") {
                        this.beforeHideEvent.fire();

                        nEffectInstances = effectInstances.length;
                        for (k = 0; k < nEffectInstances; k++) {
                            h = effectInstances[k];
    
                            if (k === 0 && !alreadySubscribed(
                                h.animateOutCompleteEvent, this.hideEvent.fire, 
                                this.hideEvent)) {
    
                                /*
                                     Delegate hideEvent until end 
                                     of animateOutComplete
                                */
    
                                h.animateOutCompleteEvent.subscribe(
                                    this.hideEvent.fire, this.hideEvent, true);
    
                            }
                            h.animateOut();
                        }

                    } else if (currentVis === "") {
                        Dom.setStyle(this.element, "visibility", "hidden");
                    }

                } else { // Simple hide

                    if (currentVis == "visible" || currentVis === "") {
                        this.beforeHideEvent.fire();
                        Dom.setStyle(this.element, "visibility", "hidden");
                        this.hideEvent.fire();
                    }
                }
            }
        },

        /**
        * Center event handler used for centering on scroll/resize, but only if 
        * the Overlay is visible
        * @method doCenterOnDOMEvent
        */
        doCenterOnDOMEvent: function () {
            if (this.cfg.getProperty("visible")) {
                this.center();
            }
        },

        /**
        * The default event handler fired when the "fixedcenter" property 
        * is changed.
        * @method configFixedCenter
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configFixedCenter: function (type, args, obj) {

            var val = args[0],
                alreadySubscribed = Config.alreadySubscribed,
                windowResizeEvent = Overlay.windowResizeEvent,
                windowScrollEvent = Overlay.windowScrollEvent;

            if (val) {
                this.center();

                if (!alreadySubscribed(this.beforeShowEvent, this.center, this)) {
                    this.beforeShowEvent.subscribe(this.center);
                }

                if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
                    windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
                }

                if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
                    windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
                }

            } else {
                this.beforeShowEvent.unsubscribe(this.center);

                windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
                windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
            }
        },
        
        /**
        * The default event handler fired when the "height" property is changed.
        * @method configHeight
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configHeight: function (type, args, obj) {

            var height = args[0],
                el = this.element;

            Dom.setStyle(el, "height", height);
            this.cfg.refireEvent("iframe");
        },

        /**
        * The default event handler fired when the "width" property is changed.
        * @method configWidth
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configWidth: function (type, args, obj) {

            var width = args[0],
                el = this.element;
    
            Dom.setStyle(el, "width", width);
            this.cfg.refireEvent("iframe");
        },
        
        /**
        * The default event handler fired when the "zIndex" property is changed.
        * @method configzIndex
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configzIndex: function (type, args, obj) {

            var zIndex = args[0],
                el = this.element;

            if (! zIndex) {
                zIndex = Dom.getStyle(el, "zIndex");
                if (! zIndex || isNaN(zIndex)) {
                    zIndex = 0;
                }
            }

            if (this.iframe || this.cfg.getProperty("iframe") === true) {
                if (zIndex <= 0) {
                    zIndex = 1;
                }
            }

            Dom.setStyle(el, "zIndex", zIndex);
            this.cfg.setProperty("zIndex", zIndex, true);

            if (this.iframe) {
                this.stackIframe();
            }
        },

        /**
        * The default event handler fired when the "xy" property is changed.
        * @method configXY
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configXY: function (type, args, obj) {

            var pos = args[0],
                x = pos[0],
                y = pos[1];

            this.cfg.setProperty("x", x);
            this.cfg.setProperty("y", y);

            this.beforeMoveEvent.fire([x, y]);

            x = this.cfg.getProperty("x");
            y = this.cfg.getProperty("y");


            this.cfg.refireEvent("iframe");
            this.moveEvent.fire([x, y]);
        },

        /**
        * The default event handler fired when the "x" property is changed.
        * @method configX
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configX: function (type, args, obj) {

            var x = args[0],
                y = this.cfg.getProperty("y");

            this.cfg.setProperty("x", x, true);
            this.cfg.setProperty("y", y, true);

            this.beforeMoveEvent.fire([x, y]);

            x = this.cfg.getProperty("x");
            y = this.cfg.getProperty("y");
            
            Dom.setX(this.element, x, true);

            this.cfg.setProperty("xy", [x, y], true);

            this.cfg.refireEvent("iframe");
            this.moveEvent.fire([x, y]);
        },

        /**
        * The default event handler fired when the "y" property is changed.
        * @method configY
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configY: function (type, args, obj) {

            var x = this.cfg.getProperty("x"),
                y = args[0];

            this.cfg.setProperty("x", x, true);
            this.cfg.setProperty("y", y, true);

            this.beforeMoveEvent.fire([x, y]);

            x = this.cfg.getProperty("x");
            y = this.cfg.getProperty("y");

            Dom.setY(this.element, y, true);

            this.cfg.setProperty("xy", [x, y], true);

            this.cfg.refireEvent("iframe");
            this.moveEvent.fire([x, y]);
        },
        
        /**
        * Shows the iframe shim, if it has been enabled.
        * @method showIframe
        */
        showIframe: function () {

            var oIFrame = this.iframe,
                oParentNode;

            if (oIFrame) {
                oParentNode = this.element.parentNode;

                if (oParentNode != oIFrame.parentNode) {
                    this._addToParent(oParentNode, oIFrame);
                }
                oIFrame.style.display = "block";
            }
        },

        /**
        * Hides the iframe shim, if it has been enabled.
        * @method hideIframe
        */
        hideIframe: function () {
            if (this.iframe) {
                this.iframe.style.display = "none";
            }
        },

        /**
        * Syncronizes the size and position of iframe shim to that of its 
        * corresponding Overlay instance.
        * @method syncIframe
        */
        syncIframe: function () {

            var oIFrame = this.iframe,
                oElement = this.element,
                nOffset = Overlay.IFRAME_OFFSET,
                nDimensionOffset = (nOffset * 2),
                aXY;

            if (oIFrame) {
                // Size <iframe>
                oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
                oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");

                // Position <iframe>
                aXY = this.cfg.getProperty("xy");

                if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
                    this.syncPosition();
                    aXY = this.cfg.getProperty("xy");
                }
                Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
            }
        },

        /**
         * Sets the zindex of the iframe shim, if it exists, based on the zindex of
         * the Overlay element. The zindex of the iframe is set to be one less 
         * than the Overlay element's zindex.
         * 
         * <p>NOTE: This method will not bump up the zindex of the Overlay element
         * to ensure that the iframe shim has a non-negative zindex.
         * If you require the iframe zindex to be 0 or higher, the zindex of 
         * the Overlay element should be set to a value greater than 0, before 
         * this method is called.
         * </p>
         * @method stackIframe
         */
        stackIframe: function () {
            if (this.iframe) {
                var overlayZ = Dom.getStyle(this.element, "zIndex");
                if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
                    Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
                }
            }
        },

        /**
        * The default event handler fired when the "iframe" property is changed.
        * @method configIframe
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configIframe: function (type, args, obj) {

            var bIFrame = args[0];

            function createIFrame() {

                var oIFrame = this.iframe,
                    oElement = this.element,
                    oParent;

                if (!oIFrame) {
                    if (!m_oIFrameTemplate) {
                        m_oIFrameTemplate = document.createElement("iframe");

                        if (this.isSecure) {
                            m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
                        }

                        /*
                            Set the opacity of the <iframe> to 0 so that it 
                            doesn't modify the opacity of any transparent 
                            elements that may be on top of it (like a shadow).
                        */

                        if (YAHOO.env.ua.ie) {
                            m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
                            /*
                                 Need to set the "frameBorder" property to 0 
                                 supress the default <iframe> border in IE.  
                                 Setting the CSS "border" property alone 
                                 doesn't supress it.
                            */
                            m_oIFrameTemplate.frameBorder = 0;
                        }
                        else {
                            m_oIFrameTemplate.style.opacity = "0";
                        }

                        m_oIFrameTemplate.style.position = "absolute";
                        m_oIFrameTemplate.style.border = "none";
                        m_oIFrameTemplate.style.margin = "0";
                        m_oIFrameTemplate.style.padding = "0";
                        m_oIFrameTemplate.style.display = "none";
                    }

                    oIFrame = m_oIFrameTemplate.cloneNode(false);
                    oParent = oElement.parentNode;

                    var parentNode = oParent || document.body;

                    this._addToParent(parentNode, oIFrame);
                    this.iframe = oIFrame;
                }

                /*
                     Show the <iframe> before positioning it since the "setXY" 
                     method of DOM requires the element be in the document 
                     and visible.
                */
                this.showIframe();

                /*
                     Syncronize the size and position of the <iframe> to that 
                     of the Overlay.
                */
                this.syncIframe();
                this.stackIframe();

                // Add event listeners to update the <iframe> when necessary
                if (!this._hasIframeEventListeners) {
                    this.showEvent.subscribe(this.showIframe);
                    this.hideEvent.subscribe(this.hideIframe);
                    this.changeContentEvent.subscribe(this.syncIframe);

                    this._hasIframeEventListeners = true;
                }
            }

            function onBeforeShow() {
                createIFrame.call(this);
                this.beforeShowEvent.unsubscribe(onBeforeShow);
                this._iframeDeferred = false;
            }

            if (bIFrame) { // <iframe> shim is enabled

                if (this.cfg.getProperty("visible")) {
                    createIFrame.call(this);
                } else {
                    if (!this._iframeDeferred) {
                        this.beforeShowEvent.subscribe(onBeforeShow);
                        this._iframeDeferred = true;
                    }
                }

            } else {    // <iframe> shim is disabled
                this.hideIframe();

                if (this._hasIframeEventListeners) {
                    this.showEvent.unsubscribe(this.showIframe);
                    this.hideEvent.unsubscribe(this.hideIframe);
                    this.changeContentEvent.unsubscribe(this.syncIframe);

                    this._hasIframeEventListeners = false;
                }
            }
        },

        /**
         * Set's the container's XY value from DOM if not already set.
         * 
         * Differs from syncPosition, in that the XY value is only sync'd with DOM if 
         * not already set. The method also refire's the XY config property event, so any
         * beforeMove, Move event listeners are invoked.
         * 
         * @method _primeXYFromDOM
         * @protected
         */
        _primeXYFromDOM : function() {
            if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
                // Set CFG XY based on DOM XY
                this.syncPosition();
                // Account for XY being set silently in syncPosition (no moveTo fired/called)
                this.cfg.refireEvent("xy");
                this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
            }
        },

        /**
        * The default event handler fired when the "constraintoviewport" 
        * property is changed.
        * @method configConstrainToViewport
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for 
        * the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configConstrainToViewport: function (type, args, obj) {
            var val = args[0];

            if (val) {
                if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
                    this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
                }
                if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
                    this.beforeShowEvent.subscribe(this._primeXYFromDOM);
                }
            } else {
                this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
                this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
            }
        },

         /**
        * The default event handler fired when the "context" property 
        * is changed.
        * @method configContext
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configContext: function (type, args, obj) {
    
            var contextArgs = args[0],
                contextEl,
                elementMagnetCorner,
                contextMagnetCorner;

            if (contextArgs) {
                contextEl = contextArgs[0];
                elementMagnetCorner = contextArgs[1];
                contextMagnetCorner = contextArgs[2];
                
                if (contextEl) {
                    if (typeof contextEl == "string") {
                        this.cfg.setProperty("context", 
                            [document.getElementById(contextEl), 
                                elementMagnetCorner, contextMagnetCorner], 
                                true);
                    }
                    
                    if (elementMagnetCorner && contextMagnetCorner) {
                        this.align(elementMagnetCorner, contextMagnetCorner);
                    }
                }
            }
        },

        // END BUILT-IN PROPERTY EVENT HANDLERS //
        /**
        * Aligns the Overlay to its context element using the specified corner 
        * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, 
        * and BOTTOM_RIGHT.
        * @method align
        * @param {String} elementAlign  The String representing the corner of 
        * the Overlay that should be aligned to the context element
        * @param {String} contextAlign  The corner of the context element 
        * that the elementAlign corner should stick to.
        */
        align: function (elementAlign, contextAlign) {

            var contextArgs = this.cfg.getProperty("context"),
                me = this,
                context,
                element,
                contextRegion;

            function doAlign(v, h) {
    
                switch (elementAlign) {
    
                case Overlay.TOP_LEFT:
                    me.moveTo(h, v);
                    break;
    
                case Overlay.TOP_RIGHT:
                    me.moveTo((h - element.offsetWidth), v);
                    break;
    
                case Overlay.BOTTOM_LEFT:
                    me.moveTo(h, (v - element.offsetHeight));
                    break;
    
                case Overlay.BOTTOM_RIGHT:
                    me.moveTo((h - element.offsetWidth), 
                        (v - element.offsetHeight));
                    break;
                }
            }
    
    
            if (contextArgs) {
            
                context = contextArgs[0];
                element = this.element;
                me = this;
                
                if (! elementAlign) {
                    elementAlign = contextArgs[1];
                }
                
                if (! contextAlign) {
                    contextAlign = contextArgs[2];
                }
                
                if (element && context) {
                    contextRegion = Dom.getRegion(context);

                    switch (contextAlign) {
    
                    case Overlay.TOP_LEFT:
                        doAlign(contextRegion.top, contextRegion.left);
                        break;
    
                    case Overlay.TOP_RIGHT:
                        doAlign(contextRegion.top, contextRegion.right);
                        break;
    
                    case Overlay.BOTTOM_LEFT:
                        doAlign(contextRegion.bottom, contextRegion.left);
                        break;
    
                    case Overlay.BOTTOM_RIGHT:
                        doAlign(contextRegion.bottom, contextRegion.right);
                        break;
                    }
    
                }
    
            }
            
        },

        /**
        * The default event handler executed when the moveEvent is fired, if the 
        * "constraintoviewport" is set to true.
        * @method enforceConstraints
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        enforceConstraints: function (type, args, obj) {
            var pos = args[0];
            var cXY = this.getConstrainedXY(pos[0], pos[1]);
            this.cfg.setProperty("x", cXY[0], true);
            this.cfg.setProperty("y", cXY[1], true);
            this.cfg.setProperty("xy", cXY, true);
        },

        /**
         * Given x, y coordinate values, returns the calculated coordinates required to 
         * position the Overlay if it is to be constrained to the viewport, based on the 
         * current element size, viewport dimensions and scroll values.
         *
         * @param {Number} x The X coordinate value to be constrained
         * @param {Number} y The Y coordinate value to be constrained
         * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
         */
        getConstrainedXY: function(x, y) {

            var nViewportOffset = Overlay.VIEWPORT_OFFSET,
                viewPortWidth = Dom.getViewportWidth(),
                viewPortHeight = Dom.getViewportHeight(),
                offsetHeight = this.element.offsetHeight,
                offsetWidth = this.element.offsetWidth,
                scrollX = Dom.getDocumentScrollLeft(),
                scrollY = Dom.getDocumentScrollTop();

            var xNew = x;
            var yNew = y;

            if (offsetWidth + nViewportOffset < viewPortWidth) {

                var leftConstraint = scrollX + nViewportOffset;
                var rightConstraint = scrollX + viewPortWidth - offsetWidth - nViewportOffset;

                if (x < leftConstraint) {
                    xNew = leftConstraint;
                } else if (x > rightConstraint) {
                    xNew = rightConstraint;
                }
            } else {
                xNew = nViewportOffset + scrollX;
            }

            if (offsetHeight + nViewportOffset < viewPortHeight) {

                var topConstraint = scrollY + nViewportOffset;
                var bottomConstraint = scrollY + viewPortHeight - offsetHeight - nViewportOffset;

                if (y < topConstraint) {
                    yNew  = topConstraint;
                } else if (y  > bottomConstraint) {
                    yNew  = bottomConstraint;
                }
            } else {
                yNew = nViewportOffset + scrollY;
            }

            return [xNew, yNew];
        },

        /**
        * Centers the container in the viewport.
        * @method center
        */
        center: function () {

            var nViewportOffset = Overlay.VIEWPORT_OFFSET,
                elementWidth = this.element.offsetWidth,
                elementHeight = this.element.offsetHeight,
                viewPortWidth = Dom.getViewportWidth(),
                viewPortHeight = Dom.getViewportHeight(),
                x,
                y;

            if (elementWidth < viewPortWidth) {
                x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
            } else {
                x = nViewportOffset + Dom.getDocumentScrollLeft();
            }

            if (elementHeight < viewPortHeight) {
                y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
            } else {
                y = nViewportOffset + Dom.getDocumentScrollTop();
            }

            this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
            this.cfg.refireEvent("iframe");
        },

        /**
        * Synchronizes the Panel's "xy", "x", and "y" properties with the 
        * Panel's position in the DOM. This is primarily used to update  
        * position information during drag & drop.
        * @method syncPosition
        */
        syncPosition: function () {

            var pos = Dom.getXY(this.element);

            this.cfg.setProperty("x", pos[0], true);
            this.cfg.setProperty("y", pos[1], true);
            this.cfg.setProperty("xy", pos, true);

        },

        /**
        * Event handler fired when the resize monitor element is resized.
        * @method onDomResize
        * @param {DOMEvent} e The resize DOM event
        * @param {Object} obj The scope object
        */
        onDomResize: function (e, obj) {

            var me = this;

            Overlay.superclass.onDomResize.call(this, e, obj);

            setTimeout(function () {
                me.syncPosition();
                me.cfg.refireEvent("iframe");
                me.cfg.refireEvent("context");
            }, 0);
    
        },

        /**
        * Places the Overlay on top of all other instances of 
        * YAHOO.widget.Overlay.
        * @method bringToTop
        */
        bringToTop: function () {

            var aOverlays = [],
                oElement = this.element;

            function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {

                var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
                    sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),

                    nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
                    nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);

                if (nZIndex1 > nZIndex2) {
                    return -1;
                } else if (nZIndex1 < nZIndex2) {
                    return 1;
                } else {
                    return 0;
                }
            }

            function isOverlayElement(p_oElement) {

                var oOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
                    Panel = YAHOO.widget.Panel;

                if (oOverlay && !Dom.isAncestor(oElement, oOverlay)) {
                    if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
                        aOverlays[aOverlays.length] = p_oElement.parentNode;
                    } else {
                        aOverlays[aOverlays.length] = p_oElement;
                    }
                }
            }

            Dom.getElementsBy(isOverlayElement, "DIV", document.body);

            aOverlays.sort(compareZIndexDesc);

            var oTopOverlay = aOverlays[0],
                nTopZIndex;

            if (oTopOverlay) {
                nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");

                if (!isNaN(nTopZIndex)) {
                    var bRequiresBump = false;

                    if (oTopOverlay != oElement) {
                        bRequiresBump = true;
                    } else if (aOverlays.length > 1) {
                        var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
                        // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
                        if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
                            bRequiresBump = true;
                        }
                    }
                    if (bRequiresBump) {
                        this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
                    }
                }
            }
        },

        /**
        * Removes the Overlay element from the DOM and sets all child 
        * elements to null.
        * @method destroy
        */
        destroy: function () {

            if (this.iframe) {
                this.iframe.parentNode.removeChild(this.iframe);
            }

            this.iframe = null;
        
            Overlay.windowResizeEvent.unsubscribe(
                this.doCenterOnDOMEvent, this);
    
            Overlay.windowScrollEvent.unsubscribe(
                this.doCenterOnDOMEvent, this);
        
            Overlay.superclass.destroy.call(this);
        },
        
        /**
        * Returns a String representation of the object.
        * @method toString
        * @return {String} The string representation of the Overlay.
        */
        toString: function () {
            return "Overlay " + this.id;
        }

    });
}());

(function () {
    
    /**
    * OverlayManager is used for maintaining the focus status of 
    * multiple Overlays.
    * @namespace YAHOO.widget
    * @namespace YAHOO.widget
    * @class OverlayManager
    * @constructor
    * @param {Array} overlays Optional. A collection of Overlays to register 
    * with the manager.
    * @param {Object} userConfig  The object literal representing the user 
    * configuration of the OverlayManager
    */
    YAHOO.widget.OverlayManager = function (userConfig) {
        this.init(userConfig);
    };

    var Overlay = YAHOO.widget.Overlay,
        Event = YAHOO.util.Event,
        Dom = YAHOO.util.Dom,
        Config = YAHOO.util.Config,
        CustomEvent = YAHOO.util.CustomEvent,
        OverlayManager = YAHOO.widget.OverlayManager;
    
    /**
    * The CSS class representing a focused Overlay
    * @property OverlayManager.CSS_FOCUSED
    * @static
    * @final
    * @type String
    */
    OverlayManager.CSS_FOCUSED = "focused";
    
    OverlayManager.prototype = {
    
        /**
        * The class's constructor function
        * @property contructor
        * @type Function
        */
        constructor: OverlayManager,
        
        /**
        * The array of Overlays that are currently registered
        * @property overlays
        * @type YAHOO.widget.Overlay[]
        */
        overlays: null,
        
        /**
        * Initializes the default configuration of the OverlayManager
        * @method initDefaultConfig
        */
        initDefaultConfig: function () {
        
            /**
            * The collection of registered Overlays in use by 
            * the OverlayManager
            * @config overlays
            * @type YAHOO.widget.Overlay[]
            * @default null
            */
            this.cfg.addProperty("overlays", { suppressEvent: true } );
        
            /**
            * The default DOM event that should be used to focus an Overlay
            * @config focusevent
            * @type String
            * @default "mousedown"
            */
            this.cfg.addProperty("focusevent", { value: "mousedown" } );

        },

        /**
        * Initializes the OverlayManager
        * @method init
        * @param {Overlay[]} overlays Optional. A collection of Overlays to 
        * register with the manager.
        * @param {Object} userConfig  The object literal representing the user 
        * configuration of the OverlayManager
        */
        init: function (userConfig) {

            /**
            * The OverlayManager's Config object used for monitoring 
            * configuration properties.
            * @property cfg
            * @type Config
            */
            this.cfg = new Config(this);

            this.initDefaultConfig();

            if (userConfig) {
                this.cfg.applyConfig(userConfig, true);
            }
            this.cfg.fireQueue();

            /**
            * The currently activated Overlay
            * @property activeOverlay
            * @private
            * @type YAHOO.widget.Overlay
            */
            var activeOverlay = null;

            /**
            * Returns the currently focused Overlay
            * @method getActive
            * @return {Overlay} The currently focused Overlay
            */
            this.getActive = function () {
                return activeOverlay;
            };

            /**
            * Focuses the specified Overlay
            * @method focus
            * @param {Overlay} overlay The Overlay to focus
            * @param {String} overlay The id of the Overlay to focus
            */
            this.focus = function (overlay) {
                var o = this.find(overlay);
                if (o) {
                    if (activeOverlay != o) {
                        if (activeOverlay) {
                            activeOverlay.blur();
                        }
                        this.bringToTop(o);

                        activeOverlay = o;

                        Dom.addClass(activeOverlay.element, 
                            OverlayManager.CSS_FOCUSED);

                        o.focusEvent.fire();
                    }
                }
            };
        
            /**
            * Removes the specified Overlay from the manager
            * @method remove
            * @param {Overlay} overlay The Overlay to remove
            * @param {String} overlay The id of the Overlay to remove
            */
            this.remove = function (overlay) {
                var o = this.find(overlay), 
                        originalZ;
                if (o) {
                    if (activeOverlay == o) {
                        activeOverlay = null;
                    }

                    var bDestroyed = (o.element === null && o.cfg === null) ? true : false;

                    if (!bDestroyed) {
                        // Set it's zindex so that it's sorted to the end.
                        originalZ = Dom.getStyle(o.element, "zIndex");
                        o.cfg.setProperty("zIndex", -1000, true);
                    }

                    this.overlays.sort(this.compareZIndexDesc);
                    this.overlays = this.overlays.slice(0, (this.overlays.length - 1));

                    o.hideEvent.unsubscribe(o.blur);
                    o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);

                    if (!bDestroyed) {
                        Event.removeListener(o.element, 
                                    this.cfg.getProperty("focusevent"), 
                                    this._onOverlayElementFocus);

                        o.cfg.setProperty("zIndex", originalZ, true);
                        o.cfg.setProperty("manager", null);
                    }

                    o.focusEvent.unsubscribeAll();
                    o.blurEvent.unsubscribeAll();

                    o.focusEvent = null;
                    o.blurEvent = null;

                    o.focus = null;
                    o.blur = null;
                }
            };

            /**
            * Removes focus from all registered Overlays in the manager
            * @method blurAll
            */
            this.blurAll = function () {
    
                var nOverlays = this.overlays.length,
                    i;

                if (nOverlays > 0) {
                    i = nOverlays - 1;

                    do {
                        this.overlays[i].blur();
                    }
                    while(i--);
                }
            };
        
            this._onOverlayBlur = function (p_sType, p_aArgs) {
                activeOverlay = null;
            };
        
            var overlays = this.cfg.getProperty("overlays");
        
            if (! this.overlays) {
                this.overlays = [];
            }
        
            if (overlays) {
                this.register(overlays);
                this.overlays.sort(this.compareZIndexDesc);
            }
        },
        
        
        /**
        * @method _onOverlayElementFocus
        * @description Event handler for the DOM event that is used to focus 
        * the Overlay instance as specified by the "focusevent" 
        * configuration property.
        * @private
        * @param {Event} p_oEvent Object representing the DOM event 
        * object passed back by the event utility (Event).
        */
        _onOverlayElementFocus: function (p_oEvent) {
        
            var oTarget = Event.getTarget(p_oEvent),
                oClose = this.close;
            
            if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
                this.blur();
            } else {
                this.focus();
            }
        },
        
        
        /**
        * @method _onOverlayDestroy
        * @description "destroy" event handler for the Overlay.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        * @param {Overlay} p_oOverlay Object representing the menu that 
        * fired the event.
        */
        _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
            this.remove(p_oOverlay);
        },
        
        /**
        * Registers an Overlay or an array of Overlays with the manager. Upon 
        * registration, the Overlay receives functions for focus and blur, 
        * along with CustomEvents for each.
        * @method register
        * @param {Overlay} overlay  An Overlay to register with the manager.
        * @param {Overlay[]} overlay  An array of Overlays to register with 
        * the manager.
        * @return {Boolean} True if any Overlays are registered.
        */
        register: function (overlay) {
        
            var mgr = this,
                zIndex,
                regcount,
                i,
                nOverlays;
        
            if (overlay instanceof Overlay) {

                overlay.cfg.addProperty("manager", { value: this } );

                overlay.focusEvent = overlay.createEvent("focus");
                overlay.focusEvent.signature = CustomEvent.LIST;

                overlay.blurEvent = overlay.createEvent("blur");
                overlay.blurEvent.signature = CustomEvent.LIST;
        
                overlay.focus = function () {
                    mgr.focus(this);
                };
        
                overlay.blur = function () {
                    if (mgr.getActive() == this) {
                        Dom.removeClass(this.element, OverlayManager.CSS_FOCUSED);
                        this.blurEvent.fire();
                    }
                };
        
                overlay.blurEvent.subscribe(mgr._onOverlayBlur);
                overlay.hideEvent.subscribe(overlay.blur);
                
                overlay.destroyEvent.subscribe(this._onOverlayDestroy, overlay, this);
        
                Event.on(overlay.element, this.cfg.getProperty("focusevent"), 
                            this._onOverlayElementFocus, null, overlay);
        
                zIndex = Dom.getStyle(overlay.element, "zIndex");

                if (!isNaN(zIndex)) {
                    overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
                } else {
                    overlay.cfg.setProperty("zIndex", 0);
                }

                this.overlays.push(overlay);
                this.bringToTop(overlay);

                return true;

            } else if (overlay instanceof Array) {

                regcount = 0;
                nOverlays = overlay.length;

                for (i = 0; i < nOverlays; i++) {
                    if (this.register(overlay[i])) {
                        regcount++;
                    }
                }

                if (regcount > 0) {
                    return true;
                }
            } else {
                return false;
            }
        },

        /**
        * Places the specified Overlay instance on top of all other 
        * Overlay instances.
        * @method bringToTop
        * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an 
        * Overlay instance.
        * @param {String} p_oOverlay String representing the id of an 
        * Overlay instance.
        */        
        bringToTop: function (p_oOverlay) {

            var oOverlay = this.find(p_oOverlay),
                nTopZIndex,
                oTopOverlay,
                aOverlays;

            if (oOverlay) {

                aOverlays = this.overlays;
                aOverlays.sort(this.compareZIndexDesc);

                oTopOverlay = aOverlays[0];

                if (oTopOverlay) {
                    nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");

                    if (!isNaN(nTopZIndex)) {

                        var bRequiresBump = false;

                        if (oTopOverlay !== oOverlay) {
                            bRequiresBump = true;
                        } else if (aOverlays.length > 1) {
                            var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
                            // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
                            if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
                                bRequiresBump = true;
                            }
                        }

                        if (bRequiresBump) {
                            oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
                        }
                    }
                    aOverlays.sort(this.compareZIndexDesc);
                }
            }
        },

        /**
        * Attempts to locate an Overlay by instance or ID.
        * @method find
        * @param {Overlay} overlay  An Overlay to locate within the manager
        * @param {String} overlay  An Overlay id to locate within the manager
        * @return {Overlay} The requested Overlay, if found, or null if it 
        * cannot be located.
        */
        find: function (overlay) {

            var aOverlays = this.overlays,
                nOverlays = aOverlays.length,
                i;

            if (nOverlays > 0) {
                i = nOverlays - 1;

                if (overlay instanceof Overlay) {
                    do {
                        if (aOverlays[i] == overlay) {
                            return aOverlays[i];
                        }
                    }
                    while(i--);

                } else if (typeof overlay == "string") {
                    do {
                        if (aOverlays[i].id == overlay) {
                            return aOverlays[i];
                        }
                    }
                    while(i--);
                }
                return null;
            }
        },
        
        /**
        * Used for sorting the manager's Overlays by z-index.
        * @method compareZIndexDesc
        * @private
        * @return {Number} 0, 1, or -1, depending on where the Overlay should 
        * fall in the stacking order.
        */
        compareZIndexDesc: function (o1, o2) {

            var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
                zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.

            if (zIndex1 === null && zIndex2 === null) {
                return 0;
            } else if (zIndex1 === null){
                return 1;
            } else if (zIndex2 === null) {
                return -1;
            } else if (zIndex1 > zIndex2) {
                return -1;
            } else if (zIndex1 < zIndex2) {
                return 1;
            } else {
                return 0;
            }
        },
        
        /**
        * Shows all Overlays in the manager.
        * @method showAll
        */
        showAll: function () {
        
            var aOverlays = this.overlays,
                nOverlays = aOverlays.length,
                i;

            if (nOverlays > 0) {
                i = nOverlays - 1;
                do {
                    aOverlays[i].show();
                }
                while(i--);
            }
        },

        /**
        * Hides all Overlays in the manager.
        * @method hideAll
        */
        hideAll: function () {
        
            var aOverlays = this.overlays,
                nOverlays = aOverlays.length,
                i;

            if (nOverlays > 0) {
                i = nOverlays - 1;
                do {
                    aOverlays[i].hide();
                }
                while(i--);
            }
        },

        /**
        * Returns a string representation of the object.
        * @method toString
        * @return {String} The string representation of the OverlayManager
        */
        toString: function () {
            return "OverlayManager";
        }
    };

}());

(function () {

    /**
    * Tooltip is an implementation of Overlay that behaves like an OS tooltip, 
    * displaying when the user mouses over a particular element, and 
    * disappearing on mouse out.
    * @namespace YAHOO.widget
    * @class Tooltip
    * @extends YAHOO.widget.Overlay
    * @constructor
    * @param {String} el The element ID representing the Tooltip <em>OR</em>
    * @param {HTMLElement} el The element representing the Tooltip
    * @param {Object} userConfig The configuration object literal containing 
    * the configuration that should be set for this Overlay. See configuration 
    * documentation for more details.
    */
    YAHOO.widget.Tooltip = function (el, userConfig) {
        YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
    };

    var Lang = YAHOO.lang,
        Event = YAHOO.util.Event,
        CustomEvent = YAHOO.util.CustomEvent,
        Dom = YAHOO.util.Dom,
        Tooltip = YAHOO.widget.Tooltip,

        m_oShadowTemplate,

        /**
        * Constant representing the Tooltip's configuration properties
        * @property DEFAULT_CONFIG
        * @private
        * @final
        * @type Object
        */
        DEFAULT_CONFIG = {

            "PREVENT_OVERLAP": { 
                key: "preventoverlap", 
                value: true, 
                validator: Lang.isBoolean, 
                supercedes: ["x", "y", "xy"] 
            },

            "SHOW_DELAY": { 
                key: "showdelay", 
                value: 200, 
                validator: Lang.isNumber 
            }, 

            "AUTO_DISMISS_DELAY": { 
                key: "autodismissdelay", 
                value: 5000, 
                validator: Lang.isNumber 
            }, 

            "HIDE_DELAY": { 
                key: "hidedelay", 
                value: 250, 
                validator: Lang.isNumber 
            }, 

            "TEXT": { 
                key: "text", 
                suppressEvent: true 
            }, 

            "CONTAINER": { 
                key: "container"
            },

            "DISABLED": {
                key: "disabled",
                value: false,
                suppressEvent: true
            }
        },

        /**
        * Constant representing the name of the Tooltip's events
        * @property EVENT_TYPES
        * @private
        * @final
        * @type Object
        */
        EVENT_TYPES = {
            "CONTEXT_MOUSE_OVER": "contextMouseOver",
            "CONTEXT_MOUSE_OUT": "contextMouseOut",
            "CONTEXT_TRIGGER": "contextTrigger"
        };

    /**
    * Constant representing the Tooltip CSS class
    * @property YAHOO.widget.Tooltip.CSS_TOOLTIP
    * @static
    * @final
    * @type String
    */
    Tooltip.CSS_TOOLTIP = "yui-tt";

    /* 
        "hide" event handler that sets a Tooltip instance's "width"
        configuration property back to its original value before 
        "setWidthToOffsetWidth" was called.
    */
    function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {

        var sOriginalWidth = p_oObject[0],
            sNewWidth = p_oObject[1],
            oConfig = this.cfg,
            sCurrentWidth = oConfig.getProperty("width");

        if (sCurrentWidth == sNewWidth) {
            oConfig.setProperty("width", sOriginalWidth);
        }

        this.unsubscribe("hide", this._onHide, p_oObject);
    }

    /* 
        "beforeShow" event handler that sets a Tooltip instance's "width"
        configuration property to the value of its root HTML 
        elements's offsetWidth
    */

    function setWidthToOffsetWidth(p_sType, p_aArgs) {

        var oBody = document.body,
            oConfig = this.cfg,
            sOriginalWidth = oConfig.getProperty("width"),
            sNewWidth,
            oClone;

        if ((!sOriginalWidth || sOriginalWidth == "auto") && 
            (oConfig.getProperty("container") != oBody || 
            oConfig.getProperty("x") >= Dom.getViewportWidth() || 
            oConfig.getProperty("y") >= Dom.getViewportHeight())) {

            oClone = this.element.cloneNode(true);
            oClone.style.visibility = "hidden";
            oClone.style.top = "0px";
            oClone.style.left = "0px";

            oBody.appendChild(oClone);

            sNewWidth = (oClone.offsetWidth + "px");

            oBody.removeChild(oClone);
            oClone = null;

            oConfig.setProperty("width", sNewWidth);
            oConfig.refireEvent("xy");

            this.subscribe("hide", restoreOriginalWidth, [(sOriginalWidth || ""), sNewWidth]);
        }
    }

    // "onDOMReady" that renders the ToolTip

    function onDOMReady(p_sType, p_aArgs, p_oObject) {
        this.render(p_oObject);
    }

    //  "init" event handler that automatically renders the Tooltip

    function onInit() {
        Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
    }

    YAHOO.extend(Tooltip, YAHOO.widget.Overlay, { 

        /**
        * The Tooltip initialization method. This method is automatically 
        * called by the constructor. A Tooltip is automatically rendered by 
        * the init method, and it also is set to be invisible by default, 
        * and constrained to viewport by default as well.
        * @method init
        * @param {String} el The element ID representing the Tooltip <em>OR</em>
        * @param {HTMLElement} el The element representing the Tooltip
        * @param {Object} userConfig The configuration object literal 
        * containing the configuration that should be set for this Tooltip. 
        * See configuration documentation for more details.
        */
        init: function (el, userConfig) {


            Tooltip.superclass.init.call(this, el);

            this.beforeInitEvent.fire(Tooltip);

            Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);

            if (userConfig) {
                this.cfg.applyConfig(userConfig, true);
            }

            this.cfg.queueProperty("visible", false);
            this.cfg.queueProperty("constraintoviewport", true);

            this.setBody("");

            this.subscribe("beforeShow", setWidthToOffsetWidth);
            this.subscribe("init", onInit);
            this.subscribe("render", this.onRender);

            this.initEvent.fire(Tooltip);
        },

        /**
        * Initializes the custom events for Tooltip
        * @method initEvents
        */
        initEvents: function () {

            Tooltip.superclass.initEvents.call(this);
            var SIGNATURE = CustomEvent.LIST;

            /**
            * CustomEvent fired when user mouses over a context element. Returning false from
            * a subscriber to this event will prevent the tooltip from being displayed for
            * the current context element.
            * 
            * @event contextMouseOverEvent
            * @param {HTMLElement} context The context element which the user just moused over
            * @param {DOMEvent} e The DOM event object, associated with the mouse over
            */
            this.contextMouseOverEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OVER);
            this.contextMouseOverEvent.signature = SIGNATURE;

            /**
            * CustomEvent fired when the user mouses out of a context element.
            * 
            * @event contextMouseOutEvent
            * @param {HTMLElement} context The context element which the user just moused out of
            * @param {DOMEvent} e The DOM event object, associated with the mouse out
            */
            this.contextMouseOutEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OUT);
            this.contextMouseOutEvent.signature = SIGNATURE;

            /**
            * CustomEvent fired just before the tooltip is displayed for the current context.
            * <p>
            *  You can subscribe to this event if you need to set up the text for the 
            *  tooltip based on the context element for which it is about to be displayed.
            * </p>
            * <p>This event differs from the beforeShow event in following respects:</p>
            * <ol>
            *   <li>
            *    When moving from one context element to another, if the tooltip is not
            *    hidden (the <code>hidedelay</code> is not reached), the beforeShow and Show events will not
            *    be fired when the tooltip is displayed for the new context since it is already visible.
            *    However the contextTrigger event is always fired before displaying the tooltip for
            *    a new context.
            *   </li>
            *   <li>
            *    The trigger event provides access to the context element, allowing you to 
            *    set the text of the tooltip based on context element for which the tooltip is
            *    triggered.
            *   </li>
            * </ol>
            * <p>
            *  It is not possible to prevent the tooltip from being displayed
            *  using this event. You can use the contextMouseOverEvent if you need to prevent
            *  the tooltip from being displayed.
            * </p>
            * @event contextTriggerEvent
            * @param {HTMLElement} context The context element for which the tooltip is triggered
            */
            this.contextTriggerEvent = this.createEvent(EVENT_TYPES.CONTEXT_TRIGGER);
            this.contextTriggerEvent.signature = SIGNATURE;
        },

        /**
        * Initializes the class's configurable properties which can be 
        * changed using the Overlay's Config object (cfg).
        * @method initDefaultConfig
        */
        initDefaultConfig: function () {

            Tooltip.superclass.initDefaultConfig.call(this);

            /**
            * Specifies whether the Tooltip should be kept from overlapping 
            * its context element.
            * @config preventoverlap
            * @type Boolean
            * @default true
            */
            this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
                value: DEFAULT_CONFIG.PREVENT_OVERLAP.value, 
                validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator, 
                supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
            });

            /**
            * The number of milliseconds to wait before showing a Tooltip 
            * on mouseover.
            * @config showdelay
            * @type Number
            * @default 200
            */
            this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
                handler: this.configShowDelay,
                value: 200, 
                validator: DEFAULT_CONFIG.SHOW_DELAY.validator
            });

            /**
            * The number of milliseconds to wait before automatically 
            * dismissing a Tooltip after the mouse has been resting on the 
            * context element.
            * @config autodismissdelay
            * @type Number
            * @default 5000
            */
            this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
                handler: this.configAutoDismissDelay,
                value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
                validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
            });

            /**
            * The number of milliseconds to wait before hiding a Tooltip 
            * on mouseover.
            * @config hidedelay
            * @type Number
            * @default 250
            */
            this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
                handler: this.configHideDelay,
                value: DEFAULT_CONFIG.HIDE_DELAY.value, 
                validator: DEFAULT_CONFIG.HIDE_DELAY.validator
            });

            /**
            * Specifies the Tooltip's text. 
            * @config text
            * @type String
            * @default null
            */
            this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
                handler: this.configText,
                suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
            });

            /**
            * Specifies the container element that the Tooltip's markup 
            * should be rendered into.
            * @config container
            * @type HTMLElement/String
            * @default document.body
            */
            this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
                handler: this.configContainer,
                value: document.body
            });

            /**
            * Specifies whether or not the tooltip is disabled. Disabled tooltips
            * will not be displayed. If the tooltip is driven by the title attribute
            * of the context element, the title attribute will still be removed for 
            * disabled tooltips, to prevent default tooltip behavior.
            * 
            * @config disabled
            * @type Boolean
            * @default false
            */
            this.cfg.addProperty(DEFAULT_CONFIG.DISABLED.key, {
                handler: this.configContainer,
                value: DEFAULT_CONFIG.DISABLED.value,
                supressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
            });

            /**
            * Specifies the element or elements that the Tooltip should be 
            * anchored to on mouseover.
            * @config context
            * @type HTMLElement[]/String[]
            * @default null
            */ 

            /**
            * String representing the width of the Tooltip.  <em>Please note:
            * </em> As of version 2.3 if either no value or a value of "auto" 
            * is specified, and the Toolip's "container" configuration property
            * is set to something other than <code>document.body</code> or 
            * its "context" element resides outside the immediately visible 
            * portion of the document, the width of the Tooltip will be 
            * calculated based on the offsetWidth of its root HTML and set just 
            * before it is made visible.  The original value will be 
            * restored when the Tooltip is hidden. This ensures the Tooltip is 
            * rendered at a usable width.  For more information see 
            * SourceForge bug #1685496 and SourceForge 
            * bug #1735423.
            * @config width
            * @type String
            * @default null
            */
        
        },
        
        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
        
        /**
        * The default event handler fired when the "text" property is changed.
        * @method configText
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configText: function (type, args, obj) {
            var text = args[0];
            if (text) {
                this.setBody(text);
            }
        },
        
        /**
        * The default event handler fired when the "container" property 
        * is changed.
        * @method configContainer
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For 
        * configuration handlers, args[0] will equal the newly applied value 
        * for the property.
        * @param {Object} obj The scope object. For configuration handlers,
        * this will usually equal the owner.
        */
        configContainer: function (type, args, obj) {
            var container = args[0];

            if (typeof container == 'string') {
                this.cfg.setProperty("container", document.getElementById(container), true);
            }
        },
        
        /**
        * @method _removeEventListeners
        * @description Removes all of the DOM event handlers from the HTML
        *  element(s) that trigger the display of the tooltip.
        * @protected
        */
        _removeEventListeners: function () {
        
            var aElements = this._context,
                nElements,
                oElement,
                i;

            if (aElements) {
                nElements = aElements.length;
                if (nElements > 0) {
                    i = nElements - 1;
                    do {
                        oElement = aElements[i];
                        Event.removeListener(oElement, "mouseover", this.onContextMouseOver);
                        Event.removeListener(oElement, "mousemove", this.onContextMouseMove);
                        Event.removeListener(oElement, "mouseout", this.onContextMouseOut);
                    }
                    while (i--);
                }
            }
        },
        
        /**
        * The default event handler fired when the "context" property 
        * is changed.
        * @method configContext
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers,
        * this will usually equal the owner.
        */
        configContext: function (type, args, obj) {
        
            var context = args[0],
                aElements,
                nElements,
                oElement,
                i;

            if (context) {

                // Normalize parameter into an array
                if (! (context instanceof Array)) {
                    if (typeof context == "string") {
                        this.cfg.setProperty("context", [document.getElementById(context)], true);
                    } else { // Assuming this is an element
                        this.cfg.setProperty("context", [context], true);
                    }
                    context = this.cfg.getProperty("context");
                }

                // Remove any existing mouseover/mouseout listeners
                this._removeEventListeners();

                // Add mouseover/mouseout listeners to context elements
                this._context = context;

                aElements = this._context;

                if (aElements) {
                    nElements = aElements.length;
                    if (nElements > 0) {
                        i = nElements - 1;
                        do {
                            oElement = aElements[i];
                            Event.on(oElement, "mouseover", this.onContextMouseOver, this);
                            Event.on(oElement, "mousemove", this.onContextMouseMove, this);
                            Event.on(oElement, "mouseout", this.onContextMouseOut, this);
                        }
                        while (i--);
                    }
                }
            }
        },

        // END BUILT-IN PROPERTY EVENT HANDLERS //

        // BEGIN BUILT-IN DOM EVENT HANDLERS //

        /**
        * The default event handler fired when the user moves the mouse while 
        * over the context element.
        * @method onContextMouseMove
        * @param {DOMEvent} e The current DOM event
        * @param {Object} obj The object argument
        */
        onContextMouseMove: function (e, obj) {
            obj.pageX = Event.getPageX(e);
            obj.pageY = Event.getPageY(e);
        },

        /**
        * The default event handler fired when the user mouses over the 
        * context element.
        * @method onContextMouseOver
        * @param {DOMEvent} e The current DOM event
        * @param {Object} obj The object argument
        */
        onContextMouseOver: function (e, obj) {
            var context = this;

            if (context.title) {
                obj._tempTitle = context.title;
                context.title = "";
            }

            // Fire first, to honor disabled set in the listner
            if (obj.fireEvent("contextMouseOver", context, e) !== false 
                    && !obj.cfg.getProperty("disabled")) {

                // Stop the tooltip from being hidden (set on last mouseout)
                if (obj.hideProcId) {
                    clearTimeout(obj.hideProcId);
                    obj.hideProcId = null;
                }

                Event.on(context, "mousemove", obj.onContextMouseMove, obj);

                /**
                * The unique process ID associated with the thread responsible 
                * for showing the Tooltip.
                * @type int
                */
                obj.showProcId = obj.doShow(e, context);
            }
        },

        /**
        * The default event handler fired when the user mouses out of 
        * the context element.
        * @method onContextMouseOut
        * @param {DOMEvent} e The current DOM event
        * @param {Object} obj The object argument
        */
        onContextMouseOut: function (e, obj) {
            var el = this;

            if (obj._tempTitle) {
                el.title = obj._tempTitle;
                obj._tempTitle = null;
            }

            if (obj.showProcId) {
                clearTimeout(obj.showProcId);
                obj.showProcId = null;
            }

            if (obj.hideProcId) {
                clearTimeout(obj.hideProcId);
                obj.hideProcId = null;
            }

            obj.fireEvent("contextMouseOut", el, e);

            obj.hideProcId = setTimeout(function () {
                obj.hide();
            }, obj.cfg.getProperty("hidedelay"));
        },

        // END BUILT-IN DOM EVENT HANDLERS //

        /**
        * Processes the showing of the Tooltip by setting the timeout delay 
        * and offset of the Tooltip.
        * @method doShow
        * @param {DOMEvent} e The current DOM event
        * @return {Number} The process ID of the timeout function associated 
        * with doShow
        */
        doShow: function (e, context) {

            var yOffset = 25,
                me = this;

            if (YAHOO.env.ua.opera && context.tagName && 
                context.tagName.toUpperCase() == "A") {
                yOffset += 12;
            }

            return setTimeout(function () {

                var txt = me.cfg.getProperty("text");

                // title does not over-ride text
                if (me._tempTitle && (txt === "" || YAHOO.lang.isUndefined(txt) || YAHOO.lang.isNull(txt))) {
                    me.setBody(me._tempTitle);
                } else {
                    me.cfg.refireEvent("text");
                }

                me.moveTo(me.pageX, me.pageY + yOffset);

                if (me.cfg.getProperty("preventoverlap")) {
                    me.preventOverlap(me.pageX, me.pageY);
                }

                Event.removeListener(context, "mousemove", me.onContextMouseMove);

                me.contextTriggerEvent.fire(context);

                me.show();

                me.hideProcId = me.doHide();

            }, this.cfg.getProperty("showdelay"));
        },

        /**
        * Sets the timeout for the auto-dismiss delay, which by default is 5 
        * seconds, meaning that a tooltip will automatically dismiss itself 
        * after 5 seconds of being displayed.
        * @method doHide
        */
        doHide: function () {

            var me = this;


            return setTimeout(function () {

                me.hide();

            }, this.cfg.getProperty("autodismissdelay"));

        },
        
        /**
        * Fired when the Tooltip is moved, this event handler is used to 
        * prevent the Tooltip from overlapping with its context element.
        * @method preventOverlay
        * @param {Number} pageX The x coordinate position of the mouse pointer
        * @param {Number} pageY The y coordinate position of the mouse pointer
        */
        preventOverlap: function (pageX, pageY) {
        
            var height = this.element.offsetHeight,
                mousePoint = new YAHOO.util.Point(pageX, pageY),
                elementRegion = Dom.getRegion(this.element);
        
            elementRegion.top -= 5;
            elementRegion.left -= 5;
            elementRegion.right += 5;
            elementRegion.bottom += 5;
        
        
            if (elementRegion.contains(mousePoint)) {
                this.cfg.setProperty("y", (pageY - height - 5));
            }
        },


        /**
        * @method onRender
        * @description "render" event handler for the Tooltip.
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        */
        onRender: function (p_sType, p_aArgs) {
    
            function sizeShadow() {
    
                var oElement = this.element,
                    oShadow = this._shadow;
            
                if (oShadow) {
                    oShadow.style.width = (oElement.offsetWidth + 6) + "px";
                    oShadow.style.height = (oElement.offsetHeight + 1) + "px"; 
                }
            
            }

            function addShadowVisibleClass() {
                Dom.addClass(this._shadow, "yui-tt-shadow-visible");
            }
            

            function removeShadowVisibleClass() {
                Dom.removeClass(this._shadow, "yui-tt-shadow-visible");
            }

            function createShadow() {
    
                var oShadow = this._shadow,
                    oElement,
                    Module,
                    nIE,
                    me;
    
                if (!oShadow) {
    
                    oElement = this.element;
                    Module = YAHOO.widget.Module;
                    nIE = YAHOO.env.ua.ie;
                    me = this;

                    if (!m_oShadowTemplate) {
                        m_oShadowTemplate = document.createElement("div");
                        m_oShadowTemplate.className = "yui-tt-shadow";
                    }

                    oShadow = m_oShadowTemplate.cloneNode(false);

                    oElement.appendChild(oShadow);

                    this._shadow = oShadow;

                    addShadowVisibleClass.call(this);

                    this.subscribe("beforeShow", addShadowVisibleClass);
                    this.subscribe("beforeHide", removeShadowVisibleClass);

                    if (nIE == 6 || (nIE == 7 && document.compatMode == "BackCompat")) {
                        window.setTimeout(function () { 
                            sizeShadow.call(me); 
                        }, 0);
    
                        this.cfg.subscribeToConfigEvent("width", sizeShadow);
                        this.cfg.subscribeToConfigEvent("height", sizeShadow);
                        this.subscribe("changeContent", sizeShadow);

                        Module.textResizeEvent.subscribe(sizeShadow, this, true);
                        this.subscribe("destroy", function () {
                            Module.textResizeEvent.unsubscribe(sizeShadow, this);
                        });
                    }
                }
            }

            function onBeforeShow() {
                createShadow.call(this);
                this.unsubscribe("beforeShow", onBeforeShow);
            }

            if (this.cfg.getProperty("visible")) {
                createShadow.call(this);
            } else {
                this.subscribe("beforeShow", onBeforeShow);
            }
        
        },
        
        /**
        * Removes the Tooltip element from the DOM and sets all child 
        * elements to null.
        * @method destroy
        */
        destroy: function () {
        
            // Remove any existing mouseover/mouseout listeners
            this._removeEventListeners();

            Tooltip.superclass.destroy.call(this);  
        
        },
        
        /**
        * Returns a string representation of the object.
        * @method toString
        * @return {String} The string representation of the Tooltip
        */
        toString: function () {
            return "Tooltip " + this.id;
        }
    
    });

}());

(function () {

    /**
    * Panel is an implementation of Overlay that behaves like an OS window, 
    * with a draggable header and an optional close icon at the top right.
    * @namespace YAHOO.widget
    * @class Panel
    * @extends YAHOO.widget.Overlay
    * @constructor
    * @param {String} el The element ID representing the Panel <em>OR</em>
    * @param {HTMLElement} el The element representing the Panel
    * @param {Object} userConfig The configuration object literal containing 
    * the configuration that should be set for this Panel. See configuration 
    * documentation for more details.
    */
    YAHOO.widget.Panel = function (el, userConfig) {
        YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
    };

    var Lang = YAHOO.lang,
        DD = YAHOO.util.DD,
        Dom = YAHOO.util.Dom,
        Event = YAHOO.util.Event,
        Overlay = YAHOO.widget.Overlay,
        CustomEvent = YAHOO.util.CustomEvent,
        Config = YAHOO.util.Config,
        Panel = YAHOO.widget.Panel,

        m_oMaskTemplate,
        m_oUnderlayTemplate,
        m_oCloseIconTemplate,

        /**
        * Constant representing the name of the Panel's events
        * @property EVENT_TYPES
        * @private
        * @final
        * @type Object
        */
        EVENT_TYPES = {
            "SHOW_MASK": "showMask",
            "HIDE_MASK": "hideMask",
            "DRAG": "drag"
        },

        /**
        * Constant representing the Panel's configuration properties
        * @property DEFAULT_CONFIG
        * @private
        * @final
        * @type Object
        */
        DEFAULT_CONFIG = {

            "CLOSE": { 
                key: "close", 
                value: true, 
                validator: Lang.isBoolean, 
                supercedes: ["visible"] 
            },

            "DRAGGABLE": { 
                key: "draggable", 
                value: (DD ? true : false), 
                validator: Lang.isBoolean, 
                supercedes: ["visible"]  
            },

            "DRAG_ONLY" : {
                key: "dragonly",
                value: false,
                validator: Lang.isBoolean,
                supercedes: ["draggable"]
            },

            "UNDERLAY": { 
                key: "underlay", 
                value: "shadow", 
                supercedes: ["visible"] 
            },

            "MODAL": { 
                key: "modal", 
                value: false, 
                validator: Lang.isBoolean, 
                supercedes: ["visible", "zindex"]
            },

            "KEY_LISTENERS": {
                key: "keylisteners",
                suppressEvent: true,
                supercedes: ["visible"]
            }
        };

    /**
    * Constant representing the default CSS class used for a Panel
    * @property YAHOO.widget.Panel.CSS_PANEL
    * @static
    * @final
    * @type String
    */
    Panel.CSS_PANEL = "yui-panel";
    
    /**
    * Constant representing the default CSS class used for a Panel's 
    * wrapping container
    * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
    * @static
    * @final
    * @type String
    */
    Panel.CSS_PANEL_CONTAINER = "yui-panel-container";

    /**
     * Constant representing the default set of focusable elements 
     * on the pagewhich Modal Panels will prevent access to, when
     * the modal mask is displayed
     * 
     * @property YAHOO.widget.Panel.FOCUSABLE
     * @static
     * @type Array
     */
    Panel.FOCUSABLE = [
        "a",
        "button",
        "select",
        "textarea",
        "input"
    ];

    // Private CustomEvent listeners

    /* 
        "beforeRender" event handler that creates an empty header for a Panel 
        instance if its "draggable" configuration property is set to "true" 
        and no header has been created.
    */

    function createHeader(p_sType, p_aArgs) {
        if (!this.header && this.cfg.getProperty("draggable")) {
            this.setHeader("&#160;");
        }
    }

    /* 
        "hide" event handler that sets a Panel instance's "width"
        configuration property back to its original value before 
        "setWidthToOffsetWidth" was called.
    */
    
    function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {

        var sOriginalWidth = p_oObject[0],
            sNewWidth = p_oObject[1],
            oConfig = this.cfg,
            sCurrentWidth = oConfig.getProperty("width");

        if (sCurrentWidth == sNewWidth) {
            oConfig.setProperty("width", sOriginalWidth);
        }

        this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
    }

    /* 
        "beforeShow" event handler that sets a Panel instance's "width"
        configuration property to the value of its root HTML 
        elements's offsetWidth
    */

    function setWidthToOffsetWidth(p_sType, p_aArgs) {

        var nIE = YAHOO.env.ua.ie,
            oConfig,
            sOriginalWidth,
            sNewWidth;

        if (nIE == 6 || (nIE == 7 && document.compatMode == "BackCompat")) {

            oConfig = this.cfg;
            sOriginalWidth = oConfig.getProperty("width");
            
            if (!sOriginalWidth || sOriginalWidth == "auto") {
    
                sNewWidth = (this.element.offsetWidth + "px");
    
                oConfig.setProperty("width", sNewWidth);
                
                this.subscribe("hide", restoreOriginalWidth, 
                    [(sOriginalWidth || ""), sNewWidth]);
            
            }
        }
    }

    YAHOO.extend(Panel, Overlay, {

        /**
        * The Overlay initialization method, which is executed for Overlay and 
        * all of its subclasses. This method is automatically called by the 
        * constructor, and  sets up all DOM references for pre-existing markup, 
        * and creates required markup if it is not already present.
        * @method init
        * @param {String} el The element ID representing the Overlay <em>OR</em>
        * @param {HTMLElement} el The element representing the Overlay
        * @param {Object} userConfig The configuration object literal 
        * containing the configuration that should be set for this Overlay. 
        * See configuration documentation for more details.
        */
        init: function (el, userConfig) {
    
            /*
                 Note that we don't pass the user config in here yet because 
                 we only want it executed once, at the lowest subclass level
            */

            Panel.superclass.init.call(this, el/*, userConfig*/);  

            this.beforeInitEvent.fire(Panel);

            Dom.addClass(this.element, Panel.CSS_PANEL);

            this.buildWrapper();

            if (userConfig) {
                this.cfg.applyConfig(userConfig, true);
            }

            this.subscribe("showMask", this._addFocusHandlers);
            this.subscribe("hideMask", this._removeFocusHandlers);
            this.subscribe("beforeRender", createHeader);

            this.initEvent.fire(Panel);
        },

        /**
         * @method _onElementFocus 
         * @private
         * 
         * "focus" event handler for a focuable element. Used to automatically 
         * blur the element when it receives focus to ensure that a Panel 
         * instance's modality is not compromised.
         * 
         * @param {Event} e The DOM event object
         */
        _onElementFocus : function(e){
            this.blur();
        },

        /** 
         *  @method _addFocusHandlers
         *  @protected
         *  
         *  "showMask" event handler that adds a "focus" event handler to all
         *  focusable elements in the document to enforce a Panel instance's 
         *  modality from being compromised.
         *  
         *  @param p_sType {String} Custom event type
         *  @param p_aArgs {Array} Custom event arguments
         */
        _addFocusHandlers: function(p_sType, p_aArgs) {
            var me = this,
                focus = "focus",
                hidden = "hidden";

            function isFocusable(el) {
                // NOTE: if e.type is undefined that's fine, want to avoid perf 
                // impact of tagName check to filter for inputs
                if (el.type !== hidden && !Dom.isAncestor(me.element, el)) {
                    Event.on(el, focus, me._onElementFocus);
                    return true;
                }
                return false;
            }

            var focusable = Panel.FOCUSABLE,
                l = focusable.length,
                arr = [];

            for (var i = 0; i < l; i++) {
                arr = arr.concat(Dom.getElementsBy(isFocusable, focusable[i]));
            }

            this.focusableElements = arr;
        },

        /** 
         *  @method _removeFocusHandlers
         *  @protected
         *  
         *  "hideMask" event handler that removes all "focus" event handlers added 
         *  by the "addFocusEventHandlers" method.
         *  
         *  @param p_sType {String} Event type
         *  @param p_aArgs {Array} Event Arguments
         */
        _removeFocusHandlers: function(p_sType, p_aArgs) {
            var aElements = this.focusableElements,
                nElements = aElements.length,
                focus = "focus";

            if (aElements) {
                for (var i = 0; i < nElements; i++) {
                    Event.removeListener(aElements[i], focus, this._onElementFocus);
                }
            }
        },

        /**
        * Initializes the custom events for Module which are fired 
        * automatically at appropriate times by the Module class.
        */
        initEvents: function () {
            Panel.superclass.initEvents.call(this);
        
            var SIGNATURE = CustomEvent.LIST;
        
            /**
            * CustomEvent fired after the modality mask is shown
            * @event showMaskEvent
            */
            this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
            this.showMaskEvent.signature = SIGNATURE;
        
            /**
            * CustomEvent fired after the modality mask is hidden
            * @event hideMaskEvent
            */
            this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
            this.hideMaskEvent.signature = SIGNATURE;
        
            /**
            * CustomEvent when the Panel is dragged
            * @event dragEvent
            */
            this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
            this.dragEvent.signature = SIGNATURE;
        
        },
        
        /**
        * Initializes the class's configurable properties which can be changed 
        * using the Panel's Config object (cfg).
        * @method initDefaultConfig
        */
        initDefaultConfig: function () {
            Panel.superclass.initDefaultConfig.call(this);
        
            // Add panel config properties //
        
            /**
            * True if the Panel should display a "close" button
            * @config close
            * @type Boolean
            * @default true
            */
            this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, { 
                handler: this.configClose, 
                value: DEFAULT_CONFIG.CLOSE.value, 
                validator: DEFAULT_CONFIG.CLOSE.validator, 
                supercedes: DEFAULT_CONFIG.CLOSE.supercedes 
            });
        
            /**
            * Boolean specifying if the Panel should be draggable.  The default 
            * value is "true" if the Drag and Drop utility is included, 
            * otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a 
            * known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7 
            * (Quirks Mode) where Panels that either don't have a value set for 
            * their "width" configuration property, or their "width" 
            * configuration property is set to "auto" will only be draggable by
            * placing the mouse on the text of the Panel's header element.
            * To fix this bug, draggable Panels missing a value for their 
            * "width" configuration property, or whose "width" configuration 
            * property is set to "auto" will have it set to the value of 
            * their root HTML element's offsetWidth before they are made 
            * visible.  The calculated width is then removed when the Panel is   
            * hidden. <em>This fix is only applied to draggable Panels in IE 6 
            * (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For 
            * more information on this issue see:
            * SourceForge bugs #1726972 and #1589210.
            * @config draggable
            * @type Boolean
            * @default true
            */
            this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, { 
                handler: this.configDraggable, 
                value: DEFAULT_CONFIG.DRAGGABLE.value, 
                validator: DEFAULT_CONFIG.DRAGGABLE.validator, 
                supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes 
            });

            /**
            * Boolean specifying if the draggable Panel should be drag only, not interacting with drop 
            * targets on the page.
            * <p>
            * When set to true, draggable Panels will not check to see if they are over drop targets,
            * or fire the DragDrop events required to support drop target interaction (onDragEnter, 
            * onDragOver, onDragOut, onDragDrop etc.).
            * If the Panel is not designed to be dropped on any target elements on the page, then this 
            * flag can be set to true to improve performance.
            * </p>
            * <p>
            * When set to false, all drop target related events will be fired.
            * </p>
            * <p>
            * The property is set to false by default to maintain backwards compatibility but should be 
            * set to true if drop target interaction is not required for the Panel, to improve performance.</p>
            * 
            * @config dragOnly
            * @type Boolean
            * @default false
            */
            this.cfg.addProperty(DEFAULT_CONFIG.DRAG_ONLY.key, { 
                value: DEFAULT_CONFIG.DRAG_ONLY.value, 
                validator: DEFAULT_CONFIG.DRAG_ONLY.validator, 
                supercedes: DEFAULT_CONFIG.DRAG_ONLY.supercedes 
            });

            /**
            * Sets the type of underlay to display for the Panel. Valid values 
            * are "shadow," "matte," and "none".  <strong>PLEASE NOTE:</strong> 
            * The creation of the underlay element is deferred until the Panel 
            * is initially made visible.  For Gecko-based browsers on Mac
            * OS X the underlay elment is always created as it is used as a 
            * shim to prevent Aqua scrollbars below a Panel instance from poking 
            * through it (See SourceForge bug #836476).
            * @config underlay
            * @type String
            * @default shadow
            */
            this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, { 
                handler: this.configUnderlay, 
                value: DEFAULT_CONFIG.UNDERLAY.value, 
                supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes 
            });
        
            /**
            * True if the Panel should be displayed in a modal fashion, 
            * automatically creating a transparent mask over the document that
            * will not be removed until the Panel is dismissed.
            * @config modal
            * @type Boolean
            * @default false
            */
            this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, { 
                handler: this.configModal, 
                value: DEFAULT_CONFIG.MODAL.value,
                validator: DEFAULT_CONFIG.MODAL.validator, 
                supercedes: DEFAULT_CONFIG.MODAL.supercedes 
            });
        
            /**
            * A KeyListener (or array of KeyListeners) that will be enabled 
            * when the Panel is shown, and disabled when the Panel is hidden.
            * @config keylisteners
            * @type YAHOO.util.KeyListener[]
            * @default null
            */
            this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, { 
                handler: this.configKeyListeners, 
                suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent, 
                supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes 
            });
        
        },
        
        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
        
        /**
        * The default event handler fired when the "close" property is changed.
        * The method controls the appending or hiding of the close icon at the 
        * top right of the Panel.
        * @method configClose
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configClose: function (type, args, obj) {

            var val = args[0],
                oClose = this.close;
        
            function doHide(e, obj) {
                obj.hide();
            }
        
            if (val) {
                if (!oClose) {
                    if (!m_oCloseIconTemplate) {
                        m_oCloseIconTemplate = document.createElement("span");
                        m_oCloseIconTemplate.innerHTML = "&#160;";
                        m_oCloseIconTemplate.className = "container-close";
                    }

                    oClose = m_oCloseIconTemplate.cloneNode(true);
                    this.innerElement.appendChild(oClose);
                    Event.on(oClose, "click", doHide, this);
                    
                    this.close = oClose;

                } else {
                    oClose.style.display = "block";
                }

            } else {
                if (oClose) {
                    oClose.style.display = "none";
                }
            }

        },

        /**
        * The default event handler fired when the "draggable" property 
        * is changed.
        * @method configDraggable
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configDraggable: function (type, args, obj) {
            var val = args[0];

            if (val) {
                if (!DD) {
                    this.cfg.setProperty("draggable", false);
                    return;
                }

                if (this.header) {
                    Dom.setStyle(this.header, "cursor", "move");
                    this.registerDragDrop();
                }

                this.subscribe("beforeShow", setWidthToOffsetWidth);

            } else {

                if (this.dd) {
                    this.dd.unreg();
                }

                if (this.header) {
                    Dom.setStyle(this.header,"cursor","auto");
                }

                this.unsubscribe("beforeShow", setWidthToOffsetWidth);
            }
        },
      
        /**
        * The default event handler fired when the "underlay" property 
        * is changed.
        * @method configUnderlay
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configUnderlay: function (type, args, obj) {

            var UA = YAHOO.env.ua,
                bMacGecko = (this.platform == "mac" && UA.gecko),
                bIEQuirks = (UA.ie == 6 || (UA.ie == 7 && document.compatMode == "BackCompat")),
                sUnderlay = args[0].toLowerCase(),
                oUnderlay = this.underlay,
                oElement = this.element;
                
            function fixWebkitUnderlay() {
                // Webkit 419.3 (Safari 2.x) does not update
                // it's Render Tree for the Container when content changes. 
                // We need to force it to update using this contentChange 
                // listener

                // Webkit 523.6 doesn't have this problem and doesn't 
                // need the fix
                var u = this.underlay;
                Dom.addClass(u, "yui-force-redraw");
                window.setTimeout(function(){Dom.removeClass(u, "yui-force-redraw");}, 0);
            }

            function createUnderlay() {
                var bNew = false;
                if (!oUnderlay) { // create if not already in DOM

                    if (!m_oUnderlayTemplate) {
                        m_oUnderlayTemplate = document.createElement("div");
                        m_oUnderlayTemplate.className = "underlay";
                    }

                    oUnderlay = m_oUnderlayTemplate.cloneNode(false);
                    this.element.appendChild(oUnderlay);

                    this.underlay = oUnderlay;

                    if (bIEQuirks) {
                        this.sizeUnderlay();
                        this.cfg.subscribeToConfigEvent("width", this.sizeUnderlay);
                        this.cfg.subscribeToConfigEvent("height",this.sizeUnderlay);
                        this.changeContentEvent.subscribe(this.sizeUnderlay);
                        YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay, this, true);
                    }

                    if (UA.webkit && UA.webkit < 420) {
                        this.changeContentEvent.subscribe(fixWebkitUnderlay);
                    }
                    bNew = true;
                }
            }

            function onBeforeShow() {
                var bNew = createUnderlay.call(this);
                if (!bNew && bIEQuirks) {
                    this.sizeUnderlay();
                }
                this._underlayDeferred = false;
                this.beforeShowEvent.unsubscribe(onBeforeShow);
            }

            function destroyUnderlay() {
                if (this._underlayDeferred) {
                    this.beforeShowEvent.unsubscribe(onBeforeShow);
                    this._underlayDeferred = false;
                }

                if (oUnderlay) {
                    this.cfg.unsubscribeFromConfigEvent("width", this.sizeUnderlay);
                    this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);
                    this.changeContentEvent.unsubscribe(this.sizeUnderlay);
                    this.changeContentEvent.unsubscribe(fixWebkitUnderlay);
                    YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay, this, true);

                    this.element.removeChild(oUnderlay);

                    this.underlay = null;
                }
            }

            switch (sUnderlay) {
                case "shadow":
                    Dom.removeClass(oElement, "matte");
                    Dom.addClass(oElement, "shadow");
                    break;
                case "matte":
                    if (!bMacGecko) {
                        destroyUnderlay.call(this);
                    }
                    Dom.removeClass(oElement, "shadow");
                    Dom.addClass(oElement, "matte");
                    break;
                default:
                    if (!bMacGecko) {
                        destroyUnderlay.call(this);
                    }
                    Dom.removeClass(oElement, "shadow");
                    Dom.removeClass(oElement, "matte");
                    break;
            }

            if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
                if (this.cfg.getProperty("visible")) {
                    var bNew = createUnderlay.call(this);
                    if (!bNew && bIEQuirks) {
                        this.sizeUnderlay();
                    }
                } else {
                    if (!this._underlayDeferred) {
                        this.beforeShowEvent.subscribe(onBeforeShow);
                        this._underlayDeferred = true;
                    }
                }
            }
        },
        
        /**
        * The default event handler fired when the "modal" property is 
        * changed. This handler subscribes or unsubscribes to the show and hide
        * events to handle the display or hide of the modality mask.
        * @method configModal
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configModal: function (type, args, obj) {

            var modal = args[0];
            if (modal) {
                if (!this._hasModalityEventListeners) {

                    this.subscribe("beforeShow", this.buildMask);
                    this.subscribe("beforeShow", this.bringToTop);
                    this.subscribe("beforeShow", this.showMask);
                    this.subscribe("hide", this.hideMask);

                    Overlay.windowResizeEvent.subscribe(this.sizeMask, 
                        this, true);

                    this._hasModalityEventListeners = true;
                }
            } else {
                if (this._hasModalityEventListeners) {

                    if (this.cfg.getProperty("visible")) {
                        this.hideMask();
                        this.removeMask();
                    }

                    this.unsubscribe("beforeShow", this.buildMask);
                    this.unsubscribe("beforeShow", this.bringToTop);
                    this.unsubscribe("beforeShow", this.showMask);
                    this.unsubscribe("hide", this.hideMask);

                    Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
                    
                    this._hasModalityEventListeners = false;
                }
            }
        },
        
        /**
        * Removes the modality mask.
        * @method removeMask
        */
        removeMask: function () {
        
            var oMask = this.mask,
                oParentNode;
        
            if (oMask) {
                /*
                    Hide the mask before destroying it to ensure that DOM
                    event handlers on focusable elements get removed.
                */
                this.hideMask();
                
                oParentNode = oMask.parentNode;
                if (oParentNode) {
                    oParentNode.removeChild(oMask);
                }

                this.mask = null;
            }
        },
        
        /**
        * The default event handler fired when the "keylisteners" property 
        * is changed.
        * @method configKeyListeners
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configKeyListeners: function (type, args, obj) {

            var listeners = args[0],
                listener,
                nListeners,
                i;
        
            if (listeners) {

                if (listeners instanceof Array) {

                    nListeners = listeners.length;

                    for (i = 0; i < nListeners; i++) {

                        listener = listeners[i];
        
                        if (!Config.alreadySubscribed(this.showEvent, 
                            listener.enable, listener)) {

                            this.showEvent.subscribe(listener.enable, 
                                listener, true);

                        }

                        if (!Config.alreadySubscribed(this.hideEvent, 
                            listener.disable, listener)) {

                            this.hideEvent.subscribe(listener.disable, 
                                listener, true);

                            this.destroyEvent.subscribe(listener.disable, 
                                listener, true);
                        }

                    }

                } else {

                    if (!Config.alreadySubscribed(this.showEvent, 
                        listeners.enable, listeners)) {

                        this.showEvent.subscribe(listeners.enable, 
                            listeners, true);
                    }

                    if (!Config.alreadySubscribed(this.hideEvent, 
                        listeners.disable, listeners)) {

                        this.hideEvent.subscribe(listeners.disable, 
                            listeners, true);

                        this.destroyEvent.subscribe(listeners.disable, 
                            listeners, true);

                    }

                }

            }

        },
        
        /**
        * The default event handler fired when the "height" property is changed.
        * @method configHeight
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configHeight: function (type, args, obj) {
    
            var height = args[0],
                el = this.innerElement;
    
            Dom.setStyle(el, "height", height);
            this.cfg.refireEvent("iframe");
    
        },
        
        /**
        * The default event handler fired when the "width" property is changed.
        * @method configWidth
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configWidth: function (type, args, obj) {
    
            var width = args[0],
                el = this.innerElement;
    
            Dom.setStyle(el, "width", width);
            this.cfg.refireEvent("iframe");
    
        },
        
        /**
        * The default event handler fired when the "zIndex" property is changed.
        * @method configzIndex
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configzIndex: function (type, args, obj) {
            Panel.superclass.configzIndex.call(this, type, args, obj);

            if (this.mask || this.cfg.getProperty("modal") === true) {
                var panelZ = Dom.getStyle(this.element, "zIndex");
                if (!panelZ || isNaN(panelZ)) {
                    panelZ = 0;
                }

                if (panelZ === 0) {
                    // Recursive call to configzindex (which should be stopped
                    // from going further because panelZ should no longer === 0)
                    this.cfg.setProperty("zIndex", 1);
                } else {
                    this.stackMask();
                }
            }
        },

        // END BUILT-IN PROPERTY EVENT HANDLERS //
        /**
        * Builds the wrapping container around the Panel that is used for 
        * positioning the shadow and matte underlays. The container element is 
        * assigned to a  local instance variable called container, and the 
        * element is reinserted inside of it.
        * @method buildWrapper
        */
        buildWrapper: function () {

            var elementParent = this.element.parentNode,
                originalElement = this.element,
                wrapper = document.createElement("div");

            wrapper.className = Panel.CSS_PANEL_CONTAINER;
            wrapper.id = originalElement.id + "_c";

            if (elementParent) {
                elementParent.insertBefore(wrapper, originalElement);
            }

            wrapper.appendChild(originalElement);

            this.element = wrapper;
            this.innerElement = originalElement;

            Dom.setStyle(this.innerElement, "visibility", "inherit");
        },

        /**
        * Adjusts the size of the shadow based on the size of the element.
        * @method sizeUnderlay
        */
        sizeUnderlay: function () {
            var oUnderlay = this.underlay,
                oElement;

            if (oUnderlay) {
                oElement = this.element;
                oUnderlay.style.width = oElement.offsetWidth + "px";
                oUnderlay.style.height = oElement.offsetHeight + "px";
            }
        },

        
        /**
        * Registers the Panel's header for drag & drop capability.
        * @method registerDragDrop
        */
        registerDragDrop: function () {

            var me = this;

            if (this.header) {

                if (!DD) {
                    return;
                }

                var bDragOnly = (this.cfg.getProperty("dragonly") === true);
                this.dd = new DD(this.element.id, this.id, {dragOnly: bDragOnly});

                if (!this.header.id) {
                    this.header.id = this.id + "_h";
                }

                this.dd.startDrag = function () {

                    var offsetHeight,
                        offsetWidth,
                        viewPortWidth,
                        viewPortHeight,
                        scrollX,
                        scrollY;

                    if (YAHOO.env.ua.ie == 6) {
                        Dom.addClass(me.element,"drag");
                    }

                    if (me.cfg.getProperty("constraintoviewport")) {

                        var nViewportOffset = Overlay.VIEWPORT_OFFSET;

                        offsetHeight = me.element.offsetHeight;
                        offsetWidth = me.element.offsetWidth;

                        viewPortWidth = Dom.getViewportWidth();
                        viewPortHeight = Dom.getViewportHeight();

                        scrollX = Dom.getDocumentScrollLeft();
                        scrollY = Dom.getDocumentScrollTop();

                        if (offsetHeight + nViewportOffset < viewPortHeight) {
                            this.minY = scrollY + nViewportOffset;
                            this.maxY = scrollY + viewPortHeight - offsetHeight - nViewportOffset;
                        } else {
                            this.minY = scrollY + nViewportOffset;
                            this.maxY = scrollY + nViewportOffset;
                        }

                        if (offsetWidth + nViewportOffset < viewPortWidth) {
                            this.minX = scrollX + nViewportOffset;
                            this.maxX = scrollX + viewPortWidth - offsetWidth - nViewportOffset;
                        } else {
                            this.minX = scrollX + nViewportOffset;
                            this.maxX = scrollX + nViewportOffset;
                        }

                        this.constrainX = true;
                        this.constrainY = true;
                    } else {
                        this.constrainX = false;
                        this.constrainY = false;
                    }

                    me.dragEvent.fire("startDrag", arguments);
                };

                this.dd.onDrag = function () {
                    me.syncPosition();
                    me.cfg.refireEvent("iframe");
                    if (this.platform == "mac" && YAHOO.env.ua.gecko) {
                        this.showMacGeckoScrollbars();
                    }

                    me.dragEvent.fire("onDrag", arguments);
                };

                this.dd.endDrag = function () {

                    if (YAHOO.env.ua.ie == 6) {
                        Dom.removeClass(me.element,"drag");
                    }

                    me.dragEvent.fire("endDrag", arguments);
                    me.moveEvent.fire(me.cfg.getProperty("xy"));

                };

                this.dd.setHandleElId(this.header.id);
                this.dd.addInvalidHandleType("INPUT");
                this.dd.addInvalidHandleType("SELECT");
                this.dd.addInvalidHandleType("TEXTAREA");
            }
        },
        
        /**
        * Builds the mask that is laid over the document when the Panel is 
        * configured to be modal.
        * @method buildMask
        */
        buildMask: function () {
            var oMask = this.mask;
            if (!oMask) {
                if (!m_oMaskTemplate) {
                    m_oMaskTemplate = document.createElement("div");
                    m_oMaskTemplate.className = "mask";
                    m_oMaskTemplate.innerHTML = "&#160;";
                }
                oMask = m_oMaskTemplate.cloneNode(true);
                oMask.id = this.id + "_mask";

                document.body.insertBefore(oMask, document.body.firstChild);

                this.mask = oMask;

                if (YAHOO.env.ua.gecko && this.platform == "mac") {
                    Dom.addClass(this.mask, "block-scrollbars");
                }

                // Stack mask based on the element zindex
                this.stackMask();
            }
        },

        /**
        * Hides the modality mask.
        * @method hideMask
        */
        hideMask: function () {
            if (this.cfg.getProperty("modal") && this.mask) {
                this.mask.style.display = "none";
                this.hideMaskEvent.fire();
                Dom.removeClass(document.body, "masked");
            }
        },

        /**
        * Shows the modality mask.
        * @method showMask
        */
        showMask: function () {
            if (this.cfg.getProperty("modal") && this.mask) {
                Dom.addClass(document.body, "masked");
                this.sizeMask();
                this.mask.style.display = "block";
                this.showMaskEvent.fire();
            }
        },

        /**
        * Sets the size of the modality mask to cover the entire scrollable 
        * area of the document
        * @method sizeMask
        */
        sizeMask: function () {
            if (this.mask) {
                this.mask.style.height = Dom.getDocumentHeight() + "px";
                this.mask.style.width = Dom.getDocumentWidth() + "px";
            }
        },

        /**
         * Sets the zindex of the mask, if it exists, based on the zindex of 
         * the Panel element. The zindex of the mask is set to be one less 
         * than the Panel element's zindex.
         * 
         * <p>NOTE: This method will not bump up the zindex of the Panel
         * to ensure that the mask has a non-negative zindex. If you require the
         * mask zindex to be 0 or higher, the zindex of the Panel 
         * should be set to a value higher than 0, before this method is called.
         * </p>
         * @method stackMask
         */
        stackMask: function() {
            if (this.mask) {
                var panelZ = Dom.getStyle(this.element, "zIndex");
                if (!YAHOO.lang.isUndefined(panelZ) && !isNaN(panelZ)) {
                    Dom.setStyle(this.mask, "zIndex", panelZ - 1);
                }
            }
        },

        /**
        * Renders the Panel by inserting the elements that are not already in 
        * the main Panel into their correct places. Optionally appends the 
        * Panel to the specified node prior to the render's execution. NOTE: 
        * For Panels without existing markup, the appendToNode argument is 
        * REQUIRED. If this argument is ommitted and the current element is 
        * not present in the document, the function will return false, 
        * indicating that the render was a failure.
        * @method render
        * @param {String} appendToNode The element id to which the Module 
        * should be appended to prior to rendering <em>OR</em>
        * @param {HTMLElement} appendToNode The element to which the Module 
        * should be appended to prior to rendering
        * @return {boolean} Success or failure of the render
        */
        render: function (appendToNode) {

            return Panel.superclass.render.call(this, 
                appendToNode, this.innerElement);

        },
        
        /**
        * Removes the Panel element from the DOM and sets all child elements
        * to null.
        * @method destroy
        */
        destroy: function () {
        
            Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
            
            this.removeMask();
        
            if (this.close) {
            
                Event.purgeElement(this.close);
        
            }
        
            Panel.superclass.destroy.call(this);  
        
        },
        
        /**
        * Returns a String representation of the object.
        * @method toString
        * @return {String} The string representation of the Panel.
        */
        toString: function () {
            return "Panel " + this.id;
        }
    
    });

}());

(function () {

    /**
    * <p>
    * Dialog is an implementation of Panel that can be used to submit form 
    * data.
    * </p>
    * <p>
    * Built-in functionality for buttons with event handlers is included. 
    * If the optional YUI Button dependancy is included on the page, the buttons
    * created will be instances of YAHOO.widget.Button, otherwise regular HTML buttons
    * will be created.
    * </p>
    * <p>
    * Forms can be processed in 3 ways -- via an asynchronous Connection utility call, 
    * a simple form POST or GET, or manually. The YUI Connection utility should be
    * included if you're using the default "async" postmethod, but is not required if
    * you're using any of the other postmethod values.
    * </p>
    * @namespace YAHOO.widget
    * @class Dialog
    * @extends YAHOO.widget.Panel
    * @constructor
    * @param {String} el The element ID representing the Dialog <em>OR</em>
    * @param {HTMLElement} el The element representing the Dialog
    * @param {Object} userConfig The configuration object literal containing 
    * the configuration that should be set for this Dialog. See configuration 
    * documentation for more details.
    */
    YAHOO.widget.Dialog = function (el, userConfig) {
        YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
    };

    var Event = YAHOO.util.Event,
        CustomEvent = YAHOO.util.CustomEvent,
        Dom = YAHOO.util.Dom,
        KeyListener = YAHOO.util.KeyListener,
        Connect = YAHOO.util.Connect,
        Dialog = YAHOO.widget.Dialog,
        Lang = YAHOO.lang,

        /**
        * Constant representing the name of the Dialog's events
        * @property EVENT_TYPES
        * @private
        * @final
        * @type Object
        */
        EVENT_TYPES = {
        
            "BEFORE_SUBMIT": "beforeSubmit",
            "SUBMIT": "submit",
            "MANUAL_SUBMIT": "manualSubmit",
            "ASYNC_SUBMIT": "asyncSubmit",
            "FORM_SUBMIT": "formSubmit",
            "CANCEL": "cancel"
        
        },

        /**
        * Constant representing the Dialog's configuration properties
        * @property DEFAULT_CONFIG
        * @private
        * @final
        * @type Object
        */
        DEFAULT_CONFIG = {

            "POST_METHOD": { 
                key: "postmethod", 
                value: "async" 
            },

            "BUTTONS": { 
                key: "buttons", 
                value: "none" 
            },

            "HIDEAFTERSUBMIT" : {
                key: "hideaftersubmit",
                value: true
            }
        };

    /**
    * Constant representing the default CSS class used for a Dialog
    * @property YAHOO.widget.Dialog.CSS_DIALOG
    * @static
    * @final
    * @type String
    */
    Dialog.CSS_DIALOG = "yui-dialog";

    function removeButtonEventHandlers() {

        var aButtons = this._aButtons,
            nButtons,
            oButton,
            i;

        if (Lang.isArray(aButtons)) {
            nButtons = aButtons.length;

            if (nButtons > 0) {
                i = nButtons - 1;
                do {
                    oButton = aButtons[i];

                    if (YAHOO.widget.Button && oButton instanceof YAHOO.widget.Button) {
                        oButton.destroy();
                    }
                    else if (oButton.tagName.toUpperCase() == "BUTTON") {
                        Event.purgeElement(oButton);
                        Event.purgeElement(oButton, false);
                    }
                }
                while (i--);
            }
        }
    }
    
    YAHOO.extend(Dialog, YAHOO.widget.Panel, { 

        /**
        * @property form
        * @description Object reference to the Dialog's 
        * <code>&#60;form&#62;</code> element.
        * @default null 
        * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-40002357">HTMLFormElement</a>
        */
        form: null,
    
        /**
        * Initializes the class's configurable properties which can be changed 
        * using the Dialog's Config object (cfg).
        * @method initDefaultConfig
        */
        initDefaultConfig: function () {
            Dialog.superclass.initDefaultConfig.call(this);

            /**
            * The internally maintained callback object for use with the 
            * Connection utility. The format of the callback object is 
            * similar to Connection Manager's callback object and is 
            * simply passed through to Connection Manager when the async 
            * request is made.
            * @property callback
            * @type Object
            */
            this.callback = {

                /**
                * The function to execute upon success of the 
                * Connection submission (when the form does not
                * contain a file input element).
                * 
                * @property callback.success
                * @type Function
                */
                success: null,

                /**
                * The function to execute upon failure of the 
                * Connection submission
                * @property callback.failure
                * @type Function
                */
                failure: null,

                /**
                 *<p>
                * The function to execute upon success of the 
                * Connection submission, when the form contains
                * a file input element.
                * </p>
                * <p>
                * <em>NOTE:</em> Connection manager will not
                * invoke the success or failure handlers for the file
                * upload use case. This will be the only callback
                * handler invoked.
                * </p>
                * <p>
                * For more information, see the <a href="http://developer.yahoo.com/yui/connection/#file">
                * Connection Manager documenation on file uploads</a>.
                * </p>
                * @property callback.upload
                * @type Function
                */

                /**
                * The arbitraty argument or arguments to pass to the Connection 
                * callback functions
                * @property callback.argument
                * @type Object
                */
                argument: null

            };

            // Add form dialog config properties //
            /**
            * The method to use for posting the Dialog's form. Possible values 
            * are "async", "form", and "manual".
            * @config postmethod
            * @type String
            * @default async
            */
            this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
                handler: this.configPostMethod, 
                value: DEFAULT_CONFIG.POST_METHOD.value, 
                validator: function (val) {
                    if (val != "form" && val != "async" && val != "none" && 
                        val != "manual") {
                        return false;
                    } else {
                        return true;
                    }
                }
            });

            /**
            * This property is used to configure whether or not the 
            * dialog should be automatically hidden after submit.
            * 
            * @config hideaftersubmit
            * @type Boolean
            * @default true
            */
            this.cfg.addProperty(DEFAULT_CONFIG.HIDEAFTERSUBMIT.key, {
                value: DEFAULT_CONFIG.HIDEAFTERSUBMIT.value
            }); 

            /**
            * Array of object literals, each containing a set of properties 
            * defining a button to be appended into the Dialog's footer.
            * 
            * Each button object in the buttons array can have three properties:
            * <dt>text:</dt>
            * <dd>The text that will display on the face of the button. The text can 
            * include HTML, as long as it is compliant with HTML Button specifications.
            * </dd>
            * <dt>handler:</dt>
            * <dd>Can be either:
            *     <ol>
            *         <li>A reference to a function that should fire when the 
            * button is clicked.  (In this case scope of this function is 
            * always its Dialog instance.)</li>
            *         <li>An object literal representing the code to be 
            * executed when the button is clicked.  Format:<br> <code> {<br>
            * <strong>fn:</strong> Function,   &#47;&#47; The handler to call 
            * when  the event fires.<br> <strong>obj:</strong> Object,
            * &#47;&#47; An  object to pass back to the handler.<br> <strong>
            * scope:</strong>  Object &#47;&#47; The object to use for the 
            * scope of the handler. <br> } </code> <br></li>
            *     </ol>
            * </dd>
            * <dt>isDefault:</dt>
            * <dd>An optional boolean value that specifies that a button 
            * should be highlighted and focused by default.</dd>
            * 
            * <em>NOTE:</em>If the YUI Button Widget is included on the page, 
            * the buttons created will be instances of YAHOO.widget.Button. 
            * Otherwise, HTML Buttons (<code>&#60;BUTTON&#62;</code>) will be 
            * created.
            * 
            * @config buttons
            * @type {Array|String}
            * @default "none"
            */
            this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
                handler: this.configButtons,
                value: DEFAULT_CONFIG.BUTTONS.value
            }); 

        },

        /**
        * Initializes the custom events for Dialog which are fired 
        * automatically at appropriate times by the Dialog class.
        * @method initEvents
        */
        initEvents: function () {
            Dialog.superclass.initEvents.call(this);

            var SIGNATURE = CustomEvent.LIST;

            /**
            * CustomEvent fired prior to submission
            * @event beforeSubmitEvent
            */ 
            this.beforeSubmitEvent = 
                this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
            this.beforeSubmitEvent.signature = SIGNATURE;
            
            /**
            * CustomEvent fired after submission
            * @event submitEvent
            */
            this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
            this.submitEvent.signature = SIGNATURE;
        
            /**
            * CustomEvent fired prior to manual submission
            * @event manualSubmitEvent
            */
            this.manualSubmitEvent = 
                this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
            this.manualSubmitEvent.signature = SIGNATURE;
        
            /**
            * CustomEvent fired prior to asynchronous submission
            * @event asyncSubmitEvent
            */ 
            this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
            this.asyncSubmitEvent.signature = SIGNATURE;
        
            /**
            * CustomEvent fired prior to form-based submission
            * @event formSubmitEvent
            */
            this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
            this.formSubmitEvent.signature = SIGNATURE;
        
            /**
            * CustomEvent fired after cancel
            * @event cancelEvent
            */
            this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
            this.cancelEvent.signature = SIGNATURE;
        
        },
        
        /**
        * The Dialog initialization method, which is executed for Dialog and 
        * all of its subclasses. This method is automatically called by the 
        * constructor, and  sets up all DOM references for pre-existing markup, 
        * and creates required markup if it is not already present.
        * @method init
        * @param {String} el The element ID representing the Dialog <em>OR</em>
        * @param {HTMLElement} el The element representing the Dialog
        * @param {Object} userConfig The configuration object literal 
        * containing the configuration that should be set for this Dialog. 
        * See configuration documentation for more details.
        */
        init: function (el, userConfig) {

            /*
                 Note that we don't pass the user config in here yet because 
                 we only want it executed once, at the lowest subclass level
            */

            Dialog.superclass.init.call(this, el/*, userConfig*/); 
        
            this.beforeInitEvent.fire(Dialog);
        
            Dom.addClass(this.element, Dialog.CSS_DIALOG);
        
            this.cfg.setProperty("visible", false);
        
            if (userConfig) {
                this.cfg.applyConfig(userConfig, true);
            }
        
            this.showEvent.subscribe(this.focusFirst, this, true);
            this.beforeHideEvent.subscribe(this.blurButtons, this, true);

            this.subscribe("changeBody", this.registerForm);
        
            this.initEvent.fire(Dialog);
        },
        
        /**
        * Submits the Dialog's form depending on the value of the 
        * "postmethod" configuration property.  <strong>Please note:
        * </strong> As of version 2.3 this method will automatically handle 
        * asyncronous file uploads should the Dialog instance's form contain 
        * <code>&#60;input type="file"&#62;</code> elements.  If a Dialog 
        * instance will be handling asyncronous file uploads, its 
        * <code>callback</code> property will need to be setup with a 
        * <code>upload</code> handler rather than the standard 
        * <code>success</code> and, or <code>failure</code> handlers.  For more 
        * information, see the <a href="http://developer.yahoo.com/yui/
        * connection/#file">Connection Manager documenation on file uploads</a>.
        * @method doSubmit
        */
        doSubmit: function () {
    
            var oForm = this.form,
                bUseFileUpload = false,
                bUseSecureFileUpload = false,
                aElements,
                nElements,
                i,
                sMethod;

            switch (this.cfg.getProperty("postmethod")) {
    
            case "async":

                aElements = oForm.elements;
                nElements = aElements.length;

                if (nElements > 0) {
                    i = nElements - 1;
                    do {
                        if (aElements[i].type == "file") {
                            bUseFileUpload = true;
                            break;
                        }
                    }
                    while(i--);
                }

                if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
                    bUseSecureFileUpload = true;
                }

                sMethod = (oForm.getAttribute("method") || "POST").toUpperCase();

                Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
                Connect.asyncRequest(sMethod, oForm.getAttribute("action"), this.callback);

                this.asyncSubmitEvent.fire();

                break;

            case "form":

                oForm.submit();
                this.formSubmitEvent.fire();

                break;

            case "none":
            case "manual":

                this.manualSubmitEvent.fire();

                break;
    
            }
    
        },
        
        
        /**
        * Prepares the Dialog's internal FORM object, creating one if one is
        * not currently present.
        * @method registerForm
        */
        registerForm: function () {
    
            var form = this.element.getElementsByTagName("form")[0],
                me = this,
                firstElement,
                lastElement;


            if (this.form) {
                if (this.form == form && 
                    Dom.isAncestor(this.element, this.form)) {
    
                    return;
                } else {
                    Event.purgeElement(this.form);
                    this.form = null;                
                }
            }

            if (!form) {
                form = document.createElement("form");
                form.name = "frm_" + this.id;

                this.body.appendChild(form);
            }

            if (form) {
                this.form = form;

                Event.on(form, "submit", function (e) {
                    Event.stopEvent(e);
                    this.submit();
                    this.form.blur();
                }, this, true);

                this.firstFormElement = function () {
                    var f, el, nElements = form.elements.length;

                    for (f = 0; f < nElements; f++) {
                        el = form.elements[f];
                        if (el.focus && !el.disabled && el.type != "hidden") {
                            return el;
                        }
                    }
                    return null;
                }();
            
                this.lastFormElement = function () {
                    var f, el, nElements = form.elements.length;
                    
                    for (f = nElements - 1; f >= 0; f--) {
                        el = form.elements[f];
                        if (el.focus && !el.disabled && el.type != "hidden") {
                            return el;
                        }
                    }
                    return null;
                }();
            
                if (this.cfg.getProperty("modal")) {
                    firstElement = this.firstFormElement || this.firstButton;
                    if (firstElement) {
                        this.preventBackTab = new KeyListener(firstElement, 
                            { shift: true, keys: 9 }, 
                            { fn: me.focusLast, scope: me, 
                            correctScope: true });
    
                        this.showEvent.subscribe(this.preventBackTab.enable, 
                            this.preventBackTab, true);
    
                        this.hideEvent.subscribe(this.preventBackTab.disable, 
                            this.preventBackTab, true);
                    }
            
                    lastElement = this.lastButton || this.lastFormElement;
    
                    if (lastElement) {
                        this.preventTabOut = new KeyListener(lastElement, 
                            { shift: false, keys: 9 }, 
                            { fn: me.focusFirst, scope: me, 
                            correctScope: true });
    
                        this.showEvent.subscribe(this.preventTabOut.enable, 
                            this.preventTabOut, true);
    
                        this.hideEvent.subscribe(this.preventTabOut.disable, 
                            this.preventTabOut, true);
                    }
                }
            }
        },
        
        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
        
        /**
        * The default event handler fired when the "close" property is 
        * changed. The method controls the appending or hiding of the close
        * icon at the top right of the Dialog.
        * @method configClose
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For 
        * configuration handlers, args[0] will equal the newly applied value 
        * for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configClose: function (type, args, obj) {
            var val = args[0];
        
            function doCancel(e, obj) {
                obj.cancel();
            }
        
            if (val) {
                if (! this.close) {
                    this.close = document.createElement("div");
                    Dom.addClass(this.close, "container-close");
        
                    this.close.innerHTML = "&#160;";
                    this.innerElement.appendChild(this.close);
                    Event.on(this.close, "click", doCancel, this);
                } else {
                    this.close.style.display = "block";
                }
            } else {
                if (this.close) {
                    this.close.style.display = "none";
                }
            }
        },
        
        /**
        * The default event handler for the "buttons" configuration property
        * @method configButtons
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configButtons: function (type, args, obj) {
    
            var Button = YAHOO.widget.Button,
                aButtons = args[0],
                oInnerElement = this.innerElement,
                oButton,
                oButtonEl,
                oYUIButton,
                nButtons,
                oSpan,
                oFooter,
                i;

            removeButtonEventHandlers.call(this);
            
            this._aButtons = null;

            if (Lang.isArray(aButtons)) {

                oSpan = document.createElement("span");
                oSpan.className = "button-group";

                nButtons = aButtons.length;

                this._aButtons = [];
        
                for (i = 0; i < nButtons; i++) {

                    oButton = aButtons[i];

                    if (Button) {

                        oYUIButton = new Button({ label: oButton.text, 
                                            container: oSpan });

                        oButtonEl = oYUIButton.get("element");

                        if (oButton.isDefault) {

                            oYUIButton.addClass("default");

                            this.defaultHtmlButton = oButtonEl;

                        }
    
                        if (Lang.isFunction(oButton.handler)) {
    
                            oYUIButton.set("onclick", { fn: oButton.handler, 
                                obj: this, scope: this });
            
                        }
                        else if (Lang.isObject(oButton.handler) && 
                            Lang.isFunction(oButton.handler.fn)) {

                            oYUIButton.set("onclick", { fn: oButton.handler.fn, 
                                obj: ((!Lang.isUndefined(oButton.handler.obj)) ? 
                                oButton.handler.obj : this), 
                                scope: (oButton.handler.scope || this) });
    
                        }

                        this._aButtons[this._aButtons.length] = oYUIButton;

                    }
                    else {
        
                        oButtonEl = document.createElement("button");
                        oButtonEl.setAttribute("type", "button");
            
                        if (oButton.isDefault) {
                            oButtonEl.className = "default";
                            this.defaultHtmlButton = oButtonEl;
                        }
    
                        oButtonEl.innerHTML = oButton.text;
    
                        if (Lang.isFunction(oButton.handler)) {
    
                            Event.on(oButtonEl, "click", oButton.handler, 
                                this, true);
            
                        }
                        else if (Lang.isObject(oButton.handler) && 
                            Lang.isFunction(oButton.handler.fn)) {
    
                            Event.on(oButtonEl, "click", oButton.handler.fn, 
                                ((!Lang.isUndefined(oButton.handler.obj)) ? 
                                oButton.handler.obj : this), 
                                (oButton.handler.scope || this));
    
                        }
            
                        oSpan.appendChild(oButtonEl);
                        
                        this._aButtons[this._aButtons.length] = oButtonEl;
                        
                    }

                    oButton.htmlButton = oButtonEl;
        
                    if (i === 0) {
                        this.firstButton = oButtonEl;
                    }
        
                    if (i == (nButtons - 1)) {
                        this.lastButton = oButtonEl;
                    }
        
                }
        
                this.setFooter(oSpan);

                oFooter = this.footer;
                
                if (Dom.inDocument(this.element) && 
                    !Dom.isAncestor(oInnerElement, oFooter)) {
    
                    oInnerElement.appendChild(oFooter);
                
                }

                this.buttonSpan = oSpan;

            } else { // Do cleanup

                oSpan = this.buttonSpan;
                oFooter = this.footer;

                if (oSpan && oFooter) {

                    oFooter.removeChild(oSpan);

                    this.buttonSpan = null;
                    this.firstButton = null;
                    this.lastButton = null;
                    this.defaultHtmlButton = null;

                }

            }

            this.cfg.refireEvent("iframe");
            this.cfg.refireEvent("underlay");
        },

        /**
        * @method getButtons
        * @description Returns an array containing each of the Dialog's 
        * buttons, by default an array of HTML <code>&#60;BUTTON&#62;</code> 
        * elements.  If the Dialog's buttons were created using the 
        * YAHOO.widget.Button class (via the inclusion of the optional Button 
        * dependancy on the page), an array of YAHOO.widget.Button instances 
        * is returned.
        * @return {Array}
        */
        getButtons: function () {
            var aButtons = this._aButtons;
            if (aButtons) {
                return aButtons;
            }
        },
        
        /**
        * Sets focus to the first element in the Dialog's form or the first 
        * button defined via the "buttons" configuration property. Called 
        * when the Dialog is made visible.
        * @method focusFirst
        */
        focusFirst: function (type, args, obj) {
    
            var oElement = this.firstFormElement,
                oEvent;

            if (args) {
                oEvent = args[1];
                if (oEvent) {
                    Event.stopEvent(oEvent);
                }
            }

            if (oElement) {
                /*
                    Place the call to the "focus" method inside a try/catch
                    block to prevent IE from throwing JavaScript errors if
                    the element is disabled or hidden.
                */
                try {
                    oElement.focus();
                }
                catch(oException) {
                }

            } else {
                this.focusDefaultButton();
            }
        },
        
        /**
        * Sets focus to the last element in the Dialog's form or the last 
        * button defined via the "buttons" configuration property.
        * @method focusLast
        */
        focusLast: function (type, args, obj) {
    
            var aButtons = this.cfg.getProperty("buttons"),
                oElement = this.lastFormElement,
                oEvent;
    
            if (args) {
                oEvent = args[1];
                if (oEvent) {
                    Event.stopEvent(oEvent);
                }
            }
            
            if (aButtons && Lang.isArray(aButtons)) {
                this.focusLastButton();
            } else {
                if (oElement) {
                    /*
                        Place the call to the "focus" method inside a try/catch
                        block to prevent IE from throwing JavaScript errors if
                        the element is disabled or hidden.
                    */
    
                    try {
                        oElement.focus();
                    } catch(oException) {
                    }
                }
            }
        },
        
        /**
        * Sets the focus to the button that is designated as the default via 
        * the "buttons" configuration property. By default, this method is 
        * called when the Dialog is made visible.
        * @method focusDefaultButton
        */
        focusDefaultButton: function () {
        
            var oElement = this.defaultHtmlButton;
        
            if (oElement) {

                /*
                    Place the call to the "focus" method inside a try/catch
                    block to prevent IE from throwing JavaScript errors if
                    the element is disabled or hidden.
                */
                try {
                    oElement.focus();
                } catch(oException) {
                }

            }
        },
        
        /**
        * Blurs all the buttons defined via the "buttons" 
        * configuration property.
        * @method blurButtons
        */
        blurButtons: function () {
            
            var aButtons = this.cfg.getProperty("buttons"),
                nButtons,
                oButton,
                oElement,
                i;

            if (aButtons && Lang.isArray(aButtons)) {
            
                nButtons = aButtons.length;
                
                if (nButtons > 0) {
                
                    i = (nButtons - 1);
                    
                    do {
                        oButton = aButtons[i];
                        
                        if (oButton) {

                            oElement = oButton.htmlButton;

                            if (oElement) {
                                /*
                                    Place the call to the "blur" method inside  
                                    a try/catch block to prevent IE from  
                                    throwing JavaScript errors if the element 
                                    is disabled or hidden.
                                */
                                try {
                                    oElement.blur();
                                } catch(oException) {
                                }
                            }
                        }
                    
                    } while(i--);
                }
            }
        },
        
        /**
        * Sets the focus to the first button created via the "buttons"
        * configuration property.
        * @method focusFirstButton
        */
        focusFirstButton: function () {
    
            var aButtons = this.cfg.getProperty("buttons"),
                oButton,
                oElement;

            if (aButtons && Lang.isArray(aButtons)) {

                oButton = aButtons[0];

                if (oButton) {

                    oElement = oButton.htmlButton;
                    
                    if (oElement) {

                        /*
                            Place the call to the "focus" method inside a 
                            try/catch block to prevent IE from throwing 
                            JavaScript errors if the element is disabled 
                            or hidden.
                        */
    
                        try {
                            oElement.focus();
                        }
                        catch(oException) {
                        }
                    }
                }
            }
        },
        
        /**
        * Sets the focus to the last button created via the "buttons" 
        * configuration property.
        * @method focusLastButton
        */
        focusLastButton: function () {
    
            var aButtons = this.cfg.getProperty("buttons"),
                nButtons,
                oButton,
                oElement;

            if (aButtons && Lang.isArray(aButtons)) {

                nButtons = aButtons.length;
                
                if (nButtons > 0) {
                    oButton = aButtons[(nButtons - 1)];
                    
                    if (oButton) {
                        oElement = oButton.htmlButton;
                        if (oElement) {
                            /*
                                Place the call to the "focus" method inside a 
                                try/catch block to prevent IE from throwing 
                                JavaScript errors if the element is disabled
                                or hidden.
                            */
        
                            try {
                                oElement.focus();
                            } catch(oException) {
                            }
                        }
                    }
                }
            }
        },
        
        /**
        * The default event handler for the "postmethod" configuration property
        * @method configPostMethod
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For 
        * configuration handlers, args[0] will equal the newly applied value 
        * for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configPostMethod: function (type, args, obj) {
            this.registerForm();
        },
        
        // END BUILT-IN PROPERTY EVENT HANDLERS //
        
        /**
        * Built-in function hook for writing a validation function that will 
        * be checked for a "true" value prior to a submit. This function, as 
        * implemented by default, always returns true, so it should be 
        * overridden if validation is necessary.
        * @method validate
        */
        validate: function () {
            return true;
        },
        
        /**
        * Executes a submit of the Dialog if validation 
        * is successful. By default the Dialog is hidden
        * after submission, but you can set the "hideaftersubmit"
        * configuration property to false, to prevent the Dialog
        * from being hidden.
        * 
        * @method submit
        */
        submit: function () {
            if (this.validate()) {
                this.beforeSubmitEvent.fire();
                this.doSubmit();
                this.submitEvent.fire();

                if (this.cfg.getProperty("hideaftersubmit")) {
                    this.hide();
                }

                return true;
            } else {
                return false;
            }
        },

        /**
        * Executes the cancel of the Dialog followed by a hide.
        * @method cancel
        */
        cancel: function () {
            this.cancelEvent.fire();
            this.hide();
        },
        
        /**
        * Returns a JSON-compatible data structure representing the data 
        * currently contained in the form.
        * @method getData
        * @return {Object} A JSON object reprsenting the data of the 
        * current form.
        */
        getData: function () {
        
            var oForm = this.form,
                aElements,
                nTotalElements,
                oData,
                sName,
                oElement,
                nElements,
                sType,
                sTagName,
                aOptions,
                nOptions,
                aValues,
                oOption,
                sValue,
                oRadio,
                oCheckbox,
                i,
                n;    
    
            function isFormElement(p_oElement) {
            
                var sTag = p_oElement.tagName.toUpperCase();
                
                return ((sTag == "INPUT" || sTag == "TEXTAREA" || 
                        sTag == "SELECT") && p_oElement.name == sName);
    
            }
    
    
            if (oForm) {
        
                aElements = oForm.elements;
                nTotalElements = aElements.length;
                oData = {};
    
        
                for (i = 0; i < nTotalElements; i++) {
        
                    sName = aElements[i].name;
        
                    /*
                        Using "Dom.getElementsBy" to safeguard user from JS 
                        errors that result from giving a form field (or set of 
                        fields) the same name as a native method of a form 
                        (like "submit") or a DOM collection (such as the "item"
                        method). Originally tried accessing fields via the 
                        "namedItem" method of the "element" collection, but 
                        discovered that it won't return a collection of fields 
                        in Gecko.
                    */
        
                    oElement = Dom.getElementsBy(isFormElement, "*", oForm);
                    nElements = oElement.length;
        
                    if (nElements > 0) {
        
                        if (nElements == 1) {
        
                            oElement = oElement[0];
        
                            sType = oElement.type;
                            sTagName = oElement.tagName.toUpperCase();
        
                            switch (sTagName) {
        
                            case "INPUT":
    
                                if (sType == "checkbox") {
    
                                    oData[sName] = oElement.checked;
    
                                }
                                else if (sType != "radio") {
    
                                    oData[sName] = oElement.value;
    
                                }
    
                                break;
    
                            case "TEXTAREA":
    
                                oData[sName] = oElement.value;
    
                                break;
    
                            case "SELECT":
    
                                aOptions = oElement.options;
                                nOptions = aOptions.length;
                                aValues = [];
    
                                for (n = 0; n < nOptions; n++) {
    
                                    oOption = aOptions[n];
    
                                    if (oOption.selected) {
    
                                        sValue = oOption.value;
    
                                        if (!sValue || sValue === "") {
    
                                            sValue = oOption.text;
    
                                        }
    
                                        aValues[aValues.length] = sValue;
    
                                    }
    
                                }
    
                                oData[sName] = aValues;
    
                                break;
        
                            }
        
        
                        }
                        else {
        
                            sType = oElement[0].type;
        
                            switch (sType) {
        
                            case "radio":
    
                                for (n = 0; n < nElements; n++) {
    
                                    oRadio = oElement[n];
    
                                    if (oRadio.checked) {
    
                                        oData[sName] = oRadio.value;
                                        break;
    
                                    }
    
                                }
    
                                break;
    
                            case "checkbox":
    
                                aValues = [];
    
                                for (n = 0; n < nElements; n++) {
    
                                    oCheckbox = oElement[n];
    
                                    if (oCheckbox.checked) {
    
                                        aValues[aValues.length] = 
                                            oCheckbox.value;
    
                                    }
    
                                }
    
                                oData[sName] = aValues;
    
                                break;
        
                            }
        
                        }
        
                    }
        
                }
        
            }
        
        
            return oData;
        
        },
        
        /**
        * Removes the Panel element from the DOM and sets all child elements 
        * to null.
        * @method destroy
        */
        destroy: function () {
        
            removeButtonEventHandlers.call(this);
            
            this._aButtons = null;

            var aForms = this.element.getElementsByTagName("form"),
                oForm;
            
            if (aForms.length > 0) {

                oForm = aForms[0];

                if (oForm) {
                    Event.purgeElement(oForm);
                    if (oForm.parentNode) {
                        oForm.parentNode.removeChild(oForm);
                    }
                    this.form = null;
                }
            }
        
            Dialog.superclass.destroy.call(this);  
        
        },
        
        /**
        * Returns a string representation of the object.
        * @method toString
        * @return {String} The string representation of the Dialog
        */
        toString: function () {
            return "Dialog " + this.id;
        }
    
    });

}());

(function () {

    /**
    * SimpleDialog is a simple implementation of Dialog that can be used to 
    * submit a single value. Forms can be processed in 3 ways -- via an 
    * asynchronous Connection utility call, a simple form POST or GET, 
    * or manually.
    * @namespace YAHOO.widget
    * @class SimpleDialog
    * @extends YAHOO.widget.Dialog
    * @constructor
    * @param {String} el The element ID representing the SimpleDialog 
    * <em>OR</em>
    * @param {HTMLElement} el The element representing the SimpleDialog
    * @param {Object} userConfig The configuration object literal containing 
    * the configuration that should be set for this SimpleDialog. See 
    * configuration documentation for more details.
    */
    YAHOO.widget.SimpleDialog = function (el, userConfig) {
    
        YAHOO.widget.SimpleDialog.superclass.constructor.call(this, 
            el, userConfig);
    
    };

    var Dom = YAHOO.util.Dom,
        SimpleDialog = YAHOO.widget.SimpleDialog,
    
        /**
        * Constant representing the SimpleDialog's configuration properties
        * @property DEFAULT_CONFIG
        * @private
        * @final
        * @type Object
        */
        DEFAULT_CONFIG = {
        
            "ICON": { 
                key: "icon", 
                value: "none", 
                suppressEvent: true  
            },
        
            "TEXT": { 
                key: "text", 
                value: "", 
                suppressEvent: true, 
                supercedes: ["icon"] 
            }
        
        };

    /**
    * Constant for the standard network icon for a blocking action
    * @property YAHOO.widget.SimpleDialog.ICON_BLOCK
    * @static
    * @final
    * @type String
    */
    SimpleDialog.ICON_BLOCK = "blckicon";
    
    /**
    * Constant for the standard network icon for alarm
    * @property YAHOO.widget.SimpleDialog.ICON_ALARM
    * @static
    * @final
    * @type String
    */
    SimpleDialog.ICON_ALARM = "alrticon";
    
    /**
    * Constant for the standard network icon for help
    * @property YAHOO.widget.SimpleDialog.ICON_HELP
    * @static
    * @final
    * @type String
    */
    SimpleDialog.ICON_HELP  = "hlpicon";
    
    /**
    * Constant for the standard network icon for info
    * @property YAHOO.widget.SimpleDialog.ICON_INFO
    * @static
    * @final
    * @type String
    */
    SimpleDialog.ICON_INFO  = "infoicon";
    
    /**
    * Constant for the standard network icon for warn
    * @property YAHOO.widget.SimpleDialog.ICON_WARN
    * @static
    * @final
    * @type String
    */
    SimpleDialog.ICON_WARN  = "warnicon";
    
    /**
    * Constant for the standard network icon for a tip
    * @property YAHOO.widget.SimpleDialog.ICON_TIP
    * @static
    * @final
    * @type String
    */
    SimpleDialog.ICON_TIP   = "tipicon";

    /**
    * Constant representing the name of the CSS class applied to the element 
    * created by the "icon" configuration property.
    * @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
    * @static
    * @final
    * @type String
    */
    SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
    
    /**
    * Constant representing the default CSS class used for a SimpleDialog
    * @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
    * @static
    * @final
    * @type String
    */
    SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";

    
    YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
    
        /**
        * Initializes the class's configurable properties which can be changed 
        * using the SimpleDialog's Config object (cfg).
        * @method initDefaultConfig
        */
        initDefaultConfig: function () {
        
            SimpleDialog.superclass.initDefaultConfig.call(this);
        
            // Add dialog config properties //
        
            /**
            * Sets the informational icon for the SimpleDialog
            * @config icon
            * @type String
            * @default "none"
            */
            this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
                handler: this.configIcon,
                value: DEFAULT_CONFIG.ICON.value,
                suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
            });
        
            /**
            * Sets the text for the SimpleDialog
            * @config text
            * @type String
            * @default ""
            */
            this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, { 
                handler: this.configText, 
                value: DEFAULT_CONFIG.TEXT.value, 
                suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent, 
                supercedes: DEFAULT_CONFIG.TEXT.supercedes 
            });
        
        },
        
        
        /**
        * The SimpleDialog initialization method, which is executed for 
        * SimpleDialog and all of its subclasses. This method is automatically 
        * called by the constructor, and  sets up all DOM references for 
        * pre-existing markup, and creates required markup if it is not 
        * already present.
        * @method init
        * @param {String} el The element ID representing the SimpleDialog 
        * <em>OR</em>
        * @param {HTMLElement} el The element representing the SimpleDialog
        * @param {Object} userConfig The configuration object literal 
        * containing the configuration that should be set for this 
        * SimpleDialog. See configuration documentation for more details.
        */
        init: function (el, userConfig) {

            /*
                Note that we don't pass the user config in here yet because we 
                only want it executed once, at the lowest subclass level
            */

            SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
        
            this.beforeInitEvent.fire(SimpleDialog);
        
            Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
        
            this.cfg.queueProperty("postmethod", "manual");
        
            if (userConfig) {
                this.cfg.applyConfig(userConfig, true);
            }
        
            this.beforeRenderEvent.subscribe(function () {
                if (! this.body) {
                    this.setBody("");
                }
            }, this, true);
        
            this.initEvent.fire(SimpleDialog);
        
        },
        
        /**
        * Prepares the SimpleDialog's internal FORM object, creating one if one 
        * is not currently present, and adding the value hidden field.
        * @method registerForm
        */
        registerForm: function () {

            SimpleDialog.superclass.registerForm.call(this);

            this.form.innerHTML += "<input type=\"hidden\" name=\"" + 
                this.id + "\" value=\"\"/>";

        },
        
        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
        
        /**
        * Fired when the "icon" property is set.
        * @method configIcon
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configIcon: function (type,args,obj) {
        
            var sIcon = args[0],
                oBody = this.body,
                sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
                oIcon,
                oIconParent;
        
            if (sIcon && sIcon != "none") {

                oIcon = Dom.getElementsByClassName(sCSSClass, "*" , oBody);

                if (oIcon) {

                    oIconParent = oIcon.parentNode;
                    
                    if (oIconParent) {
                    
                        oIconParent.removeChild(oIcon);
                        
                        oIcon = null;
                    
                    }

                }


                if (sIcon.indexOf(".") == -1) {

                    oIcon = document.createElement("span");
                    oIcon.className = (sCSSClass + " " + sIcon);
                    oIcon.innerHTML = "&#160;";

                } else {

                    oIcon = document.createElement("img");
                    oIcon.src = (this.imageRoot + sIcon);
                    oIcon.className = sCSSClass;

                }
                

                if (oIcon) {
                
                    oBody.insertBefore(oIcon, oBody.firstChild);
                
                }

            }

        },
        
        /**
        * Fired when the "text" property is set.
        * @method configText
        * @param {String} type The CustomEvent type (usually the property name)
        * @param {Object[]} args The CustomEvent arguments. For configuration 
        * handlers, args[0] will equal the newly applied value for the property.
        * @param {Object} obj The scope object. For configuration handlers, 
        * this will usually equal the owner.
        */
        configText: function (type,args,obj) {
            var text = args[0];
            if (text) {
                this.setBody(text);
                this.cfg.refireEvent("icon");
            }
        },
        
        // END BUILT-IN PROPERTY EVENT HANDLERS //
        
        /**
        * Returns a string representation of the object.
        * @method toString
        * @return {String} The string representation of the SimpleDialog
        */
        toString: function () {
            return "SimpleDialog " + this.id;
        }
    
    });

}());

(function () {

    /**
    * ContainerEffect encapsulates animation transitions that are executed when 
    * an Overlay is shown or hidden.
    * @namespace YAHOO.widget
    * @class ContainerEffect
    * @constructor
    * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation 
    * should be associated with
    * @param {Object} attrIn The object literal representing the animation 
    * arguments to be used for the animate-in transition. The arguments for 
    * this literal are: attributes(object, see YAHOO.util.Anim for description), 
    * duration(Number), and method(i.e. Easing.easeIn).
    * @param {Object} attrOut The object literal representing the animation 
    * arguments to be used for the animate-out transition. The arguments for  
    * this literal are: attributes(object, see YAHOO.util.Anim for description), 
    * duration(Number), and method(i.e. Easing.easeIn).
    * @param {HTMLElement} targetElement Optional. The target element that  
    * should be animated during the transition. Defaults to overlay.element.
    * @param {class} Optional. The animation class to instantiate. Defaults to 
    * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
    */
    YAHOO.widget.ContainerEffect = 
    
        function (overlay, attrIn, attrOut, targetElement, animClass) {
    
        if (!animClass) {
            animClass = YAHOO.util.Anim;
        }
        
        /**
        * The overlay to animate
        * @property overlay
        * @type YAHOO.widget.Overlay
        */
        this.overlay = overlay;
    
        /**
        * The animation attributes to use when transitioning into view
        * @property attrIn
        * @type Object
        */
        this.attrIn = attrIn;
    
        /**
        * The animation attributes to use when transitioning out of view
        * @property attrOut
        * @type Object
        */
        this.attrOut = attrOut;
    
        /**
        * The target element to be animated
        * @property targetElement
        * @type HTMLElement
        */
        this.targetElement = targetElement || overlay.element;
    
        /**
        * The animation class to use for animating the overlay
        * @property animClass
        * @type class
        */
        this.animClass = animClass;
    
    };


    var Dom = YAHOO.util.Dom,
        CustomEvent = YAHOO.util.CustomEvent,
        Easing = YAHOO.util.Easing,
        ContainerEffect = YAHOO.widget.ContainerEffect;


    /**
    * A pre-configured ContainerEffect instance that can be used for fading 
    * an overlay in and out.
    * @method FADE
    * @static
    * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
    * @param {Number} dur The duration of the animation
    * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
    */
    ContainerEffect.FADE = function (overlay, dur) {

        var fin = {
            attributes: {opacity:{from:0, to:1}},
            duration: dur,
            method: Easing.easeIn
        };

        var fout = {
            attributes: {opacity:{to:0}},
            duration: dur,
            method: Easing.easeOut
        };

        var fade = new ContainerEffect(overlay, fin, fout, overlay.element);

        fade.handleUnderlayStart = function() {
            var underlay = this.overlay.underlay;
            if (underlay && YAHOO.env.ua.ie) {
                var hasFilters = (underlay.filters && underlay.filters.length > 0);
                if(hasFilters) {
                    Dom.addClass(overlay.element, "yui-effect-fade");
                }
            }
        };

        fade.handleUnderlayComplete = function() {
            var underlay = this.overlay.underlay;
            if (underlay && YAHOO.env.ua.ie) {
                Dom.removeClass(overlay.element, "yui-effect-fade");
            }
        };

        fade.handleStartAnimateIn = function (type,args,obj) {
            Dom.addClass(obj.overlay.element, "hide-select");

            if (!obj.overlay.underlay) {
                obj.overlay.cfg.refireEvent("underlay");
            }

            obj.handleUnderlayStart();

            Dom.setStyle(obj.overlay.element, "visibility", "visible");
            Dom.setStyle(obj.overlay.element, "opacity", 0);
        };

        fade.handleCompleteAnimateIn = function (type,args,obj) {
            Dom.removeClass(obj.overlay.element, "hide-select");

            if (obj.overlay.element.style.filter) {
                obj.overlay.element.style.filter = null;
            }

            obj.handleUnderlayComplete();

            obj.overlay.cfg.refireEvent("iframe");
            obj.animateInCompleteEvent.fire();
        };

        fade.handleStartAnimateOut = function (type, args, obj) {
            Dom.addClass(obj.overlay.element, "hide-select");
            obj.handleUnderlayStart();
        };

        fade.handleCompleteAnimateOut =  function (type, args, obj) {
            Dom.removeClass(obj.overlay.element, "hide-select");
            if (obj.overlay.element.style.filter) {
                obj.overlay.element.style.filter = null;
            }
            Dom.setStyle(obj.overlay.element, "visibility", "hidden");
            Dom.setStyle(obj.overlay.element, "opacity", 1);

            obj.handleUnderlayComplete();

            obj.overlay.cfg.refireEvent("iframe");
            obj.animateOutCompleteEvent.fire();
        };

        fade.init();
        return fade;
    };
    
    
    /**
    * A pre-configured ContainerEffect instance that can be used for sliding an 
    * overlay in and out.
    * @method SLIDE
    * @static
    * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
    * @param {Number} dur The duration of the animation
    * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
    */
    ContainerEffect.SLIDE = function (overlay, dur) {
    
        var x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
    
            y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
    
            clientWidth = Dom.getClientWidth(),
    
            offsetWidth = overlay.element.offsetWidth,
    
            slide = new ContainerEffect(overlay, 
            
            { attributes: { points: { to: [x, y] } },
                duration: dur,
                method: Easing.easeIn },
    
            { attributes: { points: { to: [(clientWidth + 25), y] } },
                duration: dur,
                method: Easing.easeOut },
    
            overlay.element, YAHOO.util.Motion);
        
        
        slide.handleStartAnimateIn = function (type,args,obj) {
            obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
            obj.overlay.element.style.top  = y + "px";
        };
        
        slide.handleTweenAnimateIn = function (type, args, obj) {
        
            var pos = Dom.getXY(obj.overlay.element),
                currentX = pos[0],
                currentY = pos[1];
        
            if (Dom.getStyle(obj.overlay.element, "visibility") == 
                "hidden" && currentX < x) {

                Dom.setStyle(obj.overlay.element, "visibility", "visible");

            }
        
            obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
            obj.overlay.cfg.refireEvent("iframe");
        };
        
        slide.handleCompleteAnimateIn = function (type, args, obj) {
            obj.overlay.cfg.setProperty("xy", [x, y], true);
            obj.startX = x;
            obj.startY = y;
            obj.overlay.cfg.refireEvent("iframe");
            obj.animateInCompleteEvent.fire();
        };
        
        slide.handleStartAnimateOut = function (type, args, obj) {
    
            var vw = Dom.getViewportWidth(),
                pos = Dom.getXY(obj.overlay.element),
                yso = pos[1];
    
            obj.animOut.attributes.points.to = [(vw + 25), yso];
        };
        
        slide.handleTweenAnimateOut = function (type, args, obj) {
    
            var pos = Dom.getXY(obj.overlay.element),
                xto = pos[0],
                yto = pos[1];
        
            obj.overlay.cfg.setProperty("xy", [xto, yto], true);
            obj.overlay.cfg.refireEvent("iframe");
        };
        
        slide.handleCompleteAnimateOut = function (type, args, obj) {
            Dom.setStyle(obj.overlay.element, "visibility", "hidden");
        
            obj.overlay.cfg.setProperty("xy", [x, y]);
            obj.animateOutCompleteEvent.fire();
        };
        
        slide.init();
        return slide;
    };
    
    ContainerEffect.prototype = {
    
        /**
        * Initializes the animation classes and events.
        * @method init
        */
        init: function () {

            this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
            this.beforeAnimateInEvent.signature = CustomEvent.LIST;
            
            this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
            this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
        
            this.animateInCompleteEvent = this.createEvent("animateInComplete");
            this.animateInCompleteEvent.signature = CustomEvent.LIST;
        
            this.animateOutCompleteEvent = 
                this.createEvent("animateOutComplete");
            this.animateOutCompleteEvent.signature = CustomEvent.LIST;
        
            this.animIn = new this.animClass(this.targetElement, 
                this.attrIn.attributes, this.attrIn.duration, 
                this.attrIn.method);

            this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
            this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);

            this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn, 
                this);
        
            this.animOut = new this.animClass(this.targetElement, 
                this.attrOut.attributes, this.attrOut.duration, 
                this.attrOut.method);

            this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
            this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
            this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, 
                this);

        },
        
        /**
        * Triggers the in-animation.
        * @method animateIn
        */
        animateIn: function () {
            this.beforeAnimateInEvent.fire();
            this.animIn.animate();
        },
        
        /**
        * Triggers the out-animation.
        * @method animateOut
        */
        animateOut: function () {
            this.beforeAnimateOutEvent.fire();
            this.animOut.animate();
        },
        
        /**
        * The default onStart handler for the in-animation.
        * @method handleStartAnimateIn
        * @param {String} type The CustomEvent type
        * @param {Object[]} args The CustomEvent arguments
        * @param {Object} obj The scope object
        */
        handleStartAnimateIn: function (type, args, obj) { },
    
        /**
        * The default onTween handler for the in-animation.
        * @method handleTweenAnimateIn
        * @param {String} type The CustomEvent type
        * @param {Object[]} args The CustomEvent arguments
        * @param {Object} obj The scope object
        */
        handleTweenAnimateIn: function (type, args, obj) { },
    
        /**
        * The default onComplete handler for the in-animation.
        * @method handleCompleteAnimateIn
        * @param {String} type The CustomEvent type
        * @param {Object[]} args The CustomEvent arguments
        * @param {Object} obj The scope object
        */
        handleCompleteAnimateIn: function (type, args, obj) { },
        
        /**
        * The default onStart handler for the out-animation.
        * @method handleStartAnimateOut
        * @param {String} type The CustomEvent type
        * @param {Object[]} args The CustomEvent arguments
        * @param {Object} obj The scope object
        */
        handleStartAnimateOut: function (type, args, obj) { },
    
        /**
        * The default onTween handler for the out-animation.
        * @method handleTweenAnimateOut
        * @param {String} type The CustomEvent type
        * @param {Object[]} args The CustomEvent arguments
        * @param {Object} obj The scope object
        */
        handleTweenAnimateOut: function (type, args, obj) { },
    
        /**
        * The default onComplete handler for the out-animation.
        * @method handleCompleteAnimateOut
        * @param {String} type The CustomEvent type
        * @param {Object[]} args The CustomEvent arguments
        * @param {Object} obj The scope object
        */
        handleCompleteAnimateOut: function (type, args, obj) { },
        
        /**
        * Returns a string representation of the object.
        * @method toString
        * @return {String} The string representation of the ContainerEffect
        */
        toString: function () {
            var output = "ContainerEffect";
            if (this.overlay) {
                output += " [" + this.overlay.toString() + "]";
            }
            return output;
        }
    
    };

    YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);

})();

YAHOO.register("container", YAHOO.widget.Module, {version: "2.5.2", build: "1076"});
/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.5.2
*/


/**
* @module menu
* @description <p>The Menu family of components features a collection of 
* controls that make it easy to add menus to your website or web application.  
* With the Menu Controls you can create website fly-out menus, customized 
* context menus, or application-style menu bars with just a small amount of 
* scripting.</p><p>The Menu family of controls features:</p>
* <ul>
*    <li>Keyboard and mouse navigation.</li>
*    <li>A rich event model that provides access to all of a menu's 
*    interesting moments.</li>
*    <li>Support for 
*    <a href="http://en.wikipedia.org/wiki/Progressive_Enhancement">Progressive
*    Enhancement</a>; Menus can be created from simple, 
*    semantic markup on the page or purely through JavaScript.</li>
* </ul>
* @title Menu
* @namespace YAHOO.widget
* @requires Event, Dom, Container
*/
(function () {

    var Dom = YAHOO.util.Dom,
        Event = YAHOO.util.Event;


    /**
    * Singleton that manages a collection of all menus and menu items.  Listens 
    * for DOM events at the document level and dispatches the events to the 
    * corresponding menu or menu item.
    *
    * @namespace YAHOO.widget
    * @class MenuManager
    * @static
    */
    YAHOO.widget.MenuManager = function () {
    
        // Private member variables
    
    
        // Flag indicating if the DOM event handlers have been attached
    
        var m_bInitializedEventHandlers = false,
    
    
        // Collection of menus

        m_oMenus = {},


        // Collection of visible menus
    
        m_oVisibleMenus = {},
    
    
        //  Collection of menu items 

        m_oItems = {},


        // Map of DOM event types to their equivalent CustomEvent types
        
        m_oEventTypes = {
            "click": "clickEvent",
            "mousedown": "mouseDownEvent",
            "mouseup": "mouseUpEvent",
            "mouseover": "mouseOverEvent",
            "mouseout": "mouseOutEvent",
            "keydown": "keyDownEvent",
            "keyup": "keyUpEvent",
            "keypress": "keyPressEvent"
        },
    
    
        m_oFocusedMenuItem = null;
    
    
    
    
    
        // Private methods
    
    
        /**
        * @method getMenuRootElement
        * @description Finds the root DIV node of a menu or the root LI node of 
        * a menu item.
        * @private
        * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object 
        * specifying an HTML element.
        */
        function getMenuRootElement(p_oElement) {
        
            var oParentNode;
    
            if (p_oElement && p_oElement.tagName) {
            
                switch (p_oElement.tagName.toUpperCase()) {
                        
                case "DIV":
    
                    oParentNode = p_oElement.parentNode;
    
                    // Check if the DIV is the inner "body" node of a menu

                    if (
                        (
                            Dom.hasClass(p_oElement, "hd") ||
                            Dom.hasClass(p_oElement, "bd") ||
                            Dom.hasClass(p_oElement, "ft")
                        ) && 
                        oParentNode && 
                        oParentNode.tagName && 
                        oParentNode.tagName.toUpperCase() == "DIV") 
                    {
                    
                        return oParentNode;
                    
                    }
                    else {
                    
                        return p_oElement;
                    
                    }
                
                    break;

                case "LI":
    
                    return p_oElement;

                default:
    
                    oParentNode = p_oElement.parentNode;
    
                    if (oParentNode) {
                    
                        return getMenuRootElement(oParentNode);
                    
                    }
                
                    break;
                
                }
    
            }
            
        }
    
    
    
        // Private event handlers
    
    
        /**
        * @method onDOMEvent
        * @description Generic, global event handler for all of a menu's 
        * DOM-based events.  This listens for events against the document 
        * object.  If the target of a given event is a member of a menu or 
        * menu item's DOM, the instance's corresponding Custom Event is fired.
        * @private
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        function onDOMEvent(p_oEvent) {
    
            // Get the target node of the DOM event
        
            var oTarget = Event.getTarget(p_oEvent),
                
            // See if the target of the event was a menu, or a menu item
    
            oElement = getMenuRootElement(oTarget),
            sCustomEventType,
            sTagName,
            sId,
            oMenuItem,
            oMenu; 
    
    
            if (oElement) {
    
                sTagName = oElement.tagName.toUpperCase();
        
                if (sTagName == "LI") {
            
                    sId = oElement.id;
            
                    if (sId && m_oItems[sId]) {
            
                        oMenuItem = m_oItems[sId];
                        oMenu = oMenuItem.parent;
            
                    }
                
                }
                else if (sTagName == "DIV") {
                
                    if (oElement.id) {
                    
                        oMenu = m_oMenus[oElement.id];
                    
                    }
                
                }
    
            }
    
    
            if (oMenu) {
    
                sCustomEventType = m_oEventTypes[p_oEvent.type];
    
    
                // Fire the Custom Event that corresponds the current DOM event    
        
                if (oMenuItem && !oMenuItem.cfg.getProperty("disabled")) {
    
                    oMenuItem[sCustomEventType].fire(p_oEvent);                   
    
    
                    if (
                            p_oEvent.type == "keyup" || 
                            p_oEvent.type == "mousedown") 
                    {
    
                        if (m_oFocusedMenuItem != oMenuItem) {
                        
                            if (m_oFocusedMenuItem) {
    
                                m_oFocusedMenuItem.blurEvent.fire();
                            
                            }
    
                            oMenuItem.focusEvent.fire();
                        
                        }
                    
                    }
    
                }
        
                oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
            
            }
            else if (p_oEvent.type == "mousedown") {
    
                if (m_oFocusedMenuItem) {
    
                    m_oFocusedMenuItem.blurEvent.fire();
    
                    m_oFocusedMenuItem = null;
    
                }
    
    
                /*
                    If the target of the event wasn't a menu, hide all 
                    dynamically positioned menus
                */
                
                for (var i in m_oVisibleMenus) {
        
                    if (YAHOO.lang.hasOwnProperty(m_oVisibleMenus, i)) {
        
                        oMenu = m_oVisibleMenus[i];

                        if (oMenu.cfg.getProperty("clicktohide") && 
                            !(oMenu instanceof YAHOO.widget.MenuBar) && 
                            oMenu.cfg.getProperty("position") == "dynamic") {
        
                            oMenu.hide();
        
                        }
                        else {
                            
							if (oMenu.cfg.getProperty("showdelay") > 0) {
							
								oMenu._cancelShowDelay();
							
							}


							if (oMenu.activeItem) {
						
								oMenu.activeItem.blur();
								oMenu.activeItem.cfg.setProperty("selected", false);
						
								oMenu.activeItem = null;            
						
							}
        
                        }
        
                    }
        
                } 
    
            }
            else if (p_oEvent.type == "keyup") { 
    
                if (m_oFocusedMenuItem) {
    
                    m_oFocusedMenuItem.blurEvent.fire();
    
                    m_oFocusedMenuItem = null;
    
                }
    
            }
    
        }
    
    
        /**
        * @method onMenuDestroy
        * @description "destroy" event handler for a menu.
        * @private
        * @param {String} p_sType String representing the name of the event 
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
        */
        function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
    
            if (m_oMenus[p_oMenu.id]) {
    
                this.removeMenu(p_oMenu);
    
            }
    
        }
    
    
        /**
        * @method onMenuFocus
        * @description "focus" event handler for a MenuItem instance.
        * @private
        * @param {String} p_sType String representing the name of the event 
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        */
        function onMenuFocus(p_sType, p_aArgs) {
    
            var oItem = p_aArgs[0];
    
            if (oItem) {
    
                m_oFocusedMenuItem = oItem;
            
            }
    
        }
    
    
        /**
        * @method onMenuBlur
        * @description "blur" event handler for a MenuItem instance.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        */
        function onMenuBlur(p_sType, p_aArgs) {
    
            m_oFocusedMenuItem = null;
    
        }
    
    
    
        /**
        * @method onMenuVisibleConfigChange
        * @description Event handler for when the "visible" configuration  
        * property of a Menu instance changes.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        */
        function onMenuVisibleConfigChange(p_sType, p_aArgs) {
    
            var bVisible = p_aArgs[0],
                sId = this.id;
            
            if (bVisible) {
    
                m_oVisibleMenus[sId] = this;
                
            
            }
            else if (m_oVisibleMenus[sId]) {
            
                delete m_oVisibleMenus[sId];
                
            
            }
        
        }
    
    
        /**
        * @method onItemDestroy
        * @description "destroy" event handler for a MenuItem instance.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        */
        function onItemDestroy(p_sType, p_aArgs) {
    
            removeItem(this);
    
        }

    
        function removeItem(p_oMenuItem) {

            var sId = p_oMenuItem.id;
    
            if (sId && m_oItems[sId]) {
    
                if (m_oFocusedMenuItem == p_oMenuItem) {
    
                    m_oFocusedMenuItem = null;
    
                }
    
                delete m_oItems[sId];
                
                p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
    
    
            }

        }
    
    
        /**
        * @method onItemAdded
        * @description "itemadded" event handler for a Menu instance.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        */
        function onItemAdded(p_sType, p_aArgs) {
    
            var oItem = p_aArgs[0],
                sId;
    
            if (oItem instanceof YAHOO.widget.MenuItem) { 
    
                sId = oItem.id;
        
                if (!m_oItems[sId]) {
            
                    m_oItems[sId] = oItem;
        
                    oItem.destroyEvent.subscribe(onItemDestroy);
        
        
                }
    
            }
        
        }
    
    
        return {
    
            // Privileged methods
    
    
            /**
            * @method addMenu
            * @description Adds a menu to the collection of known menus.
            * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu  
            * instance to be added.
            */
            addMenu: function (p_oMenu) {
    
                var oDoc;
    
                if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id && 
                    !m_oMenus[p_oMenu.id]) {
        
                    m_oMenus[p_oMenu.id] = p_oMenu;
                
            
                    if (!m_bInitializedEventHandlers) {
            
                        oDoc = document;
                
                        Event.on(oDoc, "mouseover", onDOMEvent, this, true);
                        Event.on(oDoc, "mouseout", onDOMEvent, this, true);
                        Event.on(oDoc, "mousedown", onDOMEvent, this, true);
                        Event.on(oDoc, "mouseup", onDOMEvent, this, true);
                        Event.on(oDoc, "click", onDOMEvent, this, true);
                        Event.on(oDoc, "keydown", onDOMEvent, this, true);
                        Event.on(oDoc, "keyup", onDOMEvent, this, true);
                        Event.on(oDoc, "keypress", onDOMEvent, this, true);
    
    
                        m_bInitializedEventHandlers = true;
                        
            
                    }
            
                    p_oMenu.cfg.subscribeToConfigEvent("visible", 
                        onMenuVisibleConfigChange);

                    p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, 
                                            this);
            
                    p_oMenu.itemAddedEvent.subscribe(onItemAdded);
                    p_oMenu.focusEvent.subscribe(onMenuFocus);
                    p_oMenu.blurEvent.subscribe(onMenuBlur);
        
        
                }
        
            },
    
        
            /**
            * @method removeMenu
            * @description Removes a menu from the collection of known menus.
            * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu  
            * instance to be removed.
            */
            removeMenu: function (p_oMenu) {
    
                var sId,
                    aItems,
                    i;
        
                if (p_oMenu) {
    
                    sId = p_oMenu.id;
        
                    if (m_oMenus[sId] == p_oMenu) {

                        // Unregister each menu item

                        aItems = p_oMenu.getItems();

                        if (aItems && aItems.length > 0) {

                            i = aItems.length - 1;

                            do {

                                removeItem(aItems[i]);

                            }
                            while (i--);

                        }


                        // Unregister the menu

                        delete m_oMenus[sId];
            
        

                        /*
                             Unregister the menu from the collection of 
                             visible menus
                        */

                        if (m_oVisibleMenus[sId] == p_oMenu) {
            
                            delete m_oVisibleMenus[sId];
                            
       
                        }


                        // Unsubscribe event listeners

                        if (p_oMenu.cfg) {

                            p_oMenu.cfg.unsubscribeFromConfigEvent("visible", 
                                onMenuVisibleConfigChange);
                            
                        }

                        p_oMenu.destroyEvent.unsubscribe(onMenuDestroy, 
                            p_oMenu);
                
                        p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
                        p_oMenu.focusEvent.unsubscribe(onMenuFocus);
                        p_oMenu.blurEvent.unsubscribe(onMenuBlur);

                    }
                
                }
    
            },
        
        
            /**
            * @method hideVisible
            * @description Hides all visible, dynamically positioned menus 
            * (excluding instances of YAHOO.widget.MenuBar).
            */
            hideVisible: function () {
        
                var oMenu;
        
                for (var i in m_oVisibleMenus) {
        
                    if (YAHOO.lang.hasOwnProperty(m_oVisibleMenus, i)) {
        
                        oMenu = m_oVisibleMenus[i];
        
                        if (!(oMenu instanceof YAHOO.widget.MenuBar) && 
                            oMenu.cfg.getProperty("position") == "dynamic") {
        
                            oMenu.hide();
        
                        }
        
                    }
        
                }        
    
            },


            /**
            * @method getVisible
            * @description Returns a collection of all visible menus registered
            * with the menu manger.
            * @return {Array}
            */
            getVisible: function () {
            
                return m_oVisibleMenus;
            
            },

    
            /**
            * @method getMenus
            * @description Returns a collection of all menus registered with the 
            * menu manger.
            * @return {Array}
            */
            getMenus: function () {
    
                return m_oMenus;
            
            },
    
    
            /**
            * @method getMenu
            * @description Returns a menu with the specified id.
            * @param {String} p_sId String specifying the id of the 
            * <code>&#60;div&#62;</code> element representing the menu to
            * be retrieved.
            * @return {YAHOO.widget.Menu}
            */
            getMenu: function (p_sId) {
    
                var oMenu = m_oMenus[p_sId];
        
                if (oMenu) {
                
                    return oMenu;
                
                }
            
            },
    
    
            /**
            * @method getMenuItem
            * @description Returns a menu item with the specified id.
            * @param {String} p_sId String specifying the id of the 
            * <code>&#60;li&#62;</code> element representing the menu item to
            * be retrieved.
            * @return {YAHOO.widget.MenuItem}
            */
            getMenuItem: function (p_sId) {
    
                var oItem = m_oItems[p_sId];
        
                if (oItem) {
                
                    return oItem;
                
                }
            
            },


            /**
            * @method getMenuItemGroup
            * @description Returns an array of menu item instances whose 
            * corresponding <code>&#60;li&#62;</code> elements are child 
            * nodes of the <code>&#60;ul&#62;</code> element with the 
            * specified id.
            * @param {String} p_sId String specifying the id of the 
            * <code>&#60;ul&#62;</code> element representing the group of 
            * menu items to be retrieved.
            * @return {Array}
            */
            getMenuItemGroup: function (p_sId) {

                var oUL = Dom.get(p_sId),
                    aItems,
                    oNode,
                    oItem,
                    sId;
    

                if (oUL && oUL.tagName && 
                    oUL.tagName.toUpperCase() == "UL") {

                    oNode = oUL.firstChild;

                    if (oNode) {

                        aItems = [];
                        
                        do {

                            sId = oNode.id;

                            if (sId) {
                            
                                oItem = this.getMenuItem(sId);
                                
                                if (oItem) {
                                
                                    aItems[aItems.length] = oItem;
                                
                                }
                            
                            }
                        
                        }
                        while ((oNode = oNode.nextSibling));


                        if (aItems.length > 0) {

                            return aItems;
                        
                        }

                    }
                
                }
            
            },

    
            /**
            * @method getFocusedMenuItem
            * @description Returns a reference to the menu item that currently 
            * has focus.
            * @return {YAHOO.widget.MenuItem}
            */
            getFocusedMenuItem: function () {
    
                return m_oFocusedMenuItem;
    
            },
    
    
            /**
            * @method getFocusedMenu
            * @description Returns a reference to the menu that currently 
            * has focus.
            * @return {YAHOO.widget.Menu}
            */
            getFocusedMenu: function () {
    
                if (m_oFocusedMenuItem) {
    
                    return (m_oFocusedMenuItem.parent.getRoot());
                
                }
    
            },
    
        
            /**
            * @method toString
            * @description Returns a string representing the menu manager.
            * @return {String}
            */
            toString: function () {
            
                return "MenuManager";
            
            }
    
        };
    
    }();

})();



(function () {


/**
* The Menu class creates a container that holds a vertical list representing 
* a set of options or commands.  Menu is the base class for all 
* menu containers. 
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;div&#62;</code> element of the menu.
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;select&#62;</code> element to be used as the data source 
* for the menu.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
* level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object 
* specifying the <code>&#60;div&#62;</code> element of the menu.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
* level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement 
* Object specifying the <code>&#60;select&#62;</code> element to be used as 
* the data source for the menu.
* @param {Object} p_oConfig Optional. Object literal specifying the 
* configuration for the menu. See configuration class documentation for 
* more details.
* @namespace YAHOO.widget
* @class Menu
* @constructor
* @extends YAHOO.widget.Overlay
*/
YAHOO.widget.Menu = function (p_oElement, p_oConfig) {

    if (p_oConfig) {

        this.parent = p_oConfig.parent;
        this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
        this.itemData = p_oConfig.itemData || p_oConfig.itemdata;

    }


    YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);

};



/**
* @method checkPosition
* @description Checks to make sure that the value of the "position" property 
* is one of the supported strings. Returns true if the position is supported.
* @private
* @param {Object} p_sPosition String specifying the position of the menu.
* @return {Boolean}
*/
function checkPosition(p_sPosition) {

    if (typeof p_sPosition == "string") {

        return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1);

    }

}


var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event,
    Module = YAHOO.widget.Module,
    Overlay = YAHOO.widget.Overlay,
    Menu = YAHOO.widget.Menu,
    MenuManager = YAHOO.widget.MenuManager,
    CustomEvent = YAHOO.util.CustomEvent,
    Lang = YAHOO.lang,
    UA = YAHOO.env.ua,
    
    m_oShadowTemplate,

    /**
    * Constant representing the name of the Menu's events
    * @property EVENT_TYPES
    * @private
    * @final
    * @type Object
    */
    EVENT_TYPES = {
    
        "MOUSE_OVER": "mouseover",
        "MOUSE_OUT": "mouseout",
        "MOUSE_DOWN": "mousedown",
        "MOUSE_UP": "mouseup",
        "CLICK": "click",
        "KEY_PRESS": "keypress",
        "KEY_DOWN": "keydown",
        "KEY_UP": "keyup",
        "FOCUS": "focus",
        "BLUR": "blur",
        "ITEM_ADDED": "itemAdded",
        "ITEM_REMOVED": "itemRemoved"
    
    },


    /**
    * Constant representing the Menu's configuration properties
    * @property DEFAULT_CONFIG
    * @private
    * @final
    * @type Object
    */
    DEFAULT_CONFIG = {

        "VISIBLE": { 
            key: "visible", 
            value: false, 
            validator: Lang.isBoolean
        }, 
    
        "CONSTRAIN_TO_VIEWPORT": {
            key: "constraintoviewport", 
            value: true, 
            validator: Lang.isBoolean, 
            supercedes: ["iframe","x","y","xy"]
        }, 
    
        "POSITION": { 
            key: "position", 
            value: "dynamic", 
            validator: checkPosition, 
            supercedes: ["visible", "iframe"]
        }, 
    
        "SUBMENU_ALIGNMENT": { 
            key: "submenualignment", 
            value: ["tl","tr"],
            suppressEvent: true
        },
    
        "AUTO_SUBMENU_DISPLAY": { 
            key: "autosubmenudisplay", 
            value: true, 
            validator: Lang.isBoolean,
            suppressEvent: true
        }, 
    
        "SHOW_DELAY": { 
            key: "showdelay", 
            value: 250, 
            validator: Lang.isNumber, 
            suppressEvent: true
        }, 
    
        "HIDE_DELAY": { 
            key: "hidedelay", 
            value: 0, 
            validator: Lang.isNumber, 
            suppressEvent: true
        }, 
    
        "SUBMENU_HIDE_DELAY": { 
            key: "submenuhidedelay", 
            value: 250, 
            validator: Lang.isNumber,
            suppressEvent: true
        }, 
    
        "CLICK_TO_HIDE": { 
            key: "clicktohide", 
            value: true, 
            validator: Lang.isBoolean,
            suppressEvent: true
        },
    
        "CONTAINER": { 
            key: "container",
            suppressEvent: true
        }, 

        "SCROLL_INCREMENT": { 
            key: "scrollincrement", 
            value: 1, 
            validator: Lang.isNumber,
            supercedes: ["maxheight"],
            suppressEvent: true
        },

        "MIN_SCROLL_HEIGHT": { 
            key: "minscrollheight", 
            value: 90, 
            validator: Lang.isNumber,
            supercedes: ["maxheight"],
            suppressEvent: true
        },    
    
        "MAX_HEIGHT": { 
            key: "maxheight", 
            value: 0, 
            validator: Lang.isNumber,
            supercedes: ["iframe"],
            suppressEvent: true
        }, 
    
        "CLASS_NAME": { 
            key: "classname", 
            value: null, 
            validator: Lang.isString,
            suppressEvent: true
        }, 
    
        "DISABLED": { 
            key: "disabled", 
            value: false, 
            validator: Lang.isBoolean,
            suppressEvent: true
        }
    
    };



YAHOO.lang.extend(Menu, Overlay, {


// Constants


/**
* @property CSS_CLASS_NAME
* @description String representing the CSS class(es) to be applied to the 
* menu's <code>&#60;div&#62;</code> element.
* @default "yuimenu"
* @final
* @type String
*/
CSS_CLASS_NAME: "yuimenu",


/**
* @property ITEM_TYPE
* @description Object representing the type of menu item to instantiate and 
* add when parsing the child nodes (either <code>&#60;li&#62;</code> element, 
* <code>&#60;optgroup&#62;</code> element or <code>&#60;option&#62;</code>) 
* of the menu's source HTML element.
* @default YAHOO.widget.MenuItem
* @final
* @type YAHOO.widget.MenuItem
*/
ITEM_TYPE: null,


/**
* @property GROUP_TITLE_TAG_NAME
* @description String representing the tagname of the HTML element used to 
* title the menu's item groups.
* @default H6
* @final
* @type String
*/
GROUP_TITLE_TAG_NAME: "h6",


/**
* @property OFF_SCREEN_POSITION
* @description Array representing the default x and y position that a menu 
* should have when it is positioned outside the viewport by the 
* "poistionOffScreen" method.
* @default [-10000, -10000]
* @final
* @type Array
*/
OFF_SCREEN_POSITION: [-10000, -10000],


// Private properties


/** 
* @property _nHideDelayId
* @description Number representing the time-out setting used to cancel the 
* hiding of a menu.
* @default null
* @private
* @type Number
*/
_nHideDelayId: null,


/** 
* @property _nShowDelayId
* @description Number representing the time-out setting used to cancel the 
* showing of a menu.
* @default null
* @private
* @type Number
*/
_nShowDelayId: null,


/** 
* @property _nSubmenuHideDelayId
* @description Number representing the time-out setting used to cancel the 
* hiding of a submenu.
* @default null
* @private
* @type Number
*/
_nSubmenuHideDelayId: null,


/** 
* @property _nBodyScrollId
* @description Number representing the time-out setting used to cancel the 
* scrolling of the menu's body element.
* @default null
* @private
* @type Number
*/
_nBodyScrollId: null,


/** 
* @property _bHideDelayEventHandlersAssigned
* @description Boolean indicating if the "mouseover" and "mouseout" event 
* handlers used for hiding the menu via a call to "window.setTimeout" have 
* already been assigned.
* @default false
* @private
* @type Boolean
*/
_bHideDelayEventHandlersAssigned: false,


/**
* @property _bHandledMouseOverEvent
* @description Boolean indicating the current state of the menu's 
* "mouseover" event.
* @default false
* @private
* @type Boolean
*/
_bHandledMouseOverEvent: false,


/**
* @property _bHandledMouseOutEvent
* @description Boolean indicating the current state of the menu's
* "mouseout" event.
* @default false
* @private
* @type Boolean
*/
_bHandledMouseOutEvent: false,


/**
* @property _aGroupTitleElements
* @description Array of HTML element used to title groups of menu items.
* @default []
* @private
* @type Array
*/
_aGroupTitleElements: null,


/**
* @property _aItemGroups
* @description Multi-dimensional Array representing the menu items as they
* are grouped in the menu.
* @default []
* @private
* @type Array
*/
_aItemGroups: null,


/**
* @property _aListElements
* @description Array of <code>&#60;ul&#62;</code> elements, each of which is 
* the parent node for each item's <code>&#60;li&#62;</code> element.
* @default []
* @private
* @type Array
*/
_aListElements: null,


/**
* @property _nCurrentMouseX
* @description The current x coordinate of the mouse inside the area of 
* the menu.
* @default 0
* @private
* @type Number
*/
_nCurrentMouseX: 0,


/**
* @property _bStopMouseEventHandlers
* @description Stops "mouseover," "mouseout," and "mousemove" event handlers 
* from executing.
* @default false
* @private
* @type Boolean
*/
_bStopMouseEventHandlers: false,


/**
* @property _sClassName
* @description The current value of the "classname" configuration attribute.
* @default null
* @private
* @type String
*/
_sClassName: null,



// Public properties


/**
* @property lazyLoad
* @description Boolean indicating if the menu's "lazy load" feature is 
* enabled.  If set to "true," initialization and rendering of the menu's 
* items will be deferred until the first time it is made visible.  This 
* property should be set via the constructor using the configuration 
* object literal.
* @default false
* @type Boolean
*/
lazyLoad: false,


/**
* @property itemData
* @description Array of items to be added to the menu.  The array can contain 
* strings representing the text for each item to be created, object literals 
* representing the menu item configuration properties, or MenuItem instances.  
* This property should be set via the constructor using the configuration 
* object literal.
* @default null
* @type Array
*/
itemData: null,


/**
* @property activeItem
* @description Object reference to the item in the menu that has is selected.
* @default null
* @type YAHOO.widget.MenuItem
*/
activeItem: null,


/**
* @property parent
* @description Object reference to the menu's parent menu or menu item.  
* This property can be set via the constructor using the configuration 
* object literal.
* @default null
* @type YAHOO.widget.MenuItem
*/
parent: null,


/**
* @property srcElement
* @description Object reference to the HTML element (either 
* <code>&#60;select&#62;</code> or <code>&#60;div&#62;</code>) used to 
* create the menu.
* @default null
* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
* level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a 
* href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
* html#ID-22445964">HTMLDivElement</a>
*/
srcElement: null,



// Events


/**
* @event mouseOverEvent
* @description Fires when the mouse has entered the menu.  Passes back 
* the DOM Event object as an argument.
*/
mouseOverEvent: null,


/**
* @event mouseOutEvent
* @description Fires when the mouse has left the menu.  Passes back the DOM 
* Event object as an argument.
* @type YAHOO.util.CustomEvent
*/
mouseOutEvent: null,


/**
* @event mouseDownEvent
* @description Fires when the user mouses down on the menu.  Passes back the 
* DOM Event object as an argument.
* @type YAHOO.util.CustomEvent
*/
mouseDownEvent: null,


/**
* @event mouseUpEvent
* @description Fires when the user releases a mouse button while the mouse is 
* over the menu.  Passes back the DOM Event object as an argument.
* @type YAHOO.util.CustomEvent
*/
mouseUpEvent: null,


/**
* @event clickEvent
* @description Fires when the user clicks the on the menu.  Passes back the 
* DOM Event object as an argument.
* @type YAHOO.util.CustomEvent
*/
clickEvent: null,


/**
* @event keyPressEvent
* @description Fires when the user presses an alphanumeric key when one of the
* menu's items has focus.  Passes back the DOM Event object as an argument.
* @type YAHOO.util.CustomEvent
*/
keyPressEvent: null,


/**
* @event keyDownEvent
* @description Fires when the user presses a key when one of the menu's items 
* has focus.  Passes back the DOM Event object as an argument.
* @type YAHOO.util.CustomEvent
*/
keyDownEvent: null,


/**
* @event keyUpEvent
* @description Fires when the user releases a key when one of the menu's items 
* has focus.  Passes back the DOM Event object as an argument.
* @type YAHOO.util.CustomEvent
*/
keyUpEvent: null,


/**
* @event itemAddedEvent
* @description Fires when an item is added to the menu.
* @type YAHOO.util.CustomEvent
*/
itemAddedEvent: null,


/**
* @event itemRemovedEvent
* @description Fires when an item is removed to the menu.
* @type YAHOO.util.CustomEvent
*/
itemRemovedEvent: null,


/**
* @method init
* @description The Menu class's initialization method. This method is 
* automatically called by the constructor, and sets up all DOM references 
* for pre-existing markup, and creates required markup if it is not 
* already present.
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;div&#62;</code> element of the menu.
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;select&#62;</code> element to be used as the data source 
* for the menu.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
* level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object 
* specifying the <code>&#60;div&#62;</code> element of the menu.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
* level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement 
* Object specifying the <code>&#60;select&#62;</code> element to be used as 
* the data source for the menu.
* @param {Object} p_oConfig Optional. Object literal specifying the 
* configuration for the menu. See configuration class documentation for 
* more details.
*/
init: function (p_oElement, p_oConfig) {

    this._aItemGroups = [];
    this._aListElements = [];
    this._aGroupTitleElements = [];

    if (!this.ITEM_TYPE) {

        this.ITEM_TYPE = YAHOO.widget.MenuItem;

    }


    var oElement;

    if (typeof p_oElement == "string") {

        oElement = document.getElementById(p_oElement);

    }
    else if (p_oElement.tagName) {

        oElement = p_oElement;

    }


    if (oElement && oElement.tagName) {

        switch(oElement.tagName.toUpperCase()) {
    
            case "DIV":

                this.srcElement = oElement;

                if (!oElement.id) {

                    oElement.setAttribute("id", Dom.generateId());

                }


                /* 
                    Note: we don't pass the user config in here yet 
                    because we only want it executed once, at the lowest 
                    subclass level.
                */ 
            
                Menu.superclass.init.call(this, oElement);

                this.beforeInitEvent.fire(Menu);


    
            break;
    
            case "SELECT":
    
                this.srcElement = oElement;

    
                /*
                    The source element is not something that we can use 
                    outright, so we need to create a new Overlay

                    Note: we don't pass the user config in here yet 
                    because we only want it executed once, at the lowest 
                    subclass level.
                */ 

                Menu.superclass.init.call(this, Dom.generateId());

                this.beforeInitEvent.fire(Menu);



            break;

        }

    }
    else {

        /* 
            Note: we don't pass the user config in here yet 
            because we only want it executed once, at the lowest 
            subclass level.
        */ 
    
        Menu.superclass.init.call(this, p_oElement);

        this.beforeInitEvent.fire(Menu);



    }


    if (this.element) {

        Dom.addClass(this.element, this.CSS_CLASS_NAME);


        // Subscribe to Custom Events

        this.initEvent.subscribe(this._onInit);
        this.beforeRenderEvent.subscribe(this._onBeforeRender);
        this.renderEvent.subscribe(this._onRender);
        this.renderEvent.subscribe(this.onRender);
        this.beforeShowEvent.subscribe(this._onBeforeShow);
        this.hideEvent.subscribe(this.positionOffScreen);
        this.showEvent.subscribe(this._onShow);
        this.beforeHideEvent.subscribe(this._onBeforeHide);
        this.mouseOverEvent.subscribe(this._onMouseOver);
        this.mouseOutEvent.subscribe(this._onMouseOut);
        this.clickEvent.subscribe(this._onClick);
        this.keyDownEvent.subscribe(this._onKeyDown);
        this.keyPressEvent.subscribe(this._onKeyPress);
        

        if (UA.gecko || UA.webkit) {

            this.cfg.subscribeToConfigEvent("y", this._onYChange);

        }


        if (p_oConfig) {
    
            this.cfg.applyConfig(p_oConfig, true);
    
        }


        // Register the Menu instance with the MenuManager

        MenuManager.addMenu(this);
        

        this.initEvent.fire(Menu);

    }

},



// Private methods


/**
* @method _initSubTree
* @description Iterates the childNodes of the source element to find nodes 
* used to instantiate menu and menu items.
* @private
*/
_initSubTree: function () {

    var oSrcElement = this.srcElement,
        sSrcElementTagName,
        nGroup,
        sGroupTitleTagName,
        oNode,
        aListElements,
        nListElements,
        i;


    if (oSrcElement) {
    
        sSrcElementTagName = 
            (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());


        if (sSrcElementTagName == "DIV") {
    
            //  Populate the collection of item groups and item group titles
    
            oNode = this.body.firstChild;
    

            if (oNode) {
    
                nGroup = 0;
                sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
        
                do {
        

                    if (oNode && oNode.tagName) {
        
                        switch (oNode.tagName.toUpperCase()) {
        
                            case sGroupTitleTagName:
                            
                                this._aGroupTitleElements[nGroup] = oNode;
        
                            break;
        
                            case "UL":
        
                                this._aListElements[nGroup] = oNode;
                                this._aItemGroups[nGroup] = [];
                                nGroup++;
        
                            break;
        
                        }
                    
                    }
        
                }
                while ((oNode = oNode.nextSibling));
        
        
                /*
                    Apply the "first-of-type" class to the first UL to mimic 
                    the "first-of-type" CSS3 psuedo class.
                */
        
                if (this._aListElements[0]) {
        
                    Dom.addClass(this._aListElements[0], "first-of-type");
        
                }
            
            }
    
        }
    
    
        oNode = null;
    
    

        if (sSrcElementTagName) {
    
            switch (sSrcElementTagName) {
        
                case "DIV":

                    aListElements = this._aListElements;
                    nListElements = aListElements.length;
        
                    if (nListElements > 0) {
        
        
                        i = nListElements - 1;
        
                        do {
        
                            oNode = aListElements[i].firstChild;
            
                            if (oNode) {

            
                                do {
                
                                    if (oNode && oNode.tagName && 
                                        oNode.tagName.toUpperCase() == "LI") {
                
        
                                        this.addItem(new this.ITEM_TYPE(oNode, 
                                                    { parent: this }), i);
            
                                    }
                        
                                }
                                while ((oNode = oNode.nextSibling));
                            
                            }
                    
                        }
                        while (i--);
        
                    }
        
                break;
        
                case "SELECT":
        
        
                    oNode = oSrcElement.firstChild;
        
                    do {
        
                        if (oNode && oNode.tagName) {
                        
                            switch (oNode.tagName.toUpperCase()) {
            
                                case "OPTGROUP":
                                case "OPTION":
            
            
                                    this.addItem(
                                            new this.ITEM_TYPE(
                                                    oNode, 
                                                    { parent: this }
                                                )
                                            );
            
                                break;
            
                            }
    
                        }
        
                    }
                    while ((oNode = oNode.nextSibling));
        
                break;
        
            }
    
        }    
    
    }

},


/**
* @method _getFirstEnabledItem
* @description Returns the first enabled item in the menu.
* @return {YAHOO.widget.MenuItem}
* @private
*/
_getFirstEnabledItem: function () {

    var aItems = this.getItems(),
        nItems = aItems.length,
        oItem;
    
    for(var i=0; i<nItems; i++) {

        oItem = aItems[i];

        if (oItem && !oItem.cfg.getProperty("disabled") && 
            oItem.element.style.display != "none") {

            return oItem;

        }
    
    }
    
},


/**
* @method _addItemToGroup
* @description Adds a menu item to a group.
* @private
* @param {Number} p_nGroupIndex Number indicating the group to which the 
* item belongs.
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
* instance to be added to the menu.
* @param {String} p_oItem String specifying the text of the item to be added 
* to the menu.
* @param {Object} p_oItem Object literal containing a set of menu item 
* configuration properties.
* @param {Number} p_nItemIndex Optional. Number indicating the index at 
* which the menu item should be added.
* @return {YAHOO.widget.MenuItem}
*/
_addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {

    var oItem,
        nGroupIndex,
        aGroup,
        oGroupItem,
        bAppend,
        oNextItemSibling,
        nItemIndex;

    function getNextItemSibling(p_aArray, p_nStartIndex) {

        return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray, 
                (p_nStartIndex+1)));

    }

    if (p_oItem instanceof this.ITEM_TYPE) {

        oItem = p_oItem;
        oItem.parent = this;

    }
    else if (typeof p_oItem == "string") {

        oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
    
    }
    else if (typeof p_oItem == "object") {

        p_oItem.parent = this;

        oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);

    }


    if (oItem) {

        if (oItem.cfg.getProperty("selected")) {

            this.activeItem = oItem;
        
        }


        nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
        aGroup = this._getItemGroup(nGroupIndex);



        if (!aGroup) {

            aGroup = this._createItemGroup(nGroupIndex);

        }


        if (typeof p_nItemIndex == "number") {

            bAppend = (p_nItemIndex >= aGroup.length);            


            if (aGroup[p_nItemIndex]) {
    
                aGroup.splice(p_nItemIndex, 0, oItem);
    
            }
            else {
    
                aGroup[p_nItemIndex] = oItem;
    
            }


            oGroupItem = aGroup[p_nItemIndex];

            if (oGroupItem) {

                if (bAppend && (!oGroupItem.element.parentNode || 
                        oGroupItem.element.parentNode.nodeType == 11)) {
        
                    this._aListElements[nGroupIndex].appendChild(
                        oGroupItem.element);
    
                }
                else {
    
                    oNextItemSibling = getNextItemSibling(aGroup, 
                        (p_nItemIndex+1));
    
                    if (oNextItemSibling && (!oGroupItem.element.parentNode || 
                            oGroupItem.element.parentNode.nodeType == 11)) {
            
                        this._aListElements[nGroupIndex].insertBefore(
                                oGroupItem.element, 
                                oNextItemSibling.element);
        
                    }
    
                }
    

                oGroupItem.parent = this;
        
                this._subscribeToItemEvents(oGroupItem);
    
                this._configureSubmenu(oGroupItem);
                
                this._updateItemProperties(nGroupIndex);
        

                this.itemAddedEvent.fire(oGroupItem);
                this.changeContentEvent.fire();

                return oGroupItem;
    
            }

        }
        else {
    
            nItemIndex = aGroup.length;
    
            aGroup[nItemIndex] = oItem;

            oGroupItem = aGroup[nItemIndex];
    

            if (oGroupItem) {
    
                if (!Dom.isAncestor(this._aListElements[nGroupIndex], 
                        oGroupItem.element)) {
    
                    this._aListElements[nGroupIndex].appendChild(
                        oGroupItem.element);
    
                }
    
                oGroupItem.element.setAttribute("groupindex", nGroupIndex);
                oGroupItem.element.setAttribute("index", nItemIndex);
        
                oGroupItem.parent = this;
    
                oGroupItem.index = nItemIndex;
                oGroupItem.groupIndex = nGroupIndex;
        
                this._subscribeToItemEvents(oGroupItem);
    
                this._configureSubmenu(oGroupItem);
    
                if (nItemIndex === 0) {
        
                    Dom.addClass(oGroupItem.element, "first-of-type");
        
                }

        

                this.itemAddedEvent.fire(oGroupItem);
                this.changeContentEvent.fire();

                return oGroupItem;
    
            }
    
        }

    }
    
},


/**
* @method _removeItemFromGroupByIndex
* @description Removes a menu item from a group by index.  Returns the menu 
* item that was removed.
* @private
* @param {Number} p_nGroupIndex Number indicating the group to which the menu 
* item belongs.
* @param {Number} p_nItemIndex Number indicating the index of the menu item 
* to be removed.
* @return {YAHOO.widget.MenuItem}
*/
_removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {

    var nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0,
        aGroup = this._getItemGroup(nGroupIndex),
        aArray,
        oItem,
        oUL;

    if (aGroup) {

        aArray = aGroup.splice(p_nItemIndex, 1);
        oItem = aArray[0];
    
        if (oItem) {
    
            // Update the index and className properties of each member        
            
            this._updateItemProperties(nGroupIndex);
    
            if (aGroup.length === 0) {
    
                // Remove the UL
    
                oUL = this._aListElements[nGroupIndex];
    
                if (this.body && oUL) {
    
                    this.body.removeChild(oUL);
    
                }
    
                // Remove the group from the array of items
    
                this._aItemGroups.splice(nGroupIndex, 1);
    
    
                // Remove the UL from the array of ULs
    
                this._aListElements.splice(nGroupIndex, 1);
    
    
                /*
                     Assign the "first-of-type" class to the new first UL 
                     in the collection
                */
    
                oUL = this._aListElements[0];
    
                if (oUL) {
    
                    Dom.addClass(oUL, "first-of-type");
    
                }            
    
            }
    

            this.itemRemovedEvent.fire(oItem);
            this.changeContentEvent.fire();


            // Return a reference to the item that was removed
        
            return oItem;
    
        }

    }
    
},


/**
* @method _removeItemFromGroupByValue
* @description Removes a menu item from a group by reference.  Returns the 
* menu item that was removed.
* @private
* @param {Number} p_nGroupIndex Number indicating the group to which the
* menu item belongs.
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
* instance to be removed.
* @return {YAHOO.widget.MenuItem}
*/    
_removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {

    var aGroup = this._getItemGroup(p_nGroupIndex),
        nItems,
        nItemIndex,
        i;

    if (aGroup) {

        nItems = aGroup.length;
        nItemIndex = -1;
    
        if (nItems > 0) {
    
            i = nItems-1;
        
            do {
        
                if (aGroup[i] == p_oItem) {
        
                    nItemIndex = i;
                    break;    
        
                }
        
            }
            while(i--);
        
            if (nItemIndex > -1) {
        
                return (this._removeItemFromGroupByIndex(p_nGroupIndex, 
                            nItemIndex));
        
            }
    
        }
    
    }

},


/**
* @method _updateItemProperties
* @description Updates the "index," "groupindex," and "className" properties 
* of the menu items in the specified group. 
* @private
* @param {Number} p_nGroupIndex Number indicating the group of items to update.
*/
_updateItemProperties: function (p_nGroupIndex) {

    var aGroup = this._getItemGroup(p_nGroupIndex),
        nItems = aGroup.length,
        oItem,
        oLI,
        i;


    if (nItems > 0) {

        i = nItems - 1;

        // Update the index and className properties of each member
    
        do {

            oItem = aGroup[i];

            if (oItem) {
    
                oLI = oItem.element;

                oItem.index = i;
                oItem.groupIndex = p_nGroupIndex;

                oLI.setAttribute("groupindex", p_nGroupIndex);
                oLI.setAttribute("index", i);

                Dom.removeClass(oLI, "first-of-type");

            }
    
        }
        while(i--);


        if (oLI) {

            Dom.addClass(oLI, "first-of-type");

        }

    }

},


/**
* @method _createItemGroup
* @description Creates a new menu item group (array) and its associated 
* <code>&#60;ul&#62;</code> element. Returns an aray of menu item groups.
* @private
* @param {Number} p_nIndex Number indicating the group to create.
* @return {Array}
*/
_createItemGroup: function (p_nIndex) {

    var oUL;

    if (!this._aItemGroups[p_nIndex]) {

        this._aItemGroups[p_nIndex] = [];

        oUL = document.createElement("ul");

        this._aListElements[p_nIndex] = oUL;

        return this._aItemGroups[p_nIndex];

    }

},


/**
* @method _getItemGroup
* @description Returns the menu item group at the specified index.
* @private
* @param {Number} p_nIndex Number indicating the index of the menu item group 
* to be retrieved.
* @return {Array}
*/
_getItemGroup: function (p_nIndex) {

    var nIndex = ((typeof p_nIndex == "number") ? p_nIndex : 0);

    return this._aItemGroups[nIndex];

},


/**
* @method _configureSubmenu
* @description Subscribes the menu item's submenu to its parent menu's events.
* @private
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
* instance with the submenu to be configured.
*/
_configureSubmenu: function (p_oItem) {

    var oSubmenu = p_oItem.cfg.getProperty("submenu");

    if (oSubmenu) {
            
        /*
            Listen for configuration changes to the parent menu 
            so they they can be applied to the submenu.
        */

        this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange, 
                oSubmenu, true);

        this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);

        oSubmenu.beforeShowEvent.subscribe(this._onSubmenuBeforeShow);

    }

},




/**
* @method _subscribeToItemEvents
* @description Subscribes a menu to a menu item's event.
* @private
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
* instance whose events should be subscribed to.
*/
_subscribeToItemEvents: function (p_oItem) {

    p_oItem.focusEvent.subscribe(this._onMenuItemFocus);

    p_oItem.blurEvent.subscribe(this._onMenuItemBlur);

    p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);

    p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange,
        p_oItem, this);

},


/**
* @method _onVisibleChange
* @description Change event handler for the the menu's "visible" configuration
* property.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onVisibleChange: function (p_sType, p_aArgs) {

    var bVisible = p_aArgs[0];
    
    if (bVisible) {

        Dom.addClass(this.element, "visible");

    }
    else {

        Dom.removeClass(this.element, "visible");

    }

},


/**
* @method _cancelHideDelay
* @description Cancels the call to "hideMenu."
* @private
*/
_cancelHideDelay: function () {

    var oRoot = this.getRoot();

    if (oRoot._nHideDelayId) {

        window.clearTimeout(oRoot._nHideDelayId);

    }

},


/**
* @method _execHideDelay
* @description Hides the menu after the number of milliseconds specified by 
* the "hidedelay" configuration property.
* @private
*/
_execHideDelay: function () {

    this._cancelHideDelay();

    var oRoot = this.getRoot(),
        me = this;

    function hideMenu() {
    
        if (oRoot.activeItem) {

            oRoot.clearActiveItem();

        }

        if (oRoot == me && !(me instanceof YAHOO.widget.MenuBar) && 
            me.cfg.getProperty("position") == "dynamic") {

            me.hide();
        
        }
    
    }


    oRoot._nHideDelayId = 
        window.setTimeout(hideMenu, oRoot.cfg.getProperty("hidedelay"));

},


/**
* @method _cancelShowDelay
* @description Cancels the call to the "showMenu."
* @private
*/
_cancelShowDelay: function () {

    var oRoot = this.getRoot();

    if (oRoot._nShowDelayId) {

        window.clearTimeout(oRoot._nShowDelayId);

    }

},


/**
* @method _execShowDelay
* @description Shows the menu after the number of milliseconds specified by 
* the "showdelay" configuration property have ellapsed.
* @private
* @param {YAHOO.widget.Menu} p_oMenu Object specifying the menu that should 
* be made visible.
*/
_execShowDelay: function (p_oMenu) {

    var oRoot = this.getRoot();

    function showMenu() {

        if (p_oMenu.parent.cfg.getProperty("selected")) {

            p_oMenu.show();

        }

    }


    oRoot._nShowDelayId = 
        window.setTimeout(showMenu, oRoot.cfg.getProperty("showdelay"));

},


/**
* @method _execSubmenuHideDelay
* @description Hides a submenu after the number of milliseconds specified by 
* the "submenuhidedelay" configuration property have ellapsed.
* @private
* @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that  
* should be hidden.
* @param {Number} p_nMouseX The x coordinate of the mouse when it left 
* the specified submenu's parent menu item.
* @param {Number} p_nHideDelay The number of milliseconds that should ellapse
* before the submenu is hidden.
*/
_execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {

    var me = this;

    p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () {

        if (me._nCurrentMouseX > (p_nMouseX + 10)) {

            p_oSubmenu._nSubmenuHideDelayId = window.setTimeout(function () {
        
                p_oSubmenu.hide();

            }, p_nHideDelay);

        }
        else {

            p_oSubmenu.hide();
        
        }

    }, 50);

},



// Protected methods


/**
* @method _disableScrollHeader
* @description Disables the header used for scrolling the body of the menu.
* @protected
*/
_disableScrollHeader: function () {

    if (!this._bHeaderDisabled) {

        Dom.addClass(this.header, "topscrollbar_disabled");
        this._bHeaderDisabled = true;

    }

},


/**
* @method _disableScrollFooter
* @description Disables the footer used for scrolling the body of the menu.
* @protected
*/
_disableScrollFooter: function () {

    if (!this._bFooterDisabled) {

        Dom.addClass(this.footer, "bottomscrollbar_disabled");
        this._bFooterDisabled = true;

    }

},


/**
* @method _enableScrollHeader
* @description Enables the header used for scrolling the body of the menu.
* @protected
*/
_enableScrollHeader: function () {

    if (this._bHeaderDisabled) {

        Dom.removeClass(this.header, "topscrollbar_disabled");
        this._bHeaderDisabled = false;

    }

},


/**
* @method _enableScrollFooter
* @description Enables the footer used for scrolling the body of the menu.
* @protected
*/
_enableScrollFooter: function () {

    if (this._bFooterDisabled) {

        Dom.removeClass(this.footer, "bottomscrollbar_disabled");
        this._bFooterDisabled = false;

    }

},


/**
* @method _onMouseOver
* @description "mouseover" event handler for the menu.
* @protected
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onMouseOver: function (p_sType, p_aArgs) {

    if (this._bStopMouseEventHandlers) {
    
        return false;
    
    }


    var oEvent = p_aArgs[0],
        oItem = p_aArgs[1],
        oTarget = Event.getTarget(oEvent),
        oParentMenu,
        nShowDelay,
        bShowDelay,
        oActiveItem,
        oItemCfg,
        oSubmenu;


    if (!this._bHandledMouseOverEvent && (oTarget == this.element || 
        Dom.isAncestor(this.element, oTarget))) {

        // Menu mouseover logic

        this._nCurrentMouseX = 0;

        Event.on(this.element, "mousemove", this._onMouseMove, this, true);

		this.clearActiveItem();


        if (this.parent && this._nSubmenuHideDelayId) {

            window.clearTimeout(this._nSubmenuHideDelayId);

            this.parent.cfg.setProperty("selected", true);

            oParentMenu = this.parent.parent;

            oParentMenu._bHandledMouseOutEvent = true;
            oParentMenu._bHandledMouseOverEvent = false;

        }


        this._bHandledMouseOverEvent = true;
        this._bHandledMouseOutEvent = false;
    
    }


    if (oItem && !oItem.handledMouseOverEvent && 
        !oItem.cfg.getProperty("disabled") && 
        (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {

        // Menu Item mouseover logic

        nShowDelay = this.cfg.getProperty("showdelay");
        bShowDelay = (nShowDelay > 0);


        if (bShowDelay) {
        
            this._cancelShowDelay();
        
        }


        oActiveItem = this.activeItem;
    
        if (oActiveItem) {
    
            oActiveItem.cfg.setProperty("selected", false);
    
        }


        oItemCfg = oItem.cfg;
    
        // Select and focus the current menu item
    
        oItemCfg.setProperty("selected", true);


        if (this.hasFocus()) {
        
            oItem.focus();
        
        }


        if (this.cfg.getProperty("autosubmenudisplay")) {

            // Show the submenu this menu item

            oSubmenu = oItemCfg.getProperty("submenu");
        
            if (oSubmenu) {
        
                if (bShowDelay) {

                    this._execShowDelay(oSubmenu);
        
                }
                else {

                    oSubmenu.show();

                }

            }

        }                        

        oItem.handledMouseOverEvent = true;
        oItem.handledMouseOutEvent = false;

    }

},


/**
* @method _onMouseOut
* @description "mouseout" event handler for the menu.
* @protected
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onMouseOut: function (p_sType, p_aArgs) {

    if (this._bStopMouseEventHandlers) {
    
        return false;
    
    }


    var oEvent = p_aArgs[0],
        oItem = p_aArgs[1],
        oRelatedTarget = Event.getRelatedTarget(oEvent),
        bMovingToSubmenu = false,
        oItemCfg,
        oSubmenu,
        nSubmenuHideDelay,
        nShowDelay;


    if (oItem && !oItem.cfg.getProperty("disabled")) {

        oItemCfg = oItem.cfg;
        oSubmenu = oItemCfg.getProperty("submenu");


        if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
                Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {

            bMovingToSubmenu = true;

        }


        if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&  
            !Dom.isAncestor(oItem.element, oRelatedTarget)) || 
            bMovingToSubmenu)) {

            // Menu Item mouseout logic

            if (!bMovingToSubmenu) {

                oItem.cfg.setProperty("selected", false);


                if (oSubmenu) {

                    nSubmenuHideDelay = 
                        this.cfg.getProperty("submenuhidedelay");

                    nShowDelay = this.cfg.getProperty("showdelay");

                    if (!(this instanceof YAHOO.widget.MenuBar) && 
                        nSubmenuHideDelay > 0 && 
                        nShowDelay >= nSubmenuHideDelay) {

                        this._execSubmenuHideDelay(oSubmenu, 
                                Event.getPageX(oEvent),
                                nSubmenuHideDelay);

                    }
                    else {

                        oSubmenu.hide();

                    }

                }

            }


            oItem.handledMouseOutEvent = true;
            oItem.handledMouseOverEvent = false;
    
        }

    }


    if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&  
        !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {

        // Menu mouseout logic

        Event.removeListener(this.element, "mousemove", this._onMouseMove);

        this._nCurrentMouseX = Event.getPageX(oEvent);

        this._bHandledMouseOutEvent = true;
        this._bHandledMouseOverEvent = false;

    }

},


/**
* @method _onMouseMove
* @description "click" event handler for the menu.
* @protected
* @param {Event} p_oEvent Object representing the DOM event object passed 
* back by the event utility (YAHOO.util.Event).
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
* fired the event.
*/
_onMouseMove: function (p_oEvent, p_oMenu) {

    if (this._bStopMouseEventHandlers) {
    
        return false;
    
    }

    this._nCurrentMouseX = Event.getPageX(p_oEvent);

},


/**
* @method _onClick
* @description "click" event handler for the menu.
* @protected
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onClick: function (p_sType, p_aArgs) {

	var oEvent = p_aArgs[0],
		oItem = p_aArgs[1],
		bInMenuAnchor = false,
		oSubmenu,
		oRoot,
		sId,
		sURL,
		nHashPos,
		nLen;


	if (oItem) {
	
		if (oItem.cfg.getProperty("disabled")) {
		
			Event.preventDefault(oEvent);

		}
		else {

			oSubmenu = oItem.cfg.getProperty("submenu");
	
			
			/*
				 Check if the URL of the anchor is pointing to an element that is 
				 a child of the menu.
			*/
			
			sURL = oItem.cfg.getProperty("url");

		
			if (sURL) {
	
				nHashPos = sURL.indexOf("#");
	
				nLen = sURL.length;
	
	
				if (nHashPos != -1) {
	
					sURL = sURL.substr(nHashPos, nLen);
		
					nLen = sURL.length;
	
	
					if (nLen > 1) {
	
						sId = sURL.substr(1, nLen);
	
						bInMenuAnchor = Dom.isAncestor(this.element, sId);
						
					}
					else if (nLen === 1) {
	
						bInMenuAnchor = true;
					
					}
	
				}
			
			}


	
			if (bInMenuAnchor && !oItem.cfg.getProperty("target")) {
	
				Event.preventDefault(oEvent);
				

				if (UA.webkit) {
				
					oItem.focus();
				
				}
				else {

					oItem.focusEvent.fire();
				
				}
			
			}
	
	
			if (!oSubmenu) {
	
				/*
					There is an inconsistency between Firefox 2 for Mac OS X and Firefox 2 Windows 
					regarding the triggering of the display of the browser's context menu and the 
					subsequent firing of the "click" event. In Firefox for Windows, when the user 
					triggers the display of the browser's context menu the "click" event also fires 
					for the document object, even though the "click" event did not fire for the 
					element that was the original target of the "contextmenu" event. This is unique 
					to Firefox on Windows. For all other A-Grade browsers, including Firefox 2 for 
					Mac OS X, the "click" event doesn't fire for the document object. 

					This bug in Firefox 2 for Windows affects Menu as Menu instances listen for 
					events at the document level and have an internal "click" event handler they 
					use to hide themselves when clicked. As a result, in Firefox for Windows a 
					Menu will hide when the user right clicks on a MenuItem to raise the browser's 
					default context menu, because its internal "click" event handler ends up 
					getting called.  The following line fixes this bug.
				*/

				if ((UA.gecko && this.platform == "windows") && oEvent.button > 0) {
				
					return;
				
				}

				oRoot = this.getRoot();

				if (oRoot instanceof YAHOO.widget.MenuBar || 
					oRoot.cfg.getProperty("position") == "static") {
	
					oRoot.clearActiveItem();
	
				}
				else {
	
					oRoot.hide();
				
				}
	
			}
			
		}
	
	}

},


/**
* @method _onKeyDown
* @description "keydown" event handler for the menu.
* @protected
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onKeyDown: function (p_sType, p_aArgs) {

    var oEvent = p_aArgs[0],
        oItem = p_aArgs[1],
        me = this,
        oSubmenu,
        oItemCfg,
        oParentItem,
        oRoot,
        oNextItem,
        oBody,
        nBodyScrollTop,
        nBodyOffsetHeight,
        aItems,
        nItems,
        nNextItemOffsetTop,
        nScrollTarget,
        oParentMenu;


    /*
        This function is called to prevent a bug in Firefox.  In Firefox,
        moving a DOM element into a stationary mouse pointer will cause the 
        browser to fire mouse events.  This can result in the menu mouse
        event handlers being called uncessarily, especially when menus are 
        moved into a stationary mouse pointer as a result of a 
        key event handler.
    */
    function stopMouseEventHandlers() {

        me._bStopMouseEventHandlers = true;
        
        window.setTimeout(function () {
        
            me._bStopMouseEventHandlers = false;
        
        }, 10);

    }


    if (oItem && !oItem.cfg.getProperty("disabled")) {

        oItemCfg = oItem.cfg;
        oParentItem = this.parent;

        switch(oEvent.keyCode) {
    
            case 38:    // Up arrow
            case 40:    // Down arrow
    
                oNextItem = (oEvent.keyCode == 38) ? 
                    oItem.getPreviousEnabledSibling() : 
                    oItem.getNextEnabledSibling();
        
                if (oNextItem) {

                    this.clearActiveItem();

                    oNextItem.cfg.setProperty("selected", true);
                    oNextItem.focus();


                    if (this.cfg.getProperty("maxheight") > 0) {

                        oBody = this.body;
                        nBodyScrollTop = oBody.scrollTop;
                        nBodyOffsetHeight = oBody.offsetHeight;
                        aItems = this.getItems();
                        nItems = aItems.length - 1;
                        nNextItemOffsetTop = oNextItem.element.offsetTop;


                        if (oEvent.keyCode == 40 ) {    // Down
                       
                            if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {

                                oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;

                            }
                            else if (nNextItemOffsetTop <= nBodyScrollTop) {
                            
                                oBody.scrollTop = 0;
                            
                            }


                            if (oNextItem == aItems[nItems]) {

                                oBody.scrollTop = oNextItem.element.offsetTop;

                            }

                        }
                        else {  // Up

                            if (nNextItemOffsetTop <= nBodyScrollTop) {

                                oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
                            
                            }
                            else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
                            
                                oBody.scrollTop = nNextItemOffsetTop;
                            
                            }


                            if (oNextItem == aItems[0]) {
                            
                                oBody.scrollTop = 0;
                            
                            }

                        }


                        nBodyScrollTop = oBody.scrollTop;
                        nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;

                        if (nBodyScrollTop === 0) {

                            this._disableScrollHeader();
                            this._enableScrollFooter();

                        }
                        else if (nBodyScrollTop == nScrollTarget) {

                             this._enableScrollHeader();
                             this._disableScrollFooter();

                        }
                        else {

                            this._enableScrollHeader();
                            this._enableScrollFooter();

                        }

                    }

                }

    
                Event.preventDefault(oEvent);

                stopMouseEventHandlers();
    
            break;
            
    
            case 39:    // Right arrow
    
                oSubmenu = oItemCfg.getProperty("submenu");
    
                if (oSubmenu) {
    
                    if (!oItemCfg.getProperty("selected")) {
        
                        oItemCfg.setProperty("selected", true);
        
                    }
    
                    oSubmenu.show();
                    oSubmenu.setInitialFocus();
                    oSubmenu.setInitialSelection();
    
                }
                else {
    
                    oRoot = this.getRoot();
                    
                    if (oRoot instanceof YAHOO.widget.MenuBar) {
    
                        oNextItem = oRoot.activeItem.getNextEnabledSibling();
    
                        if (oNextItem) {
                        
                            oRoot.clearActiveItem();
    
                            oNextItem.cfg.setProperty("selected", true);
    
                            oSubmenu = oNextItem.cfg.getProperty("submenu");
    
                            if (oSubmenu) {
    
                                oSubmenu.show();
                            
                            }
    
                            oNextItem.focus();
                        
                        }
                    
                    }
                
                }
    
    
                Event.preventDefault(oEvent);

                stopMouseEventHandlers();

            break;
    
    
            case 37:    // Left arrow
    
                if (oParentItem) {
    
                    oParentMenu = oParentItem.parent;
    
                    if (oParentMenu instanceof YAHOO.widget.MenuBar) {
    
                        oNextItem = 
                            oParentMenu.activeItem.getPreviousEnabledSibling();
    
                        if (oNextItem) {
                        
                            oParentMenu.clearActiveItem();
    
                            oNextItem.cfg.setProperty("selected", true);
    
                            oSubmenu = oNextItem.cfg.getProperty("submenu");
    
                            if (oSubmenu) {
                            
                                oSubmenu.show();
                            
                            }
    
                            oNextItem.focus();
                        
                        } 
                    
                    }
                    else {
    
                        this.hide();
    
                        oParentItem.focus();
                    
                    }
    
                }
    
                Event.preventDefault(oEvent);

                stopMouseEventHandlers();

            break;        
    
        }


    }


    if (oEvent.keyCode == 27) { // Esc key

        if (this.cfg.getProperty("position") == "dynamic") {
        
            this.hide();

            if (this.parent) {

                this.parent.focus();
            
            }

        }
        else if (this.activeItem) {

            oSubmenu = this.activeItem.cfg.getProperty("submenu");

            if (oSubmenu && oSubmenu.cfg.getProperty("visible")) {
            
                oSubmenu.hide();
                this.activeItem.focus();
            
            }
            else {

                this.activeItem.blur();
                this.activeItem.cfg.setProperty("selected", false);
        
            }
        
        }


        Event.preventDefault(oEvent);
    
    }
    
},


/**
* @method _onKeyPress
* @description "keypress" event handler for a Menu instance.
* @protected
* @param {String} p_sType The name of the event that was fired.
* @param {Array} p_aArgs Collection of arguments sent when the event 
* was fired.
*/
_onKeyPress: function (p_sType, p_aArgs) {
    
    var oEvent = p_aArgs[0];


    if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {

        Event.preventDefault(oEvent);

    }

},


/**
* @method _onYChange
* @description "y" event handler for a Menu instance.
* @protected
* @param {String} p_sType The name of the event that was fired.
* @param {Array} p_aArgs Collection of arguments sent when the event 
* was fired.
*/
_onYChange: function (p_sType, p_aArgs) {

    var oParent = this.parent,
        nScrollTop,
        oIFrame,
        nY;


    if (oParent) {

        nScrollTop = oParent.parent.body.scrollTop;


        if (nScrollTop > 0) {
    
            nY = (this.cfg.getProperty("y") - nScrollTop);
            
            Dom.setY(this.element, nY);

            oIFrame = this.iframe;            
    

            if (oIFrame) {
    
                Dom.setY(oIFrame, nY);
    
            }
            
            this.cfg.setProperty("y", nY, true);
        
        }
    
    }

},


/**
* @method _onScrollTargetMouseOver
* @description "mouseover" event handler for the menu's "header" and "footer" 
* elements.  Used to scroll the body of the menu up and down when the 
* menu's "maxheight" configuration property is set to a value greater than 0.
* @protected
* @param {Event} p_oEvent Object representing the DOM event object passed 
* back by the event utility (YAHOO.util.Event).
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
* fired the event.
*/
_onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {

    this._cancelHideDelay();

    var oTarget = Event.getTarget(p_oEvent),
        oBody = this.body,
        me = this,
        nScrollIncrement = this.cfg.getProperty("scrollincrement"),
        nScrollTarget,
        fnScrollFunction;


    function scrollBodyDown() {

        var nScrollTop = oBody.scrollTop;


        if (nScrollTop < nScrollTarget) {

            oBody.scrollTop = (nScrollTop + nScrollIncrement);

            me._enableScrollHeader();

        }
        else {

            oBody.scrollTop = nScrollTarget;
            
            window.clearInterval(me._nBodyScrollId);

            me._disableScrollFooter();

        }

    }


    function scrollBodyUp() {

        var nScrollTop = oBody.scrollTop;


        if (nScrollTop > 0) {

            oBody.scrollTop = (nScrollTop - nScrollIncrement);

            me._enableScrollFooter();

        }
        else {

            oBody.scrollTop = 0;
            
            window.clearInterval(me._nBodyScrollId);

            me._disableScrollHeader();

        }

    }

    
    if (Dom.hasClass(oTarget, "hd")) {

        fnScrollFunction = scrollBodyUp;
    
    }
    else {

        nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;

        fnScrollFunction = scrollBodyDown;
    
    }


    this._nBodyScrollId = window.setInterval(fnScrollFunction, 10);

},


/**
* @method _onScrollTargetMouseOut
* @description "mouseout" event handler for the menu's "header" and "footer" 
* elements.  Used to stop scrolling the body of the menu up and down when the 
* menu's "maxheight" configuration property is set to a value greater than 0.
* @protected
* @param {Event} p_oEvent Object representing the DOM event object passed 
* back by the event utility (YAHOO.util.Event).
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
* fired the event.
*/
_onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {

    window.clearInterval(this._nBodyScrollId);

    this._cancelHideDelay();

},



// Private methods


/**
* @method _onInit
* @description "init" event handler for the menu.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onInit: function (p_sType, p_aArgs) {

    this.cfg.subscribeToConfigEvent("visible", this._onVisibleChange);

    var bRootMenu = !this.parent,
        bLazyLoad = this.lazyLoad;


    /*
        Automatically initialize a menu's subtree if:

        1) This is the root menu and lazyload is off
        
        2) This is the root menu, lazyload is on, but the menu is 
           already visible

        3) This menu is a submenu and lazyload is off
    */



    if (((bRootMenu && !bLazyLoad) || 
        (bRootMenu && (this.cfg.getProperty("visible") || 
        this.cfg.getProperty("position") == "static")) || 
        (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {

        if (this.srcElement) {

            this._initSubTree();
        
        }


        if (this.itemData) {

            this.addItems(this.itemData);

        }
    
    }
    else if (bLazyLoad) {

        this.cfg.fireQueue();
    
    }

},


/**
* @method _onBeforeRender
* @description "beforerender" event handler for the menu.  Appends all of the 
* <code>&#60;ul&#62;</code>, <code>&#60;li&#62;</code> and their accompanying 
* title elements to the body element of the menu.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onBeforeRender: function (p_sType, p_aArgs) {

    var oEl = this.element,
        nListElements = this._aListElements.length,
        bFirstList = true,
        i = 0,
        oUL,
        oGroupTitle;

    if (nListElements > 0) {

        do {

            oUL = this._aListElements[i];

            if (oUL) {

                if (bFirstList) {
        
                    Dom.addClass(oUL, "first-of-type");
                    bFirstList = false;
        
                }


                if (!Dom.isAncestor(oEl, oUL)) {

                    this.appendToBody(oUL);

                }


                oGroupTitle = this._aGroupTitleElements[i];

                if (oGroupTitle) {

                    if (!Dom.isAncestor(oEl, oGroupTitle)) {

                        oUL.parentNode.insertBefore(oGroupTitle, oUL);

                    }


                    Dom.addClass(oUL, "hastitle");

                }

            }

            i++;

        }
        while(i < nListElements);

    }

},


/**
* @method _onRender
* @description "render" event handler for the menu.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onRender: function (p_sType, p_aArgs) {

    if (this.cfg.getProperty("position") == "dynamic") { 

        if (!this.cfg.getProperty("visible")) {

            this.positionOffScreen();

        }
    
    }

},





/**
* @method _onBeforeShow
* @description "beforeshow" event handler for the menu.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onBeforeShow: function (p_sType, p_aArgs) {

    var nOptions,
        n,
        nViewportHeight,
        oRegion,
        oSrcElement;


    if (this.lazyLoad && this.getItemGroups().length === 0) {

        if (this.srcElement) {
        
            this._initSubTree();

        }


        if (this.itemData) {

            if (this.parent && this.parent.parent && 
                this.parent.parent.srcElement && 
                this.parent.parent.srcElement.tagName.toUpperCase() == 
                "SELECT") {

                nOptions = this.itemData.length;
    
                for(n=0; n<nOptions; n++) {

                    if (this.itemData[n].tagName) {

                        this.addItem((new this.ITEM_TYPE(this.itemData[n])));
    
                    }
    
                }
            
            }
            else {

                this.addItems(this.itemData);
            
            }
        
        }


        oSrcElement = this.srcElement;

        if (oSrcElement) {

            if (oSrcElement.tagName.toUpperCase() == "SELECT") {

                if (Dom.inDocument(oSrcElement)) {

                    this.render(oSrcElement.parentNode);
                
                }
                else {
                
                    this.render(this.cfg.getProperty("container"));
                
                }

            }
            else {

                this.render();

            }

        }
        else {

            if (this.parent) {

                this.render(this.parent.element);            

            }
            else {

                this.render(this.cfg.getProperty("container"));

            }                

        }

    }


    var nMaxHeight = this.cfg.getProperty("maxheight"),
        nMinScrollHeight = this.cfg.getProperty("minscrollheight"),
        bDynamicPos = this.cfg.getProperty("position") == "dynamic";


    if (!this.parent && bDynamicPos) {

        this.cfg.refireEvent("xy");
   
    }


    function clearMaxHeight() {
    
        this.cfg.setProperty("maxheight", 0);
    
        this.hideEvent.unsubscribe(clearMaxHeight);
    
    }


    if (!(this instanceof YAHOO.widget.MenuBar) && bDynamicPos) {


        if (nMaxHeight === 0) {

            nViewportHeight = Dom.getViewportHeight();
    
    
            if (this.parent && 
                this.parent.parent instanceof YAHOO.widget.MenuBar) {
               
                oRegion = YAHOO.util.Region.getRegion(this.parent.element);
                
                nViewportHeight = (nViewportHeight - oRegion.bottom);
    
            }
    
    
            if (this.element.offsetHeight >= nViewportHeight) {
    
                nMaxHeight = (nViewportHeight - (Overlay.VIEWPORT_OFFSET * 2));

                if (nMaxHeight < nMinScrollHeight) {

                    nMaxHeight = nMinScrollHeight;
                
                }

                this.cfg.setProperty("maxheight", nMaxHeight);

                this.hideEvent.subscribe(clearMaxHeight);

            }
        
        }

    }

},


/**
* @method _onShow
* @description "show" event handler for the menu.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onShow: function (p_sType, p_aArgs) {

    var oParent = this.parent,
        oParentMenu,
        aParentAlignment,
        aAlignment;


    function disableAutoSubmenuDisplay(p_oEvent) {

        var oTarget;

        if (p_oEvent.type == "mousedown" || (p_oEvent.type == "keydown" && 
            p_oEvent.keyCode == 27)) {

            /*  
                Set the "autosubmenudisplay" to "false" if the user
                clicks outside the menu bar.
            */

            oTarget = Event.getTarget(p_oEvent);

            if (oTarget != oParentMenu.element || 
                !Dom.isAncestor(oParentMenu.element, oTarget)) {

                oParentMenu.cfg.setProperty("autosubmenudisplay", false);

                Event.removeListener(document, "mousedown", 
                        disableAutoSubmenuDisplay);

                Event.removeListener(document, "keydown", 
                        disableAutoSubmenuDisplay);

            }
        
        }

    }


    if (oParent) {

        oParentMenu = oParent.parent;
        aParentAlignment = oParentMenu.cfg.getProperty("submenualignment");
        aAlignment = this.cfg.getProperty("submenualignment");


        if ((aParentAlignment[0] != aAlignment[0]) &&
            (aParentAlignment[1] != aAlignment[1])) {

            this.cfg.setProperty("submenualignment", 
                [aParentAlignment[0], aParentAlignment[1]]);
        
        }


        if (!oParentMenu.cfg.getProperty("autosubmenudisplay") && 
            (oParentMenu instanceof YAHOO.widget.MenuBar || 
            oParentMenu.cfg.getProperty("position") == "static")) {

            oParentMenu.cfg.setProperty("autosubmenudisplay", true);

            Event.on(document, "mousedown", disableAutoSubmenuDisplay);                             
            Event.on(document, "keydown", disableAutoSubmenuDisplay);

        }

    }

},


/**
* @method _onBeforeHide
* @description "beforehide" event handler for the menu.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onBeforeHide: function (p_sType, p_aArgs) {

    var oActiveItem = this.activeItem,
        oConfig,
        oSubmenu;

    if (oActiveItem) {

        oConfig = oActiveItem.cfg;

        oConfig.setProperty("selected", false);

        oSubmenu = oConfig.getProperty("submenu");

        if (oSubmenu) {

            oSubmenu.hide();

        }

    }

    if (this.getRoot() == this) {

        this.blur();
    
    }

},


/**
* @method _onParentMenuConfigChange
* @description "configchange" event handler for a submenu.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that 
* subscribed to the event.
*/
_onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
    
    var sPropertyName = p_aArgs[0][0],
        oPropertyValue = p_aArgs[0][1];

    switch(sPropertyName) {

        case "iframe":
        case "constraintoviewport":
        case "hidedelay":
        case "showdelay":
        case "submenuhidedelay":
        case "clicktohide":
        case "effect":
        case "classname":
        case "scrollincrement":
        case "minscrollheight":

            p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
                
        break;        
        
    }
    
},


/**
* @method _onParentMenuRender
* @description "render" event handler for a submenu.  Renders a  
* submenu in response to the firing of its parent's "render" event.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that 
* subscribed to the event.
*/
_onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {

    var oParentCfg = p_oSubmenu.parent.parent.cfg,

        oConfig = {

            constraintoviewport: oParentCfg.getProperty("constraintoviewport"),

            xy: [0,0],

            clicktohide: oParentCfg.getProperty("clicktohide"),
                
            effect: oParentCfg.getProperty("effect"),

            showdelay: oParentCfg.getProperty("showdelay"),
            
            hidedelay: oParentCfg.getProperty("hidedelay"),

            submenuhidedelay: oParentCfg.getProperty("submenuhidedelay"),

            classname: oParentCfg.getProperty("classname"),
            
            scrollincrement: oParentCfg.getProperty("scrollincrement"),
            
            minscrollheight: oParentCfg.getProperty("minscrollheight"),
            
            iframe: oParentCfg.getProperty("iframe")

        },
        
        oLI;


    p_oSubmenu.cfg.applyConfig(oConfig);


    if (!this.lazyLoad) {

        oLI = this.parent.element;

        if (this.element.parentNode == oLI) {
    
            this.render();
    
        }
        else {

            this.render(oLI);
    
        }

    }
    
},


/**
* @method _onSubmenuBeforeShow
* @description "beforeshow" event handler for a submenu.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onSubmenuBeforeShow: function (p_sType, p_aArgs) {

    var oParent = this.parent,
        aAlignment = oParent.parent.cfg.getProperty("submenualignment");


    if (!this.cfg.getProperty("context")) {
    
        this.cfg.setProperty("context", 
            [oParent.element, aAlignment[0], aAlignment[1]]);

    }
    else {

        this.align();
    
    }

},


/**
* @method _onMenuItemFocus
* @description "focus" event handler for the menu's items.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onMenuItemFocus: function (p_sType, p_aArgs) {

    this.parent.focusEvent.fire(this);

},


/**
* @method _onMenuItemBlur
* @description "blur" event handler for the menu's items.
* @private
* @param {String} p_sType String representing the name of the event 
* that was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
_onMenuItemBlur: function (p_sType, p_aArgs) {

    this.parent.blurEvent.fire(this);

},


/**
* @method _onMenuItemDestroy
* @description "destroy" event handler for the menu's items.
* @private
* @param {String} p_sType String representing the name of the event 
* that was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item 
* that fired the event.
*/
_onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {

    this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);

},


/**
* @method _onMenuItemConfigChange
* @description "configchange" event handler for the menu's items.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item 
* that fired the event.
*/
_onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {

    var sPropertyName = p_aArgs[0][0],
        oPropertyValue = p_aArgs[0][1],
        oSubmenu;


    switch(sPropertyName) {

        case "selected":

            if (oPropertyValue === true) {

                this.activeItem = p_oItem;
            
            }

        break;

        case "submenu":

            oSubmenu = p_aArgs[0][1];

            if (oSubmenu) {

                this._configureSubmenu(p_oItem);

            }

        break;

    }

},



// Public event handlers for configuration properties


/**
* @method enforceConstraints
* @description The default event handler executed when the moveEvent is fired,  
* if the "constraintoviewport" configuration property is set to true.
* @param {String} type The name of the event that was fired.
* @param {Array} args Collection of arguments sent when the 
* event was fired.
* @param {Array} obj Array containing the current Menu instance 
* and the item that fired the event.
*/
enforceConstraints: function (type, args, obj) {

	YAHOO.widget.Menu.superclass.enforceConstraints.apply(this, arguments);
	
	var oParent = this.parent,
		oParentMenu,
		nParentMenuX,
		nNewX,
		nX;
	
	
	if (oParent) {
	
		oParentMenu = oParent.parent;

		if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
	
			nParentMenuX = oParentMenu.cfg.getProperty("x");
			nX = this.cfg.getProperty("x");
		
	
			if (nX < (nParentMenuX + oParent.element.offsetWidth)) {

				nNewX = (nParentMenuX - this.element.offsetWidth);
			
				this.cfg.setProperty("x",  nNewX, true);
				this.cfg.setProperty("xy", [nNewX, (this.cfg.getProperty("y"))], true);
			
			}
		
		}
	
	}

},


/**
* @method configVisible
* @description Event handler for when the "visible" configuration property 
* the menu changes.
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
* fired the event.
*/
configVisible: function (p_sType, p_aArgs, p_oMenu) {

    var bVisible,
        sDisplay;

    if (this.cfg.getProperty("position") == "dynamic") {

        Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);

    }
    else {

        bVisible = p_aArgs[0];
        sDisplay = Dom.getStyle(this.element, "display");

        Dom.setStyle(this.element, "visibility", "visible");

        if (bVisible) {

            if (sDisplay != "block") {
                this.beforeShowEvent.fire();
                Dom.setStyle(this.element, "display", "block");
                this.showEvent.fire();
            }
        
        }
        else {

			if (sDisplay == "block") {
				this.beforeHideEvent.fire();
				Dom.setStyle(this.element, "display", "none");
				this.hideEvent.fire();
			}
        
        }

    }

},


/**
* @method configPosition
* @description Event handler for when the "position" configuration property 
* of the menu changes.
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
* fired the event.
*/
configPosition: function (p_sType, p_aArgs, p_oMenu) {

    var oElement = this.element,
        sCSSPosition = p_aArgs[0] == "static" ? "static" : "absolute",
        oCfg = this.cfg,
        nZIndex;


    Dom.setStyle(oElement, "position", sCSSPosition);


    if (sCSSPosition == "static") {

        // Statically positioned menus are visible by default
        
        Dom.setStyle(oElement, "display", "block");

        oCfg.setProperty("visible", true);

    }
    else {

        /*
            Even though the "visible" property is queued to 
            "false" by default, we need to set the "visibility" property to 
            "hidden" since Overlay's "configVisible" implementation checks the 
            element's "visibility" style property before deciding whether 
            or not to show an Overlay instance.
        */

        Dom.setStyle(oElement, "visibility", "hidden");
    
    }


    if (sCSSPosition == "absolute") {

        nZIndex = oCfg.getProperty("zindex");

        if (!nZIndex || nZIndex === 0) {

            nZIndex = this.parent ? 
                (this.parent.parent.cfg.getProperty("zindex") + 1) : 1;

            oCfg.setProperty("zindex", nZIndex);

        }

    }

},


/**
* @method configIframe
* @description Event handler for when the "iframe" configuration property of 
* the menu changes.
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
* fired the event.
*/
configIframe: function (p_sType, p_aArgs, p_oMenu) {    

    if (this.cfg.getProperty("position") == "dynamic") {

        Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);

    }

},


/**
* @method configHideDelay
* @description Event handler for when the "hidedelay" configuration property 
* of the menu changes.
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
* fired the event.
*/
configHideDelay: function (p_sType, p_aArgs, p_oMenu) {

    var nHideDelay = p_aArgs[0],
        oMouseOutEvent = this.mouseOutEvent,
        oMouseOverEvent = this.mouseOverEvent,
        oKeyDownEvent = this.keyDownEvent;

    if (nHideDelay > 0) {

        /*
            Only assign event handlers once. This way the user change 
            the value for the hidedelay as many times as they want.
        */

        if (!this._bHideDelayEventHandlersAssigned) {

            oMouseOutEvent.subscribe(this._execHideDelay);
            oMouseOverEvent.subscribe(this._cancelHideDelay);
            oKeyDownEvent.subscribe(this._cancelHideDelay);

            this._bHideDelayEventHandlersAssigned = true;
        
        }

    }
    else {

        oMouseOutEvent.unsubscribe(this._execHideDelay);
        oMouseOverEvent.unsubscribe(this._cancelHideDelay);
        oKeyDownEvent.unsubscribe(this._cancelHideDelay);

        this._bHideDelayEventHandlersAssigned = false;

    }

},


/**
* @method configContainer
* @description Event handler for when the "container" configuration property 
* of the menu changes.
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that 
* fired the event.
*/
configContainer: function (p_sType, p_aArgs, p_oMenu) {

	var oElement = p_aArgs[0];

	if (typeof oElement == 'string') {

        this.cfg.setProperty("container", document.getElementById(oElement), 
                true);

	}

},


/**
* @method _setMaxHeight
* @description "renderEvent" handler used to defer the setting of the 
* "maxheight" configuration property until the menu is rendered in lazy 
* load scenarios.
* @param {String} p_sType The name of the event that was fired.
* @param {Array} p_aArgs Collection of arguments sent when the event 
* was fired.
* @param {Number} p_nMaxHeight Number representing the value to set for the 
* "maxheight" configuration property.
* @private
*/
_setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {

    this.cfg.setProperty("maxheight", p_nMaxHeight);
    this.renderEvent.unsubscribe(this._setMaxHeight);

},


/**
* @method configMaxHeight
* @description Event handler for when the "maxheight" configuration property of 
* a Menu changes.
* @param {String} p_sType The name of the event that was fired.
* @param {Array} p_aArgs Collection of arguments sent when the event 
* was fired.
* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
* the event.
*/
configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {

    var nMaxHeight = p_aArgs[0],
        oElement = this.element,
        oBody = this.body,
        oHeader = this.header,
        oFooter = this.footer,
        fnMouseOver = this._onScrollTargetMouseOver,
        fnMouseOut = this._onScrollTargetMouseOut,
        nMinScrollHeight = this.cfg.getProperty("minscrollheight"),
        nHeight,
        nOffsetWidth,
        sWidth;


    if (nMaxHeight !== 0 && nMaxHeight < nMinScrollHeight) {
    
        nMaxHeight = nMinScrollHeight;
    
    }


    if (this.lazyLoad && !oBody) {

        this.renderEvent.unsubscribe(this._setMaxHeight);
    
        if (nMaxHeight > 0) {

            this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);

        }

        return;
    
    }


    Dom.setStyle(oBody, "height", "");
    Dom.removeClass(oBody, "yui-menu-body-scrolled");


    /*
        There is a bug in gecko-based browsers where an element whose 
        "position" property is set to "absolute" and "overflow" property is set 
        to "hidden" will not render at the correct width when its 
        offsetParent's "position" property is also set to "absolute."  It is 
        possible to work around this bug by specifying a value for the width 
        property in addition to overflow.

		In IE it is also necessary to give the Menu a width when the scrollbars are 
		rendered to prevent the Menu from rendering with a width that is 100% of
		the browser viewport.
    */

	var bSetWidth = ((UA.gecko && this.parent && this.parent.parent && 
        this.parent.parent.cfg.getProperty("position") == "dynamic") || UA.ie);


    if (bSetWidth) {

		if (!this.cfg.getProperty("width")) {

			nOffsetWidth = oElement.offsetWidth;
	
			/*
				Measuring the difference of the offsetWidth before and after
				setting the "width" style attribute allows us to compute the 
				about of padding and borders applied to the element, which in 
				turn allows us to set the "width" property correctly.
			*/
			
			oElement.style.width = nOffsetWidth + "px";
	
			sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + "px";
	
			this.cfg.setProperty("width", sWidth);
		
		}

    }


    if (!oHeader && !oFooter) {

        this.setHeader("&#32;");
        this.setFooter("&#32;");

        oHeader = this.header;
        oFooter = this.footer;

        Dom.addClass(oHeader, "topscrollbar");
        Dom.addClass(oFooter, "bottomscrollbar");
        
        oElement.insertBefore(oHeader, oBody);
        oElement.appendChild(oFooter);
    
    }


    nHeight = (nMaxHeight - (oHeader.offsetHeight + oHeader.offsetHeight));


    if (nHeight > 0 && (oBody.offsetHeight > nMaxHeight)) {

        Dom.addClass(oBody, "yui-menu-body-scrolled");
        Dom.setStyle(oBody, "height", (nHeight + "px"));

        Event.on(oHeader, "mouseover", fnMouseOver, this, true);
        Event.on(oHeader, "mouseout", fnMouseOut, this, true);
        Event.on(oFooter, "mouseover", fnMouseOver, this, true);
        Event.on(oFooter, "mouseout", fnMouseOut, this, true);

        this._disableScrollHeader();
        this._enableScrollFooter();

    }
    else if (oHeader && oFooter) {

		if (bSetWidth) {

			this.cfg.setProperty("width", "");
		
		}


        this._enableScrollHeader();
        this._enableScrollFooter();

        Event.removeListener(oHeader, "mouseover", fnMouseOver);
        Event.removeListener(oHeader, "mouseout", fnMouseOut);
        Event.removeListener(oFooter, "mouseover", fnMouseOver);
        Event.removeListener(oFooter, "mouseout", fnMouseOut);

        oElement.removeChild(oHeader);
        oElement.removeChild(oFooter);

        this.header = null;
        this.footer = null;
    
    }

    this.cfg.refireEvent("iframe");

},


/**
* @method configClassName
* @description Event handler for when the "classname" configuration property of 
* a menu changes.
* @param {String} p_sType The name of the event that was fired.
* @param {Array} p_aArgs Collection of arguments sent when the event was fired.
* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
*/
configClassName: function (p_sType, p_aArgs, p_oMenu) {

    var sClassName = p_aArgs[0];

    if (this._sClassName) {

        Dom.removeClass(this.element, this._sClassName);

    }

    Dom.addClass(this.element, sClassName);
    this._sClassName = sClassName;

},


/**
* @method _onItemAdded
* @description "itemadded" event handler for a Menu instance.
* @private
* @param {String} p_sType The name of the event that was fired.
* @param {Array} p_aArgs Collection of arguments sent when the event 
* was fired.
*/
_onItemAdded: function (p_sType, p_aArgs) {

    var oItem = p_aArgs[0];
    
    if (oItem) {

        oItem.cfg.setProperty("disabled", true);
    
    }

},


/**
* @method configDisabled
* @description Event handler for when the "disabled" configuration property of 
* a menu changes.
* @param {String} p_sType The name of the event that was fired.
* @param {Array} p_aArgs Collection of arguments sent when the event was fired.
* @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
*/
configDisabled: function (p_sType, p_aArgs, p_oMenu) {

    var bDisabled = p_aArgs[0],
        aItems = this.getItems(),
        nItems,
        i;

    if (Lang.isArray(aItems)) {

        nItems = aItems.length;
    
        if (nItems > 0) {
        
            i = nItems - 1;
    
            do {
    
                aItems[i].cfg.setProperty("disabled", bDisabled);
            
            }
            while (i--);
        
        }


        if (bDisabled) {

            this.clearActiveItem(true);

            Dom.addClass(this.element, "disabled");

            this.itemAddedEvent.subscribe(this._onItemAdded);

        }
        else {

            Dom.removeClass(this.element, "disabled");

            this.itemAddedEvent.unsubscribe(this._onItemAdded);

        }
        
    }

},


/**
* @method onRender
* @description "render" event handler for the menu.
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
*/
onRender: function (p_sType, p_aArgs) {

    function sizeShadow() {

        var oElement = this.element,
            oShadow = this._shadow;
    
        if (oShadow && oElement) {

			// Clear the previous width

			if (oShadow.style.width && oShadow.style.height) {
			
				oShadow.style.width = "";
				oShadow.style.height = "";
			
			}

            oShadow.style.width = (oElement.offsetWidth + 6) + "px";
            oShadow.style.height = (oElement.offsetHeight + 1) + "px";
            
        }
    
    }


    function replaceShadow() {

        this.element.appendChild(this._shadow);

    }


    function addShadowVisibleClass() {
    
        Dom.addClass(this._shadow, "yui-menu-shadow-visible");
    
    }
    

    function removeShadowVisibleClass() {

        Dom.removeClass(this._shadow, "yui-menu-shadow-visible");
    
    }


    function createShadow() {

        var oShadow = this._shadow,
            oElement,
            me;

        if (!oShadow) {

            oElement = this.element;
            me = this;

            if (!m_oShadowTemplate) {

                m_oShadowTemplate = document.createElement("div");
                m_oShadowTemplate.className = 
                    "yui-menu-shadow yui-menu-shadow-visible";
            
            }

            oShadow = m_oShadowTemplate.cloneNode(false);

            oElement.appendChild(oShadow);
            
            this._shadow = oShadow;

            this.beforeShowEvent.subscribe(addShadowVisibleClass);
            this.beforeHideEvent.subscribe(removeShadowVisibleClass);

            if (UA.ie) {
        
                /*
                     Need to call sizeShadow & syncIframe via setTimeout for 
                     IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode 
                     or the shadow and iframe shim will not be sized and 
                     positioned properly.
                */
        
                window.setTimeout(function () { 
        
                    sizeShadow.call(me); 
                    me.syncIframe();
        
                }, 0);

                this.cfg.subscribeToConfigEvent("width", sizeShadow);
                this.cfg.subscribeToConfigEvent("height", sizeShadow);
                this.cfg.subscribeToConfigEvent("maxheight", sizeShadow);
                this.changeContentEvent.subscribe(sizeShadow);

                Module.textResizeEvent.subscribe(sizeShadow, me, true);
                
                this.destroyEvent.subscribe(function () {
                
                    Module.textResizeEvent.unsubscribe(sizeShadow, me);
                
                });
        
            }

            this.cfg.subscribeToConfigEvent("maxheight", replaceShadow);

        }

    }


    function onBeforeShow() {
    
        createShadow.call(this);

        this.beforeShowEvent.unsubscribe(onBeforeShow);
    
    }


    if (this.cfg.getProperty("position") == "dynamic") {

        if (this.cfg.getProperty("visible")) {

            createShadow.call(this);
        
        }
        else {

            this.beforeShowEvent.subscribe(onBeforeShow);
        
        }
    
    }

},


// Public methods


/**
* @method initEvents
* @description Initializes the custom events for the menu.
*/
initEvents: function () {

	Menu.superclass.initEvents.call(this);

    // Create custom events

    var SIGNATURE = CustomEvent.LIST;

    this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER);
    this.mouseOverEvent.signature = SIGNATURE;

    this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT);
    this.mouseOutEvent.signature = SIGNATURE;
    
    this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN);
    this.mouseDownEvent.signature = SIGNATURE;

    this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP);
    this.mouseUpEvent.signature = SIGNATURE;
    
    this.clickEvent = this.createEvent(EVENT_TYPES.CLICK);
    this.clickEvent.signature = SIGNATURE;
    
    this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS);
    this.keyPressEvent.signature = SIGNATURE;
    
    this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN);
    this.keyDownEvent.signature = SIGNATURE;
    
    this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP);
    this.keyUpEvent.signature = SIGNATURE;
    
    this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS);
    this.focusEvent.signature = SIGNATURE;
    
    this.blurEvent = this.createEvent(EVENT_TYPES.BLUR);
    this.blurEvent.signature = SIGNATURE;
    
    this.itemAddedEvent = this.createEvent(EVENT_TYPES.ITEM_ADDED);
    this.itemAddedEvent.signature = SIGNATURE;
    
    this.itemRemovedEvent = this.createEvent(EVENT_TYPES.ITEM_REMOVED);
    this.itemRemovedEvent.signature = SIGNATURE;

},


/**
* @method positionOffScreen
* @description Positions the menu outside of the boundaries of the browser's 
* viewport.  Called automatically when a menu is hidden to ensure that 
* it doesn't force the browser to render uncessary scrollbars.
*/
positionOffScreen: function () {

    var oIFrame = this.iframe,
        aPos = this.OFF_SCREEN_POSITION;

    Dom.setXY(this.element, aPos);
    
    if (oIFrame) {

        Dom.setXY(oIFrame, aPos);
    
    }

},


/**
* @method getRoot
* @description Finds the menu's root menu.
*/
getRoot: function () {

    var oItem = this.parent,
        oParentMenu;

    if (oItem) {

        oParentMenu = oItem.parent;

        return oParentMenu ? oParentMenu.getRoot() : this;

    }
    else {
    
        return this;
    
    }

},


/**
* @method toString
* @description Returns a string representing the menu.
* @return {String}
*/
toString: function () {

    var sReturnVal = "Menu",
        sId = this.id;

    if (sId) {

        sReturnVal += (" " + sId);
    
    }

    return sReturnVal;

},


/**
* @method setItemGroupTitle
* @description Sets the title of a group of menu items.
* @param {String} p_sGroupTitle String specifying the title of the group.
* @param {Number} p_nGroupIndex Optional. Number specifying the group to which
* the title belongs.
*/
setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {

    var nGroupIndex,
        oTitle,
        i,
        nFirstIndex;
        
    if (typeof p_sGroupTitle == "string" && p_sGroupTitle.length > 0) {

        nGroupIndex = typeof p_nGroupIndex == "number" ? p_nGroupIndex : 0;
        oTitle = this._aGroupTitleElements[nGroupIndex];


        if (oTitle) {

            oTitle.innerHTML = p_sGroupTitle;
            
        }
        else {

            oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
                    
            oTitle.innerHTML = p_sGroupTitle;

            this._aGroupTitleElements[nGroupIndex] = oTitle;

        }


        i = this._aGroupTitleElements.length - 1;

        do {

            if (this._aGroupTitleElements[i]) {

                Dom.removeClass(this._aGroupTitleElements[i], "first-of-type");

                nFirstIndex = i;

            }

        }
        while(i--);


        if (nFirstIndex !== null) {

            Dom.addClass(this._aGroupTitleElements[nFirstIndex], 
                "first-of-type");

        }

        this.changeContentEvent.fire();

    }

},



/**
* @method addItem
* @description Appends an item to the menu.
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
* instance to be added to the menu.
* @param {String} p_oItem String specifying the text of the item to be added 
* to the menu.
* @param {Object} p_oItem Object literal containing a set of menu item 
* configuration properties.
* @param {Number} p_nGroupIndex Optional. Number indicating the group to
* which the item belongs.
* @return {YAHOO.widget.MenuItem}
*/
addItem: function (p_oItem, p_nGroupIndex) {

    if (p_oItem) {

        return this._addItemToGroup(p_nGroupIndex, p_oItem);
        
    }

},


/**
* @method addItems
* @description Adds an array of items to the menu.
* @param {Array} p_aItems Array of items to be added to the menu.  The array 
* can contain strings specifying the text for each item to be created, object
* literals specifying each of the menu item configuration properties, 
* or MenuItem instances.
* @param {Number} p_nGroupIndex Optional. Number specifying the group to 
* which the items belongs.
* @return {Array}
*/
addItems: function (p_aItems, p_nGroupIndex) {

    var nItems,
        aItems,
        oItem,
        i;

    if (Lang.isArray(p_aItems)) {

        nItems = p_aItems.length;
        aItems = [];

        for(i=0; i<nItems; i++) {

            oItem = p_aItems[i];

            if (oItem) {

                if (Lang.isArray(oItem)) {
    
                    aItems[aItems.length] = this.addItems(oItem, i);
    
                }
                else {
    
                    aItems[aItems.length] = 
                        this._addItemToGroup(p_nGroupIndex, oItem);
                
                }

            }
    
        }


        if (aItems.length) {
        
            return aItems;
        
        }

    }

},


/**
* @method insertItem
* @description Inserts an item into the menu at the specified index.
* @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem 
* instance to be added to the menu.
* @param {String} p_oItem String specifying the text of the item to be added 
* to the menu.
* @param {Object} p_oItem Object literal containing a set of menu item 
* configuration properties.
* @param {Number} p_nItemIndex Number indicating the ordinal position at which
* the item should be added.
* @param {Number} p_nGroupIndex Optional. Number indicating the group to which 
* the item belongs.
* @return {YAHOO.widget.MenuItem}
*/
insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
    
    if (p_oItem) {

        return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);

    }

},


/**
* @method removeItem
* @description Removes the specified item from the menu.
* @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem 
* instance to be removed from the menu.
* @param {Number} p_oObject Number specifying the index of the item 
* to be removed.
* @param {Number} p_nGroupIndex Optional. Number specifying the group to 
* which the item belongs.
* @return {YAHOO.widget.MenuItem}
*/
removeItem: function (p_oObject, p_nGroupIndex) {

    var oItem;
    
    if (typeof p_oObject != "undefined") {

        if (p_oObject instanceof YAHOO.widget.MenuItem) {

            oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);           

        }
        else if (typeof p_oObject == "number") {

            oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);

        }

        if (oItem) {

            oItem.destroy();


            return oItem;

        }

    }

},


/**
* @method getItems
* @description Returns an array of all of the items in the menu.
* @return {Array}
*/
getItems: function () {

    var aGroups = this._aItemGroups,
        nGroups,
        aItems = [];

    if (Lang.isArray(aGroups)) {

        nGroups = aGroups.length;

        return ((nGroups == 1) ? aGroups[0] : 
                    (Array.prototype.concat.apply(aItems, aGroups)));

    }

},


/**
* @method getItemGroups
* @description Multi-dimensional Array representing the menu items as they 
* are grouped in the menu.
* @return {Array}
*/        
getItemGroups: function () {

    return this._aItemGroups;

},


/**
* @method getItem
* @description Returns the item at the specified index.
* @param {Number} p_nItemIndex Number indicating the ordinal position of the 
* item to be retrieved.
* @param {Number} p_nGroupIndex Optional. Number indicating the group to which 
* the item belongs.
* @return {YAHOO.widget.MenuItem}
*/
getItem: function (p_nItemIndex, p_nGroupIndex) {
    
    var aGroup;
    
    if (typeof p_nItemIndex == "number") {

        aGroup = this._getItemGroup(p_nGroupIndex);

        if (aGroup) {

            return aGroup[p_nItemIndex];
        
        }

    }
    
},


/**
* @method getSubmenus
* @description Returns an array of all of the submenus that are immediate 
* children of the menu.
* @return {Array}
*/
getSubmenus: function () {

    var aItems = this.getItems(),
        nItems = aItems.length,
        aSubmenus,
        oSubmenu,
        oItem,
        i;


    if (nItems > 0) {
        
        aSubmenus = [];

        for(i=0; i<nItems; i++) {

            oItem = aItems[i];
            
            if (oItem) {

                oSubmenu = oItem.cfg.getProperty("submenu");
                
                if (oSubmenu) {

                    aSubmenus[aSubmenus.length] = oSubmenu;

                }
            
            }
        
        }
    
    }

    return aSubmenus;

},


/**
* @method clearContent
* @description Removes all of the content from the menu, including the menu 
* items, group titles, header and footer.
*/
clearContent: function () {

    var aItems = this.getItems(),
        nItems = aItems.length,
        oElement = this.element,
        oBody = this.body,
        oHeader = this.header,
        oFooter = this.footer,
        oItem,
        oSubmenu,
        i;


    if (nItems > 0) {

        i = nItems - 1;

        do {

            oItem = aItems[i];

            if (oItem) {

                oSubmenu = oItem.cfg.getProperty("submenu");

                if (oSubmenu) {

                    this.cfg.configChangedEvent.unsubscribe(
                        this._onParentMenuConfigChange, oSubmenu);

                    this.renderEvent.unsubscribe(this._onParentMenuRender, 
                        oSubmenu);

                }
                
                this.removeItem(oItem);

            }
        
        }
        while(i--);

    }


    if (oHeader) {

        Event.purgeElement(oHeader);
        oElement.removeChild(oHeader);

    }
    

    if (oFooter) {

        Event.purgeElement(oFooter);
        oElement.removeChild(oFooter);
    }


    if (oBody) {

        Event.purgeElement(oBody);

        oBody.innerHTML = "";

    }

    this.activeItem = null;

    this._aItemGroups = [];
    this._aListElements = [];
    this._aGroupTitleElements = [];

    this.cfg.setProperty("width", null);

},


/**
* @method destroy
* @description Removes the menu's <code>&#60;div&#62;</code> element 
* (and accompanying child nodes) from the document.
*/
destroy: function () {

    // Remove all items

    this.clearContent();

    this._aItemGroups = null;
    this._aListElements = null;
    this._aGroupTitleElements = null;


    // Continue with the superclass implementation of this method

    Menu.superclass.destroy.call(this);
    

},


/**
* @method setInitialFocus
* @description Sets focus to the menu's first enabled item.
*/
setInitialFocus: function () {

    var oItem = this._getFirstEnabledItem();
    
    if (oItem) {

        oItem.focus();

    }
    
},


/**
* @method setInitialSelection
* @description Sets the "selected" configuration property of the menu's first 
* enabled item to "true."
*/
setInitialSelection: function () {

    var oItem = this._getFirstEnabledItem();
    
    if (oItem) {
    
        oItem.cfg.setProperty("selected", true);
    }        

},


/**
* @method clearActiveItem
* @description Sets the "selected" configuration property of the menu's active
* item to "false" and hides the item's submenu.
* @param {Boolean} p_bBlur Boolean indicating if the menu's active item 
* should be blurred.  
*/
clearActiveItem: function (p_bBlur) {

    if (this.cfg.getProperty("showdelay") > 0) {
    
        this._cancelShowDelay();
    
    }


    var oActiveItem = this.activeItem,
        oConfig,
        oSubmenu;

    if (oActiveItem) {

        oConfig = oActiveItem.cfg;

        if (p_bBlur) {

            oActiveItem.blur();
        
        }

        oConfig.setProperty("selected", false);

        oSubmenu = oConfig.getProperty("submenu");

        if (oSubmenu) {

            oSubmenu.hide();

        }

        this.activeItem = null;            

    }

},


/**
* @method focus
* @description Causes the menu to receive focus and fires the "focus" event.
*/
focus: function () {

    if (!this.hasFocus()) {

        this.setInitialFocus();
    
    }

},


/**
* @method blur
* @description Causes the menu to lose focus and fires the "blur" event.
*/    
blur: function () {

    var oItem;

    if (this.hasFocus()) {
    
        oItem = MenuManager.getFocusedMenuItem();
        
        if (oItem) {

            oItem.blur();

        }

    }

},


/**
* @method hasFocus
* @description Returns a boolean indicating whether or not the menu has focus.
* @return {Boolean}
*/
hasFocus: function () {

    return (MenuManager.getFocusedMenu() == this.getRoot());

},


/**
* Adds the specified CustomEvent subscriber to the menu and each of 
* its submenus.
* @method subscribe
* @param p_type     {string}   the type, or name of the event
* @param p_fn       {function} the function to exectute when the event fires
* @param p_obj      {Object}   An object to be passed along when the event 
*                              fires
* @param p_override {boolean}  If true, the obj passed in becomes the 
*                              execution scope of the listener
*/
subscribe: function () {

    function onItemAdded(p_sType, p_aArgs, p_oObject) {

        var oItem = p_aArgs[0],
            oSubmenu = oItem.cfg.getProperty("submenu");

        if (oSubmenu) {

            oSubmenu.subscribe.apply(oSubmenu, p_oObject);

        }
    
    }


    function onSubmenuAdded(p_sType, p_aArgs, p_oObject) { 
    
        var oSubmenu = this.cfg.getProperty("submenu");
        
        if (oSubmenu) {

            oSubmenu.subscribe.apply(oSubmenu, p_oObject);
        
        }
    
    }


    Menu.superclass.subscribe.apply(this, arguments);
    Menu.superclass.subscribe.call(this, "itemAdded", onItemAdded, arguments);


    var aItems = this.getItems(),
        nItems,
        oItem,
        oSubmenu,
        i;
        

    if (aItems) {

        nItems = aItems.length;
        
        if (nItems > 0) {
        
            i = nItems - 1;
            
            do {

                oItem = aItems[i];
                
                oSubmenu = oItem.cfg.getProperty("submenu");
                
                if (oSubmenu) {
                
                    oSubmenu.subscribe.apply(oSubmenu, arguments);
                
                }
                else {
                
                    oItem.cfg.subscribeToConfigEvent("submenu", onSubmenuAdded, arguments);
                
                }

            }
            while (i--);
        
        }

    }

},


/**
* @description Initializes the class's configurable properties which can be
* changed using the menu's Config object ("cfg").
* @method initDefaultConfig
*/
initDefaultConfig: function () {

    Menu.superclass.initDefaultConfig.call(this);

    var oConfig = this.cfg;


    // Module documentation overrides

    /**
    * @config effect
    * @description Object or array of objects representing the ContainerEffect 
    * classes that are active for animating the container.  When set this 
    * property is automatically applied to all submenus.
    * @type Object
    * @default null
    */

    // Overlay documentation overrides


    /**
    * @config x
    * @description Number representing the absolute x-coordinate position of 
    * the Menu.  This property is only applied when the "position" 
    * configuration property is set to dynamic.
    * @type Number
    * @default null
    */
    

    /**
    * @config y
    * @description Number representing the absolute y-coordinate position of 
    * the Menu.  This property is only applied when the "position" 
    * configuration property is set to dynamic.
    * @type Number
    * @default null
    */


    /**
    * @description Array of the absolute x and y positions of the Menu.  This 
    * property is only applied when the "position" configuration property is 
    * set to dynamic.
    * @config xy
    * @type Number[]
    * @default null
    */
    

    /**
    * @config context
    * @description Array of context arguments for context-sensitive positioning.  
    * The format is: [id or element, element corner, context corner]. 
    * For example, setting this property to ["img1", "tl", "bl"] would 
    * align the Mnu's top left corner to the context element's 
    * bottom left corner.  This property is only applied when the "position" 
    * configuration property is set to dynamic.
    * @type Array
    * @default null
    */
    
    
    /**
    * @config fixedcenter
    * @description Boolean indicating if the Menu should be anchored to the 
    * center of the viewport.  This property is only applied when the 
    * "position" configuration property is set to dynamic.
    * @type Boolean
    * @default false
    */

    
    /**
    * @config zindex
    * @description Number representing the CSS z-index of the Menu.  This 
    * property is only applied when the "position" configuration property is 
    * set to dynamic.
    * @type Number
    * @default null
    */
    
    
    /**
    * @config iframe
    * @description Boolean indicating whether or not the Menu should 
    * have an IFRAME shim; used to prevent SELECT elements from 
    * poking through an Overlay instance in IE6.  When set to "true", 
    * the iframe shim is created when the Menu instance is intially
    * made visible.  This property is only applied when the "position" 
    * configuration property is set to dynamic and is automatically applied 
    * to all submenus.
    * @type Boolean
    * @default true for IE6 and below, false for all other browsers.
    */


	// Add configuration attributes

    /*
        Change the default value for the "visible" configuration 
        property to "false" by re-adding the property.
    */

    /**
    * @config visible
    * @description Boolean indicating whether or not the menu is visible.  If 
    * the menu's "position" configuration property is set to "dynamic" (the 
    * default), this property toggles the menu's <code>&#60;div&#62;</code> 
    * element's "visibility" style property between "visible" (true) or 
    * "hidden" (false).  If the menu's "position" configuration property is 
    * set to "static" this property toggles the menu's 
    * <code>&#60;div&#62;</code> element's "display" style property 
    * between "block" (true) or "none" (false).
    * @default false
    * @type Boolean
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.VISIBLE.key, 
        {
            handler: this.configVisible, 
            value: DEFAULT_CONFIG.VISIBLE.value, 
            validator: DEFAULT_CONFIG.VISIBLE.validator
         }
     );


    /*
        Change the default value for the "constraintoviewport" configuration 
        property to "true" by re-adding the property.
    */

    /**
    * @config constraintoviewport
    * @description Boolean indicating if the menu will try to remain inside 
    * the boundaries of the size of viewport.  This property is only applied 
    * when the "position" configuration property is set to dynamic and is 
    * automatically applied to all submenus.
    * @default true
    * @type Boolean
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, 
        {
            handler: this.configConstrainToViewport, 
            value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value, 
            validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator, 
            supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes 
        } 
    );


    /**
    * @config position
    * @description String indicating how a menu should be positioned on the 
    * screen.  Possible values are "static" and "dynamic."  Static menus are 
    * visible by default and reside in the normal flow of the document 
    * (CSS position: static).  Dynamic menus are hidden by default, reside 
    * out of the normal flow of the document (CSS position: absolute), and 
    * can overlay other elements on the screen.
    * @default dynamic
    * @type String
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.POSITION.key, 
        {
            handler: this.configPosition,
            value: DEFAULT_CONFIG.POSITION.value, 
            validator: DEFAULT_CONFIG.POSITION.validator,
            supercedes: DEFAULT_CONFIG.POSITION.supercedes
        }
    );


    /**
    * @config submenualignment
    * @description Array defining how submenus should be aligned to their 
    * parent menu item. The format is: [itemCorner, submenuCorner]. By default
    * a submenu's top left corner is aligned to its parent menu item's top 
    * right corner.
    * @default ["tl","tr"]
    * @type Array
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key, 
        { 
            value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value,
            suppressEvent: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.suppressEvent
        }
    );


    /**
    * @config autosubmenudisplay
    * @description Boolean indicating if submenus are automatically made 
    * visible when the user mouses over the menu's items.
    * @default true
    * @type Boolean
    */
	oConfig.addProperty(
	   DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key, 
	   { 
	       value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value, 
	       validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator,
	       suppressEvent: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.suppressEvent
       } 
    );


    /**
    * @config showdelay
    * @description Number indicating the time (in milliseconds) that should 
    * expire before a submenu is made visible when the user mouses over 
    * the menu's items.  This property is only applied when the "position" 
    * configuration property is set to dynamic and is automatically applied 
    * to all submenus.
    * @default 250
    * @type Number
    */
	oConfig.addProperty(
	   DEFAULT_CONFIG.SHOW_DELAY.key, 
	   { 
	       value: DEFAULT_CONFIG.SHOW_DELAY.value, 
	       validator: DEFAULT_CONFIG.SHOW_DELAY.validator,
	       suppressEvent: DEFAULT_CONFIG.SHOW_DELAY.suppressEvent
       } 
    );


    /**
    * @config hidedelay
    * @description Number indicating the time (in milliseconds) that should 
    * expire before the menu is hidden.  This property is only applied when 
    * the "position" configuration property is set to dynamic and is 
    * automatically applied to all submenus.
    * @default 0
    * @type Number
    */
	oConfig.addProperty(
	   DEFAULT_CONFIG.HIDE_DELAY.key, 
	   { 
	       handler: this.configHideDelay,
	       value: DEFAULT_CONFIG.HIDE_DELAY.value, 
	       validator: DEFAULT_CONFIG.HIDE_DELAY.validator, 
	       suppressEvent: DEFAULT_CONFIG.HIDE_DELAY.suppressEvent
       } 
    );


    /**
    * @config submenuhidedelay
    * @description Number indicating the time (in milliseconds) that should 
    * expire before a submenu is hidden when the user mouses out of a menu item 
    * heading in the direction of a submenu.  The value must be greater than or 
    * equal to the value specified for the "showdelay" configuration property.
    * This property is only applied when the "position" configuration property 
    * is set to dynamic and is automatically applied to all submenus.
    * @default 250
    * @type Number
    */
	oConfig.addProperty(
	   DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.key, 
	   { 
	       value: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.value, 
	       validator: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.validator,
	       suppressEvent: DEFAULT_CONFIG.SUBMENU_HIDE_DELAY.suppressEvent
       } 
    );


    /**
    * @config clicktohide
    * @description Boolean indicating if the menu will automatically be 
    * hidden if the user clicks outside of it.  This property is only 
    * applied when the "position" configuration property is set to dynamic 
    * and is automatically applied to all submenus.
    * @default true
    * @type Boolean
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.CLICK_TO_HIDE.key,
        {
            value: DEFAULT_CONFIG.CLICK_TO_HIDE.value,
            validator: DEFAULT_CONFIG.CLICK_TO_HIDE.validator,
            suppressEvent: DEFAULT_CONFIG.CLICK_TO_HIDE.suppressEvent
        }
    );


	/**
	* @config container
	* @description HTML element reference or string specifying the id 
	* attribute of the HTML element that the menu's markup should be 
	* rendered into.
	* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
	* level-one-html.html#ID-58190037">HTMLElement</a>|String
	* @default document.body
	*/
	oConfig.addProperty(
	   DEFAULT_CONFIG.CONTAINER.key, 
	   { 
	       handler: this.configContainer,
	       value: document.body,
           suppressEvent: DEFAULT_CONFIG.CONTAINER.suppressEvent
       } 
   );


    /**
    * @config scrollincrement
    * @description Number used to control the scroll speed of a menu.  Used to 
    * increment the "scrollTop" property of the menu's body by when a menu's 
    * content is scrolling.  When set this property is automatically applied 
    * to all submenus.
    * @default 1
    * @type Number
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.SCROLL_INCREMENT.key, 
        { 
            value: DEFAULT_CONFIG.SCROLL_INCREMENT.value, 
            validator: DEFAULT_CONFIG.SCROLL_INCREMENT.validator,
            supercedes: DEFAULT_CONFIG.SCROLL_INCREMENT.supercedes,
            suppressEvent: DEFAULT_CONFIG.SCROLL_INCREMENT.suppressEvent
        }
    );


    /**
    * @config minscrollheight
    * @description Number defining the minimum threshold for the "maxheight" 
    * configuration property.  When set this property is automatically applied 
    * to all submenus.
    * @default 90
    * @type Number
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.key, 
        { 
            value: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.value, 
            validator: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.validator,
            supercedes: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.supercedes,
            suppressEvent: DEFAULT_CONFIG.MIN_SCROLL_HEIGHT.suppressEvent
        }
    );


    /**
    * @config maxheight
    * @description Number defining the maximum height (in pixels) for a menu's 
    * body element (<code>&#60;div class="bd"&#60;</code>).  Once a menu's body 
    * exceeds this height, the contents of the body are scrolled to maintain 
    * this value.  This value cannot be set lower than the value of the 
    * "minscrollheight" configuration property.
    * @default 0
    * @type Number
    */
    oConfig.addProperty(
       DEFAULT_CONFIG.MAX_HEIGHT.key, 
       {
            handler: this.configMaxHeight,
            value: DEFAULT_CONFIG.MAX_HEIGHT.value,
            validator: DEFAULT_CONFIG.MAX_HEIGHT.validator,
            suppressEvent: DEFAULT_CONFIG.MAX_HEIGHT.suppressEvent,
            supercedes: DEFAULT_CONFIG.MAX_HEIGHT.supercedes            
       } 
    );


    /**
    * @config classname
    * @description String representing the CSS class to be applied to the 
    * menu's root <code>&#60;div&#62;</code> element.  The specified class(es)  
    * are appended in addition to the default class as specified by the menu's
    * CSS_CLASS_NAME constant. When set this property is automatically 
    * applied to all submenus.
    * @default null
    * @type String
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.CLASS_NAME.key, 
        { 
            handler: this.configClassName,
            value: DEFAULT_CONFIG.CLASS_NAME.value, 
            validator: DEFAULT_CONFIG.CLASS_NAME.validator,
            supercedes: DEFAULT_CONFIG.CLASS_NAME.supercedes      
        }
    );


    /**
    * @config disabled
    * @description Boolean indicating if the menu should be disabled.  
    * Disabling a menu disables each of its items.  (Disabled menu items are 
    * dimmed and will not respond to user input or fire events.)  Disabled
    * menus have a corresponding "disabled" CSS class applied to their root
    * <code>&#60;div&#62;</code> element.
    * @default false
    * @type Boolean
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.DISABLED.key, 
        { 
            handler: this.configDisabled,
            value: DEFAULT_CONFIG.DISABLED.value, 
            validator: DEFAULT_CONFIG.DISABLED.validator,
            suppressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
        }
    );

}

}); // END YAHOO.lang.extend

})();



(function () {


/**
* Creates an item for a menu.
* 
* @param {String} p_oObject String specifying the text of the menu item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying 
* the <code>&#60;li&#62;</code> element of the menu item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
* specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object 
* specifying the <code>&#60;option&#62;</code> element of the menu item.
* @param {Object} p_oConfig Optional. Object literal specifying the 
* configuration for the menu item. See configuration class documentation 
* for more details.
* @class MenuItem
* @constructor
*/
YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {

    if (p_oObject) {

        if (p_oConfig) {
    
            this.parent = p_oConfig.parent;
            this.value = p_oConfig.value;
            this.id = p_oConfig.id;

        }

        this.init(p_oObject, p_oConfig);

    }

};


var Dom = YAHOO.util.Dom,
    Module = YAHOO.widget.Module,
    Menu = YAHOO.widget.Menu,
    MenuItem = YAHOO.widget.MenuItem,
    CustomEvent = YAHOO.util.CustomEvent,
    Lang = YAHOO.lang,

    m_oMenuItemTemplate,

    /**
    * Constant representing the name of the MenuItem's events
    * @property EVENT_TYPES
    * @private
    * @final
    * @type Object
    */
    EVENT_TYPES = {
    
        "MOUSE_OVER": "mouseover",
        "MOUSE_OUT": "mouseout",
        "MOUSE_DOWN": "mousedown",
        "MOUSE_UP": "mouseup",
        "CLICK": "click",
        "KEY_PRESS": "keypress",
        "KEY_DOWN": "keydown",
        "KEY_UP": "keyup",
        "ITEM_ADDED": "itemAdded",
        "ITEM_REMOVED": "itemRemoved",
        "FOCUS": "focus",
        "BLUR": "blur",
        "DESTROY": "destroy"
    
    },

    /**
    * Constant representing the MenuItem's configuration properties
    * @property DEFAULT_CONFIG
    * @private
    * @final
    * @type Object
    */
    DEFAULT_CONFIG = {
    
        "TEXT": { 
            key: "text", 
            value: "", 
            validator: Lang.isString, 
            suppressEvent: true 
        }, 
    
        "HELP_TEXT": { 
            key: "helptext",
            supercedes: ["text"], 
            suppressEvent: true 
        },
    
        "URL": { 
            key: "url", 
            value: "#", 
            suppressEvent: true 
        }, 
    
        "TARGET": { 
            key: "target", 
            suppressEvent: true 
        }, 
    
        "EMPHASIS": { 
            key: "emphasis", 
            value: false, 
            validator: Lang.isBoolean, 
            suppressEvent: true, 
            supercedes: ["text"]
        }, 
    
        "STRONG_EMPHASIS": { 
            key: "strongemphasis", 
            value: false, 
            validator: Lang.isBoolean, 
            suppressEvent: true,
            supercedes: ["text"]
        },
    
        "CHECKED": { 
            key: "checked", 
            value: false, 
            validator: Lang.isBoolean, 
            suppressEvent: true, 
            supercedes: ["disabled", "selected"]
        }, 

        "SUBMENU": { 
            key: "submenu",
            suppressEvent: true,
            supercedes: ["disabled", "selected"]
        },
    
        "DISABLED": { 
            key: "disabled", 
            value: false, 
            validator: Lang.isBoolean, 
            suppressEvent: true,
            supercedes: ["text", "selected"]
        },
    
        "SELECTED": { 
            key: "selected", 
            value: false, 
            validator: Lang.isBoolean, 
            suppressEvent: true
        },
    
        "ONCLICK": { 
            key: "onclick",
            suppressEvent: true
        },
    
        "CLASS_NAME": { 
            key: "classname", 
            value: null, 
            validator: Lang.isString,
            suppressEvent: true
        }
    
    };


MenuItem.prototype = {

    /**
    * @property CSS_CLASS_NAME
    * @description String representing the CSS class(es) to be applied to the 
    * <code>&#60;li&#62;</code> element of the menu item.
    * @default "yuimenuitem"
    * @final
    * @type String
    */
    CSS_CLASS_NAME: "yuimenuitem",


    /**
    * @property CSS_LABEL_CLASS_NAME
    * @description String representing the CSS class(es) to be applied to the 
    * menu item's <code>&#60;a&#62;</code> element.
    * @default "yuimenuitemlabel"
    * @final
    * @type String
    */
    CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",


    /**
    * @property SUBMENU_TYPE
    * @description Object representing the type of menu to instantiate and 
    * add when parsing the child nodes of the menu item's source HTML element.
    * @final
    * @type YAHOO.widget.Menu
    */
    SUBMENU_TYPE: null,



    // Private member variables
    

    /**
    * @property _oAnchor
    * @description Object reference to the menu item's 
    * <code>&#60;a&#62;</code> element.
    * @default null 
    * @private
    * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-48250443">HTMLAnchorElement</a>
    */
    _oAnchor: null,
    
    
    /**
    * @property _oHelpTextEM
    * @description Object reference to the menu item's help text 
    * <code>&#60;em&#62;</code> element.
    * @default null
    * @private
    * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-58190037">HTMLElement</a>
    */
    _oHelpTextEM: null,
    
    
    /**
    * @property _oSubmenu
    * @description Object reference to the menu item's submenu.
    * @default null
    * @private
    * @type YAHOO.widget.Menu
    */
    _oSubmenu: null,


    /** 
    * @property _oOnclickAttributeValue
    * @description Object reference to the menu item's current value for the 
    * "onclick" configuration attribute.
    * @default null
    * @private
    * @type Object
    */
    _oOnclickAttributeValue: null,


    /**
    * @property _sClassName
    * @description The current value of the "classname" configuration attribute.
    * @default null
    * @private
    * @type String
    */
    _sClassName: null,



    // Public properties


	/**
    * @property constructor
	* @description Object reference to the menu item's constructor function.
    * @default YAHOO.widget.MenuItem
	* @type YAHOO.widget.MenuItem
	*/
	constructor: MenuItem,


    /**
    * @property index
    * @description Number indicating the ordinal position of the menu item in 
    * its group.
    * @default null
    * @type Number
    */
    index: null,


    /**
    * @property groupIndex
    * @description Number indicating the index of the group to which the menu 
    * item belongs.
    * @default null
    * @type Number
    */
    groupIndex: null,


    /**
    * @property parent
    * @description Object reference to the menu item's parent menu.
    * @default null
    * @type YAHOO.widget.Menu
    */
    parent: null,


    /**
    * @property element
    * @description Object reference to the menu item's 
    * <code>&#60;li&#62;</code> element.
    * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
    * -one-html.html#ID-74680021">HTMLLIElement</a>
    * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-74680021">HTMLLIElement</a>
    */
    element: null,


    /**
    * @property srcElement
    * @description Object reference to the HTML element (either 
    * <code>&#60;li&#62;</code>, <code>&#60;optgroup&#62;</code> or 
    * <code>&#60;option&#62;</code>) used create the menu item.
    * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
    * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
    * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
    * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
    * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
    * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
    * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
    * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
    * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
    */
    srcElement: null,


    /**
    * @property value
    * @description Object reference to the menu item's value.
    * @default null
    * @type Object
    */
    value: null,


	/**
    * @property browser
    * @deprecated Use YAHOO.env.ua
	* @description String representing the browser.
	* @type String
	*/
	browser: Module.prototype.browser,


    /**
    * @property id
    * @description Id of the menu item's root <code>&#60;li&#62;</code> 
    * element.  This property should be set via the constructor using the 
    * configuration object literal.  If an id is not specified, then one will 
    * be created using the "generateId" method of the Dom utility.
    * @default null
    * @type String
    */
    id: null,



    // Events


    /**
    * @event destroyEvent
    * @description Fires when the menu item's <code>&#60;li&#62;</code> 
    * element is removed from its parent <code>&#60;ul&#62;</code> element.
    * @type YAHOO.util.CustomEvent
    */
    destroyEvent: null,


    /**
    * @event mouseOverEvent
    * @description Fires when the mouse has entered the menu item.  Passes 
    * back the DOM Event object as an argument.
    * @type YAHOO.util.CustomEvent
    */
    mouseOverEvent: null,


    /**
    * @event mouseOutEvent
    * @description Fires when the mouse has left the menu item.  Passes back 
    * the DOM Event object as an argument.
    * @type YAHOO.util.CustomEvent
    */
    mouseOutEvent: null,


    /**
    * @event mouseDownEvent
    * @description Fires when the user mouses down on the menu item.  Passes 
    * back the DOM Event object as an argument.
    * @type YAHOO.util.CustomEvent
    */
    mouseDownEvent: null,


    /**
    * @event mouseUpEvent
    * @description Fires when the user releases a mouse button while the mouse 
    * is over the menu item.  Passes back the DOM Event object as an argument.
    * @type YAHOO.util.CustomEvent
    */
    mouseUpEvent: null,


    /**
    * @event clickEvent
    * @description Fires when the user clicks the on the menu item.  Passes 
    * back the DOM Event object as an argument.
    * @type YAHOO.util.CustomEvent
    */
    clickEvent: null,


    /**
    * @event keyPressEvent
    * @description Fires when the user presses an alphanumeric key when the 
    * menu item has focus.  Passes back the DOM Event object as an argument.
    * @type YAHOO.util.CustomEvent
    */
    keyPressEvent: null,


    /**
    * @event keyDownEvent
    * @description Fires when the user presses a key when the menu item has 
    * focus.  Passes back the DOM Event object as an argument.
    * @type YAHOO.util.CustomEvent
    */
    keyDownEvent: null,


    /**
    * @event keyUpEvent
    * @description Fires when the user releases a key when the menu item has 
    * focus.  Passes back the DOM Event object as an argument.
    * @type YAHOO.util.CustomEvent
    */
    keyUpEvent: null,


    /**
    * @event focusEvent
    * @description Fires when the menu item receives focus.
    * @type YAHOO.util.CustomEvent
    */
    focusEvent: null,


    /**
    * @event blurEvent
    * @description Fires when the menu item loses the input focus.
    * @type YAHOO.util.CustomEvent
    */
    blurEvent: null,


    /**
    * @method init
    * @description The MenuItem class's initialization method. This method is 
    * automatically called by the constructor, and sets up all DOM references 
    * for pre-existing markup, and creates required markup if it is not 
    * already present.
    * @param {String} p_oObject String specifying the text of the menu item.
    * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying 
    * the <code>&#60;li&#62;</code> element of the menu item.
    * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
    * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
    * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object 
    * specifying the <code>&#60;option&#62;</code> element of the menu item.
    * @param {Object} p_oConfig Optional. Object literal specifying the 
    * configuration for the menu item. See configuration class documentation 
    * for more details.
    */
    init: function (p_oObject, p_oConfig) {


        if (!this.SUBMENU_TYPE) {
    
            this.SUBMENU_TYPE = Menu;
    
        }


        // Create the config object

        this.cfg = new YAHOO.util.Config(this);

        this.initDefaultConfig();

        var SIGNATURE = CustomEvent.LIST,
            oConfig = this.cfg,
            sURL = "#",
            oAnchor,
            sTarget,
            sText,
            sId;


        if (Lang.isString(p_oObject)) {

            this._createRootNodeStructure();

            oConfig.queueProperty("text", p_oObject);

        }
        else if (p_oObject && p_oObject.tagName) {

            switch(p_oObject.tagName.toUpperCase()) {

                case "OPTION":

                    this._createRootNodeStructure();

                    oConfig.queueProperty("text", p_oObject.text);
                    oConfig.queueProperty("disabled", p_oObject.disabled);

                    this.value = p_oObject.value;

                    this.srcElement = p_oObject;

                break;

                case "OPTGROUP":

                    this._createRootNodeStructure();

                    oConfig.queueProperty("text", p_oObject.label);
                    oConfig.queueProperty("disabled", p_oObject.disabled);

                    this.srcElement = p_oObject;

                    this._initSubTree();

                break;

                case "LI":

                    // Get the anchor node (if it exists)
                    
                    oAnchor = Dom.getFirstChild(p_oObject);


                    // Capture the "text" and/or the "URL"

                    if (oAnchor) {

                        sURL = oAnchor.getAttribute("href", 2);
                        sTarget = oAnchor.getAttribute("target");

                        sText = oAnchor.innerHTML;

                    }

                    this.srcElement = p_oObject;
                    this.element = p_oObject;
                    this._oAnchor = oAnchor;

                    /*
                        Set these properties silently to sync up the 
                        configuration object without making changes to the 
                        element's DOM
                    */ 

                    oConfig.setProperty("text", sText, true);
                    oConfig.setProperty("url", sURL, true);
                    oConfig.setProperty("target", sTarget, true);

                    this._initSubTree();

                break;

            }            

        }


        if (this.element) {

            sId = (this.srcElement || this.element).id;

            if (!sId) {

                sId = this.id || Dom.generateId();

                this.element.id = sId;

            }

            this.id = sId;


            Dom.addClass(this.element, this.CSS_CLASS_NAME);
            Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);


            // Create custom events

            this.mouseOverEvent = this.createEvent(EVENT_TYPES.MOUSE_OVER);
            this.mouseOverEvent.signature = SIGNATURE;

            this.mouseOutEvent = this.createEvent(EVENT_TYPES.MOUSE_OUT);
            this.mouseOutEvent.signature = SIGNATURE;

            this.mouseDownEvent = this.createEvent(EVENT_TYPES.MOUSE_DOWN);
            this.mouseDownEvent.signature = SIGNATURE;

            this.mouseUpEvent = this.createEvent(EVENT_TYPES.MOUSE_UP);
            this.mouseUpEvent.signature = SIGNATURE;

            this.clickEvent = this.createEvent(EVENT_TYPES.CLICK);
            this.clickEvent.signature = SIGNATURE;

            this.keyPressEvent = this.createEvent(EVENT_TYPES.KEY_PRESS);
            this.keyPressEvent.signature = SIGNATURE;

            this.keyDownEvent = this.createEvent(EVENT_TYPES.KEY_DOWN);
            this.keyDownEvent.signature = SIGNATURE;

            this.keyUpEvent = this.createEvent(EVENT_TYPES.KEY_UP);
            this.keyUpEvent.signature = SIGNATURE;

            this.focusEvent = this.createEvent(EVENT_TYPES.FOCUS);
            this.focusEvent.signature = SIGNATURE;

            this.blurEvent = this.createEvent(EVENT_TYPES.BLUR);
            this.blurEvent.signature = SIGNATURE;

            this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
            this.destroyEvent.signature = SIGNATURE;

            if (p_oConfig) {
    
                oConfig.applyConfig(p_oConfig);
    
            }        

            oConfig.fireQueue();

        }

    },



    // Private methods


    /**
    * @method _createRootNodeStructure
    * @description Creates the core DOM structure for the menu item.
    * @private
    */
    _createRootNodeStructure: function () {

        var oElement,
            oAnchor;

        if (!m_oMenuItemTemplate) {

            m_oMenuItemTemplate = document.createElement("li");
            m_oMenuItemTemplate.innerHTML = "<a href=\"#\"></a>";

        }

        oElement = m_oMenuItemTemplate.cloneNode(true);
        oElement.className = this.CSS_CLASS_NAME;

        oAnchor = oElement.firstChild;
        oAnchor.className = this.CSS_LABEL_CLASS_NAME;
        
        this.element = oElement;
        this._oAnchor = oAnchor;

    },


    /**
    * @method _initSubTree
    * @description Iterates the source element's childNodes collection and uses 
    * the child nodes to instantiate other menus.
    * @private
    */
    _initSubTree: function () {

        var oSrcEl = this.srcElement,
            oConfig = this.cfg,
            oNode,
            aOptions,
            nOptions,
            oMenu,
            n;


        if (oSrcEl.childNodes.length > 0) {

            if (this.parent.lazyLoad && this.parent.srcElement && 
                this.parent.srcElement.tagName.toUpperCase() == "SELECT") {

                oConfig.setProperty(
                        "submenu", 
                        { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
                    );

            }
            else {

                oNode = oSrcEl.firstChild;
                aOptions = [];
    
                do {
    
                    if (oNode && oNode.tagName) {
    
                        switch(oNode.tagName.toUpperCase()) {
                
                            case "DIV":
                
                                oConfig.setProperty("submenu", oNode);
                
                            break;
         
                            case "OPTION":
        
                                aOptions[aOptions.length] = oNode;
        
                            break;
               
                        }
                    
                    }
                
                }        
                while((oNode = oNode.nextSibling));
    
    
                nOptions = aOptions.length;
    
                if (nOptions > 0) {
    
                    oMenu = new this.SUBMENU_TYPE(Dom.generateId());
                    
                    oConfig.setProperty("submenu", oMenu);
    
                    for(n=0; n<nOptions; n++) {
        
                        oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
        
                    }
        
                }
            
            }

        }

    },



    // Event handlers for configuration properties


    /**
    * @method configText
    * @description Event handler for when the "text" configuration property of 
    * the menu item changes.
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */
    configText: function (p_sType, p_aArgs, p_oItem) {

        var sText = p_aArgs[0],
            oConfig = this.cfg,
            oAnchor = this._oAnchor,
            sHelpText = oConfig.getProperty("helptext"),
            sHelpTextHTML = "",
            sEmphasisStartTag = "",
            sEmphasisEndTag = "";


        if (sText) {


            if (sHelpText) {
                    
                sHelpTextHTML = "<em class=\"helptext\">" + sHelpText + "</em>";
            
            }


            if (oConfig.getProperty("emphasis")) {

                sEmphasisStartTag = "<em>";
                sEmphasisEndTag = "</em>";

            }


            if (oConfig.getProperty("strongemphasis")) {

                sEmphasisStartTag = "<strong>";
                sEmphasisEndTag = "</strong>";
            
            }


            oAnchor.innerHTML = (sEmphasisStartTag + sText + 
                sEmphasisEndTag + sHelpTextHTML);

        }

    },


    /**
    * @method configHelpText
    * @description Event handler for when the "helptext" configuration property 
    * of the menu item changes.
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */    
    configHelpText: function (p_sType, p_aArgs, p_oItem) {

        this.cfg.refireEvent("text");

    },


    /**
    * @method configURL
    * @description Event handler for when the "url" configuration property of 
    * the menu item changes.
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */    
    configURL: function (p_sType, p_aArgs, p_oItem) {

        var sURL = p_aArgs[0];

        if (!sURL) {

            sURL = "#";

        }

        var oAnchor = this._oAnchor;

        if (YAHOO.env.ua.opera) {

            oAnchor.removeAttribute("href");
        
        }

        oAnchor.setAttribute("href", sURL);

    },


    /**
    * @method configTarget
    * @description Event handler for when the "target" configuration property 
    * of the menu item changes.  
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */    
    configTarget: function (p_sType, p_aArgs, p_oItem) {

        var sTarget = p_aArgs[0],
            oAnchor = this._oAnchor;

        if (sTarget && sTarget.length > 0) {

            oAnchor.setAttribute("target", sTarget);

        }
        else {

            oAnchor.removeAttribute("target");
        
        }

    },


    /**
    * @method configEmphasis
    * @description Event handler for when the "emphasis" configuration property
    * of the menu item changes.
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */    
    configEmphasis: function (p_sType, p_aArgs, p_oItem) {

        var bEmphasis = p_aArgs[0],
            oConfig = this.cfg;


        if (bEmphasis && oConfig.getProperty("strongemphasis")) {

            oConfig.setProperty("strongemphasis", false);

        }


        oConfig.refireEvent("text");

    },


    /**
    * @method configStrongEmphasis
    * @description Event handler for when the "strongemphasis" configuration 
    * property of the menu item changes.
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */    
    configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {

        var bStrongEmphasis = p_aArgs[0],
            oConfig = this.cfg;


        if (bStrongEmphasis && oConfig.getProperty("emphasis")) {

            oConfig.setProperty("emphasis", false);

        }

        oConfig.refireEvent("text");

    },


    /**
    * @method configChecked
    * @description Event handler for when the "checked" configuration property 
    * of the menu item changes. 
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */    
    configChecked: function (p_sType, p_aArgs, p_oItem) {

        var bChecked = p_aArgs[0],
            oElement = this.element,
            oAnchor = this._oAnchor,
            oConfig = this.cfg,
            sState = "-checked",
            sClassName = this.CSS_CLASS_NAME + sState,
            sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState;


        if (bChecked) {

            Dom.addClass(oElement, sClassName);
            Dom.addClass(oAnchor, sLabelClassName);

        }
        else {

            Dom.removeClass(oElement, sClassName);
            Dom.removeClass(oAnchor, sLabelClassName);
        
        }


        oConfig.refireEvent("text");


        if (oConfig.getProperty("disabled")) {

            oConfig.refireEvent("disabled");

        }


        if (oConfig.getProperty("selected")) {

            oConfig.refireEvent("selected");

        }

    },



    /**
    * @method configDisabled
    * @description Event handler for when the "disabled" configuration property 
    * of the menu item changes. 
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */    
    configDisabled: function (p_sType, p_aArgs, p_oItem) {

        var bDisabled = p_aArgs[0],
            oConfig = this.cfg,
            oSubmenu = oConfig.getProperty("submenu"),
            bChecked = oConfig.getProperty("checked"),
            oElement = this.element,
            oAnchor = this._oAnchor,
            sState = "-disabled",
            sCheckedState = "-checked" + sState,
            sSubmenuState = "-hassubmenu" + sState,
            sClassName = this.CSS_CLASS_NAME + sState,
            sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState,
            sCheckedClassName = this.CSS_CLASS_NAME + sCheckedState,
            sLabelCheckedClassName = this.CSS_LABEL_CLASS_NAME + sCheckedState,
            sSubmenuClassName = this.CSS_CLASS_NAME + sSubmenuState,
            sLabelSubmenuClassName = this.CSS_LABEL_CLASS_NAME + sSubmenuState;


        if (bDisabled) {

            if (oConfig.getProperty("selected")) {

                oConfig.setProperty("selected", false);

            }

            Dom.addClass(oElement, sClassName);
            Dom.addClass(oAnchor, sLabelClassName);


            if (oSubmenu) {

                Dom.addClass(oElement, sSubmenuClassName);
                Dom.addClass(oAnchor, sLabelSubmenuClassName);
            
            }
            

            if (bChecked) {

                Dom.addClass(oElement, sCheckedClassName);
                Dom.addClass(oAnchor, sLabelCheckedClassName);

            }

        }
        else {

            Dom.removeClass(oElement, sClassName);
            Dom.removeClass(oAnchor, sLabelClassName);


            if (oSubmenu) {

                Dom.removeClass(oElement, sSubmenuClassName);
                Dom.removeClass(oAnchor, sLabelSubmenuClassName);
            
            }
            

            if (bChecked) {

                Dom.removeClass(oElement, sCheckedClassName);
                Dom.removeClass(oAnchor, sLabelCheckedClassName);

            }

        }

    },


    /**
    * @method configSelected
    * @description Event handler for when the "selected" configuration property 
    * of the menu item changes. 
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */    
    configSelected: function (p_sType, p_aArgs, p_oItem) {

        var oConfig = this.cfg,
            bSelected = p_aArgs[0],
            oElement = this.element,
            oAnchor = this._oAnchor,
            bChecked = oConfig.getProperty("checked"),
            oSubmenu = oConfig.getProperty("submenu"),
            sState = "-selected",
            sCheckedState = "-checked" + sState,
            sSubmenuState = "-hassubmenu" + sState,
            sClassName = this.CSS_CLASS_NAME + sState,
            sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState,
            sCheckedClassName = this.CSS_CLASS_NAME + sCheckedState,
            sLabelCheckedClassName = this.CSS_LABEL_CLASS_NAME + sCheckedState,
            sSubmenuClassName = this.CSS_CLASS_NAME + sSubmenuState,
            sLabelSubmenuClassName = this.CSS_LABEL_CLASS_NAME + sSubmenuState;


        if (YAHOO.env.ua.opera) {

            oAnchor.blur();
        
        }


        if (bSelected && !oConfig.getProperty("disabled")) {

            Dom.addClass(oElement, sClassName);
            Dom.addClass(oAnchor, sLabelClassName);


            if (oSubmenu) {

                Dom.addClass(oElement, sSubmenuClassName);
                Dom.addClass(oAnchor, sLabelSubmenuClassName);
            
            }


            if (bChecked) {

                Dom.addClass(oElement, sCheckedClassName);
                Dom.addClass(oAnchor, sLabelCheckedClassName);

            }

        }
        else {

            Dom.removeClass(oElement, sClassName);
            Dom.removeClass(oAnchor, sLabelClassName);


            if (oSubmenu) {

                Dom.removeClass(oElement, sSubmenuClassName);
                Dom.removeClass(oAnchor, sLabelSubmenuClassName);
            
            }

        
            if (bChecked) {

                Dom.removeClass(oElement, sCheckedClassName);
                Dom.removeClass(oAnchor, sLabelCheckedClassName);

            }

        }


        if (this.hasFocus() && YAHOO.env.ua.opera) {
        
            oAnchor.focus();
        
        }

    },


    /**
    * @method _onSubmenuBeforeHide
    * @description "beforehide" Custom Event handler for a submenu.
    * @private
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    */
    _onSubmenuBeforeHide: function (p_sType, p_aArgs) {

        var oItem = this.parent,
            oMenu;

        function onHide() {

            oItem._oAnchor.blur();
            oMenu.beforeHideEvent.unsubscribe(onHide);
        
        }


        if (oItem.hasFocus()) {

            oMenu = oItem.parent;

            oMenu.beforeHideEvent.subscribe(onHide);
        
        }
    
    },


    /**
    * @method configSubmenu
    * @description Event handler for when the "submenu" configuration property 
    * of the menu item changes. 
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */
    configSubmenu: function (p_sType, p_aArgs, p_oItem) {

        var oSubmenu = p_aArgs[0],
            oConfig = this.cfg,
            oElement = this.element,
            oAnchor = this._oAnchor,
            bLazyLoad = this.parent && this.parent.lazyLoad,
            sState = "-hassubmenu",
            sClassName = this.CSS_CLASS_NAME + sState,
            sLabelClassName = this.CSS_LABEL_CLASS_NAME + sState,
            oMenu,
            sSubmenuId,
            oSubmenuConfig;


        if (oSubmenu) {

            if (oSubmenu instanceof Menu) {

                oMenu = oSubmenu;
                oMenu.parent = this;
                oMenu.lazyLoad = bLazyLoad;

            }
            else if (typeof oSubmenu == "object" && oSubmenu.id && 
                !oSubmenu.nodeType) {

                sSubmenuId = oSubmenu.id;
                oSubmenuConfig = oSubmenu;

                oSubmenuConfig.lazyload = bLazyLoad;
                oSubmenuConfig.parent = this;

                oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);


                // Set the value of the property to the Menu instance

                oConfig.setProperty("submenu", oMenu, true);

            }
            else {

                oMenu = new this.SUBMENU_TYPE(oSubmenu,
                                { lazyload: bLazyLoad, parent: this });


                // Set the value of the property to the Menu instance
                
                oConfig.setProperty("submenu", oMenu, true);

            }


            if (oMenu) {

                Dom.addClass(oElement, sClassName);
                Dom.addClass(oAnchor, sLabelClassName);

                this._oSubmenu = oMenu;

                if (YAHOO.env.ua.opera) {
                
                    oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);               
                
                }
            
            }

        }
        else {

            Dom.removeClass(oElement, sClassName);
            Dom.removeClass(oAnchor, sLabelClassName);

            if (this._oSubmenu) {

                this._oSubmenu.destroy();

            }

        }


        if (oConfig.getProperty("disabled")) {

            oConfig.refireEvent("disabled");

        }


        if (oConfig.getProperty("selected")) {

            oConfig.refireEvent("selected");

        }

    },


    /**
    * @method configOnClick
    * @description Event handler for when the "onclick" configuration property 
    * of the menu item changes. 
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */
    configOnClick: function (p_sType, p_aArgs, p_oItem) {

        var oObject = p_aArgs[0];

        /*
            Remove any existing listeners if a "click" event handler has 
            already been specified.
        */

        if (this._oOnclickAttributeValue && 
            (this._oOnclickAttributeValue != oObject)) {

            this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn, 
                                this._oOnclickAttributeValue.obj);

            this._oOnclickAttributeValue = null;

        }


        if (!this._oOnclickAttributeValue && typeof oObject == "object" && 
            typeof oObject.fn == "function") {
            
            this.clickEvent.subscribe(oObject.fn, 
                ((!YAHOO.lang.isUndefined(oObject.obj)) ? oObject.obj : this), 
                oObject.scope);

            this._oOnclickAttributeValue = oObject;

        }
    
    },


    /**
    * @method configClassName
    * @description Event handler for when the "classname" configuration 
    * property of a menu item changes.
    * @param {String} p_sType String representing the name of the event that 
    * was fired.
    * @param {Array} p_aArgs Array of arguments sent when the event was fired.
    * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
    * that fired the event.
    */
    configClassName: function (p_sType, p_aArgs, p_oItem) {
    
        var sClassName = p_aArgs[0];
    
        if (this._sClassName) {
    
            Dom.removeClass(this.element, this._sClassName);
    
        }
    
        Dom.addClass(this.element, sClassName);
        this._sClassName = sClassName;
    
    },



    // Public methods


	/**
    * @method initDefaultConfig
	* @description Initializes an item's configurable properties.
	*/
	initDefaultConfig : function () {

        var oConfig = this.cfg;


        // Define the configuration attributes

        /**
        * @config text
        * @description String specifying the text label for the menu item.  
        * When building a menu from existing HTML the value of this property
        * will be interpreted from the menu's markup.
        * @default ""
        * @type String
        */
        oConfig.addProperty(
            DEFAULT_CONFIG.TEXT.key, 
            { 
                handler: this.configText, 
                value: DEFAULT_CONFIG.TEXT.value, 
                validator: DEFAULT_CONFIG.TEXT.validator, 
                suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent 
            }
        );
        

        /**
        * @config helptext
        * @description String specifying additional instructional text to 
        * accompany the text for the menu item.
        * @deprecated Use "text" configuration property to add help text markup.  
        * For example: <code>oMenuItem.cfg.setProperty("text", "Copy &#60;em 
        * class=\"helptext\"&#62;Ctrl + C&#60;/em&#62;");</code>
        * @default null
        * @type String|<a href="http://www.w3.org/TR/
        * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
        * HTMLElement</a>
        */
        oConfig.addProperty(
            DEFAULT_CONFIG.HELP_TEXT.key,
            {
                handler: this.configHelpText, 
                supercedes: DEFAULT_CONFIG.HELP_TEXT.supercedes,
                suppressEvent: DEFAULT_CONFIG.HELP_TEXT.suppressEvent 
            }
        );


        /**
        * @config url
        * @description String specifying the URL for the menu item's anchor's 
        * "href" attribute.  When building a menu from existing HTML the value 
        * of this property will be interpreted from the menu's markup.
        * @default "#"
        * @type String
        */        
        oConfig.addProperty(
            DEFAULT_CONFIG.URL.key, 
            {
                handler: this.configURL, 
                value: DEFAULT_CONFIG.URL.value, 
                suppressEvent: DEFAULT_CONFIG.URL.suppressEvent
            }
        );


        /**
        * @config target
        * @description String specifying the value for the "target" attribute 
        * of the menu item's anchor element. <strong>Specifying a target will 
        * require the user to click directly on the menu item's anchor node in
        * order to cause the browser to navigate to the specified URL.</strong> 
        * When building a menu from existing HTML the value of this property 
        * will be interpreted from the menu's markup.
        * @default null
        * @type String
        */        
        oConfig.addProperty(
            DEFAULT_CONFIG.TARGET.key, 
            {
                handler: this.configTarget, 
                suppressEvent: DEFAULT_CONFIG.TARGET.suppressEvent
            }
        );


        /**
        * @config emphasis
        * @description Boolean indicating if the text of the menu item will be 
        * rendered with emphasis.
        * @deprecated Use "text" configuration property to add emphasis.  
        * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;em&#62;Some 
        * Text&#60;/em&#62;");</code>
        * @default false
        * @type Boolean
        */
        oConfig.addProperty(
            DEFAULT_CONFIG.EMPHASIS.key, 
            { 
                handler: this.configEmphasis, 
                value: DEFAULT_CONFIG.EMPHASIS.value, 
                validator: DEFAULT_CONFIG.EMPHASIS.validator, 
                suppressEvent: DEFAULT_CONFIG.EMPHASIS.suppressEvent,
                supercedes: DEFAULT_CONFIG.EMPHASIS.supercedes
            }
        );


        /**
        * @config strongemphasis
        * @description Boolean indicating if the text of the menu item will be 
        * rendered with strong emphasis.
        * @deprecated Use "text" configuration property to add strong emphasis.  
        * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;strong&#62; 
        * Some Text&#60;/strong&#62;");</code>
        * @default false
        * @type Boolean
        */
        oConfig.addProperty(
            DEFAULT_CONFIG.STRONG_EMPHASIS.key,
            {
                handler: this.configStrongEmphasis,
                value: DEFAULT_CONFIG.STRONG_EMPHASIS.value,
                validator: DEFAULT_CONFIG.STRONG_EMPHASIS.validator,
                suppressEvent: DEFAULT_CONFIG.STRONG_EMPHASIS.suppressEvent,
                supercedes: DEFAULT_CONFIG.STRONG_EMPHASIS.supercedes
            }
        );


        /**
        * @config checked
        * @description Boolean indicating if the menu item should be rendered 
        * with a checkmark.
        * @default false
        * @type Boolean
        */
        oConfig.addProperty(
            DEFAULT_CONFIG.CHECKED.key, 
            {
                handler: this.configChecked, 
                value: DEFAULT_CONFIG.CHECKED.value, 
                validator: DEFAULT_CONFIG.CHECKED.validator, 
                suppressEvent: DEFAULT_CONFIG.CHECKED.suppressEvent,
                supercedes: DEFAULT_CONFIG.CHECKED.supercedes
            } 
        );


        /**
        * @config disabled
        * @description Boolean indicating if the menu item should be disabled.  
        * (Disabled menu items are  dimmed and will not respond to user input 
        * or fire events.)
        * @default false
        * @type Boolean
        */
        oConfig.addProperty(
            DEFAULT_CONFIG.DISABLED.key,
            {
                handler: this.configDisabled,
                value: DEFAULT_CONFIG.DISABLED.value,
                validator: DEFAULT_CONFIG.DISABLED.validator,
                suppressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
            }
        );


        /**
        * @config selected
        * @description Boolean indicating if the menu item should 
        * be highlighted.
        * @default false
        * @type Boolean
        */
        oConfig.addProperty(
            DEFAULT_CONFIG.SELECTED.key,
            {
                handler: this.configSelected,
                value: DEFAULT_CONFIG.SELECTED.value,
                validator: DEFAULT_CONFIG.SELECTED.validator,
                suppressEvent: DEFAULT_CONFIG.SELECTED.suppressEvent
            }
        );


        /**
        * @config submenu
        * @description Object specifying the submenu to be appended to the 
        * menu item.  The value can be one of the following: <ul><li>Object 
        * specifying a Menu instance.</li><li>Object literal specifying the
        * menu to be created.  Format: <code>{ id: [menu id], itemdata: 
        * [<a href="YAHOO.widget.Menu.html#itemData">array of values for 
        * items</a>] }</code>.</li><li>String specifying the id attribute 
        * of the <code>&#60;div&#62;</code> element of the menu.</li><li>
        * Object specifying the <code>&#60;div&#62;</code> element of the 
        * menu.</li></ul>
        * @default null
        * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
        * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
        * HTMLElement</a>
        */
        oConfig.addProperty(
            DEFAULT_CONFIG.SUBMENU.key, 
            {
                handler: this.configSubmenu, 
                supercedes: DEFAULT_CONFIG.SUBMENU.supercedes,
                suppressEvent: DEFAULT_CONFIG.SUBMENU.suppressEvent
            }
        );


        /**
        * @config onclick
        * @description Object literal representing the code to be executed when 
        * the item is clicked.  Format:<br> <code> {<br> 
        * <strong>fn:</strong> Function,   &#47;&#47; The handler to call when 
        * the event fires.<br> <strong>obj:</strong> Object, &#47;&#47; An 
        * object to  pass back to the handler.<br> <strong>scope:</strong> 
        * Object &#47;&#47; The object to use for the scope of the handler.
        * <br> } </code>
        * @type Object
        * @default null
        */
        oConfig.addProperty(
            DEFAULT_CONFIG.ONCLICK.key, 
            {
                handler: this.configOnClick, 
                suppressEvent: DEFAULT_CONFIG.ONCLICK.suppressEvent 
            }
        );


        /**
        * @config classname
        * @description CSS class to be applied to the menu item's root 
        * <code>&#60;li&#62;</code> element.  The specified class(es) are 
        * appended in addition to the default class as specified by the menu 
        * item's CSS_CLASS_NAME constant.
        * @default null
        * @type String
        */
        oConfig.addProperty(
            DEFAULT_CONFIG.CLASS_NAME.key, 
            { 
                handler: this.configClassName,
                value: DEFAULT_CONFIG.CLASS_NAME.value, 
                validator: DEFAULT_CONFIG.CLASS_NAME.validator,
                suppressEvent: DEFAULT_CONFIG.CLASS_NAME.suppressEvent 
            }
        );

	},


    /**
    * @method getNextEnabledSibling
    * @description Finds the menu item's next enabled sibling.
    * @return YAHOO.widget.MenuItem
    */
    getNextEnabledSibling: function () {

        var nGroupIndex,
            aItemGroups,
            oNextItem,
            nNextGroupIndex,
            aNextGroup;

        function getNextArrayItem(p_aArray, p_nStartIndex) {

            return p_aArray[p_nStartIndex] || 
                getNextArrayItem(p_aArray, (p_nStartIndex+1));

        }

        if (this.parent instanceof Menu) {

            nGroupIndex = this.groupIndex;
    
            aItemGroups = this.parent.getItemGroups();
    
            if (this.index < (aItemGroups[nGroupIndex].length - 1)) {
    
                oNextItem = getNextArrayItem(aItemGroups[nGroupIndex], 
                        (this.index+1));
    
            }
            else {
    
                if (nGroupIndex < (aItemGroups.length - 1)) {
    
                    nNextGroupIndex = nGroupIndex + 1;
    
                }
                else {
    
                    nNextGroupIndex = 0;
    
                }
    
                aNextGroup = getNextArrayItem(aItemGroups, nNextGroupIndex);
    
                // Retrieve the first menu item in the next group
    
                oNextItem = getNextArrayItem(aNextGroup, 0);
    
            }
    
            return (oNextItem.cfg.getProperty("disabled") || 
                oNextItem.element.style.display == "none") ? 
                oNextItem.getNextEnabledSibling() : oNextItem;

        }

    },


    /**
    * @method getPreviousEnabledSibling
    * @description Finds the menu item's previous enabled sibling.
    * @return {YAHOO.widget.MenuItem}
    */
    getPreviousEnabledSibling: function () {

        var nGroupIndex,
            aItemGroups,
            oPreviousItem,
            nPreviousGroupIndex,
            aPreviousGroup;

        function getPreviousArrayItem(p_aArray, p_nStartIndex) {

            return p_aArray[p_nStartIndex] ||  
                getPreviousArrayItem(p_aArray, (p_nStartIndex-1));

        }

        function getFirstItemIndex(p_aArray, p_nStartIndex) {

            return p_aArray[p_nStartIndex] ? p_nStartIndex : 
                getFirstItemIndex(p_aArray, (p_nStartIndex+1));

        }

       if (this.parent instanceof Menu) {

            nGroupIndex = this.groupIndex;
            aItemGroups = this.parent.getItemGroups();

    
            if (this.index > getFirstItemIndex(aItemGroups[nGroupIndex], 0)) {
    
                oPreviousItem = getPreviousArrayItem(aItemGroups[nGroupIndex], 
                        (this.index-1));
    
            }
            else {
    
                if (nGroupIndex > getFirstItemIndex(aItemGroups, 0)) {
    
                    nPreviousGroupIndex = nGroupIndex - 1;
    
                }
                else {
    
                    nPreviousGroupIndex = aItemGroups.length - 1;
    
                }
    
                aPreviousGroup = getPreviousArrayItem(aItemGroups, 
                    nPreviousGroupIndex);
    
                oPreviousItem = getPreviousArrayItem(aPreviousGroup, 
                        (aPreviousGroup.length - 1));
    
            }

            return (oPreviousItem.cfg.getProperty("disabled") || 
                oPreviousItem.element.style.display == "none") ? 
                oPreviousItem.getPreviousEnabledSibling() : oPreviousItem;

        }

    },


    /**
    * @method focus
    * @description Causes the menu item to receive the focus and fires the 
    * focus event.
    */
    focus: function () {

        var oParent = this.parent,
            oAnchor = this._oAnchor,
            oActiveItem = oParent.activeItem,
            me = this;


        function setFocus() {

            try {

                if (YAHOO.env.ua.ie && !document.hasFocus()) {
                
                    return;
                
                }

                if (oActiveItem) {
    
                    oActiveItem.blurEvent.fire();
    
                }

                oAnchor.focus();
                
                me.focusEvent.fire();

            }
            catch(e) {
            
            }

        }


        if (!this.cfg.getProperty("disabled") && oParent && 
            oParent.cfg.getProperty("visible") && 
            this.element.style.display != "none") {


            /*
                Setting focus via a timer fixes a race condition in Firefox, IE 
                and Opera where the browser viewport jumps as it trys to 
                position and focus the menu.
            */

            window.setTimeout(setFocus, 0);

        }

    },


    /**
    * @method blur
    * @description Causes the menu item to lose focus and fires the 
    * blur event.
    */    
    blur: function () {

        var oParent = this.parent;

        if (!this.cfg.getProperty("disabled") && oParent && 
            oParent.cfg.getProperty("visible")) {


            var me = this;
            
            window.setTimeout(function () {

                try {
    
                    me._oAnchor.blur();
                    me.blurEvent.fire();    

                } 
                catch (e) {
                
                }
                
            }, 0);

        }

    },


    /**
    * @method hasFocus
    * @description Returns a boolean indicating whether or not the menu item
    * has focus.
    * @return {Boolean}
    */
    hasFocus: function () {
    
        return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
    
    },


	/**
    * @method destroy
	* @description Removes the menu item's <code>&#60;li&#62;</code> element 
	* from its parent <code>&#60;ul&#62;</code> element.
	*/
    destroy: function () {

        var oEl = this.element,
            oSubmenu,
            oParentNode;

        if (oEl) {


            // If the item has a submenu, destroy it first

            oSubmenu = this.cfg.getProperty("submenu");

            if (oSubmenu) {
            
                oSubmenu.destroy();
            
            }


            // Remove CustomEvent listeners
    
            this.mouseOverEvent.unsubscribeAll();
            this.mouseOutEvent.unsubscribeAll();
            this.mouseDownEvent.unsubscribeAll();
            this.mouseUpEvent.unsubscribeAll();
            this.clickEvent.unsubscribeAll();
            this.keyPressEvent.unsubscribeAll();
            this.keyDownEvent.unsubscribeAll();
            this.keyUpEvent.unsubscribeAll();
            this.focusEvent.unsubscribeAll();
            this.blurEvent.unsubscribeAll();
            this.cfg.configChangedEvent.unsubscribeAll();


            // Remove the element from the parent node

            oParentNode = oEl.parentNode;

            if (oParentNode) {

                oParentNode.removeChild(oEl);

                this.destroyEvent.fire();

            }

            this.destroyEvent.unsubscribeAll();

        }

    },


    /**
    * @method toString
    * @description Returns a string representing the menu item.
    * @return {String}
    */
    toString: function () {

        var sReturnVal = "MenuItem",
            sId = this.id;

        if (sId) {
    
            sReturnVal += (" " + sId);
        
        }

        return sReturnVal;
    
    }

};

Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);

})();
(function () {


/**
* Creates a list of options or commands which are made visible in response to 
* an HTML element's "contextmenu" event ("mousedown" for Opera).
*
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;div&#62;</code> element of the context menu.
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;select&#62;</code> element to be used as the data source for the 
* context menu.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
* html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the 
* <code>&#60;div&#62;</code> element of the context menu.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
* html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying 
* the <code>&#60;select&#62;</code> element to be used as the data source for 
* the context menu.
* @param {Object} p_oConfig Optional. Object literal specifying the 
* configuration for the context menu. See configuration class documentation 
* for more details.
* @class ContextMenu
* @constructor
* @extends YAHOO.widget.Menu
* @namespace YAHOO.widget
*/
YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {

    YAHOO.widget.ContextMenu.superclass.constructor.call(this, 
            p_oElement, p_oConfig);

};


var Event = YAHOO.util.Event,
    ContextMenu = YAHOO.widget.ContextMenu,



    /**
    * Constant representing the name of the ContextMenu's events
    * @property EVENT_TYPES
    * @private
    * @final
    * @type Object
    */
    EVENT_TYPES = {

        "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
        "CONTEXT_MENU": (YAHOO.env.ua.opera ? "mousedown" : "contextmenu"),
        "CLICK": "click"

    },
    
    
    /**
    * Constant representing the ContextMenu's configuration properties
    * @property DEFAULT_CONFIG
    * @private
    * @final
    * @type Object
    */
    DEFAULT_CONFIG = {
    
        "TRIGGER": { 
            key: "trigger",
            suppressEvent: true
        }
    
    };


/**
* @method position
* @description "beforeShow" event handler used to position the contextmenu.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {Array} p_aPos Array representing the xy position for the context menu.
*/
function position(p_sType, p_aArgs, p_aPos) {

    this.cfg.setProperty("xy", p_aPos);
    
    this.beforeShowEvent.unsubscribe(position, p_aPos);

}


YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {



// Private properties


/**
* @property _oTrigger
* @description Object reference to the current value of the "trigger" 
* configuration property.
* @default null
* @private
* @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
* l-one-html.html#ID-58190037">HTMLElement</a>|Array
*/
_oTrigger: null,


/**
* @property _bCancelled
* @description Boolean indicating if the display of the context menu should 
* be cancelled.
* @default false
* @private
* @type Boolean
*/
_bCancelled: false,



// Public properties


/**
* @property contextEventTarget
* @description Object reference for the HTML element that was the target of the
* "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of 
* the context menu.
* @default null
* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
* html.html#ID-58190037">HTMLElement</a>
*/
contextEventTarget: null,



// Events


/**
* @event triggerContextMenuEvent
* @description Custom Event wrapper for the "contextmenu" DOM event 
* ("mousedown" for Opera) fired by the element(s) that trigger the display of 
* the context menu.
*/
triggerContextMenuEvent: null,



/**
* @method init
* @description The ContextMenu class's initialization method. This method is 
* automatically called by the constructor, and sets up all DOM references for 
* pre-existing markup, and creates required markup if it is not already present.
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;div&#62;</code> element of the context menu.
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;select&#62;</code> element to be used as the data source for 
* the context menu.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
* html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the 
* <code>&#60;div&#62;</code> element of the context menu.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
* html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying 
* the <code>&#60;select&#62;</code> element to be used as the data source for 
* the context menu.
* @param {Object} p_oConfig Optional. Object literal specifying the 
* configuration for the context menu. See configuration class documentation 
* for more details.
*/
init: function(p_oElement, p_oConfig) {


    // Call the init of the superclass (YAHOO.widget.Menu)

    ContextMenu.superclass.init.call(this, p_oElement);


    this.beforeInitEvent.fire(ContextMenu);


    if(p_oConfig) {

        this.cfg.applyConfig(p_oConfig, true);

    }
    
    
    this.initEvent.fire(ContextMenu);
    
},


/**
* @method initEvents
* @description Initializes the custom events for the context menu.
*/
initEvents: function() {

	ContextMenu.superclass.initEvents.call(this);

    // Create custom events

    this.triggerContextMenuEvent = 
        this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);

    this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;

},


/**
* @method cancel
* @description Cancels the display of the context menu.
*/
cancel: function() {

    this._bCancelled = true;

},



// Private methods


/**
* @method _removeEventHandlers
* @description Removes all of the DOM event handlers from the HTML element(s) 
* whose "context menu" event ("click" for Opera) trigger the display of 
* the context menu.
* @private
*/
_removeEventHandlers: function() {

    var oTrigger = this._oTrigger;


    // Remove the event handlers from the trigger(s)

    if (oTrigger) {

        Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, 
            this._onTriggerContextMenu);    
        
        if(YAHOO.env.ua.opera) {
        
            Event.removeListener(oTrigger, EVENT_TYPES.CLICK, 
                this._onTriggerClick);
    
        }

    }

},



// Private event handlers



/**
* @method _onTriggerClick
* @description "click" event handler for the HTML element(s) identified as the 
* "trigger" for the context menu.  Used to cancel default behaviors in Opera.
* @private
* @param {Event} p_oEvent Object representing the DOM event object passed back 
* by the event utility (YAHOO.util.Event).
* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
* menu that is handling the event.
*/
_onTriggerClick: function(p_oEvent, p_oMenu) {

    if(p_oEvent.ctrlKey) {
    
        Event.stopEvent(p_oEvent);

    }
    
},


/**
* @method _onTriggerContextMenu
* @description "contextmenu" event handler ("mousedown" for Opera) for the HTML 
* element(s) that trigger the display of the context menu.
* @private
* @param {Event} p_oEvent Object representing the DOM event object passed back 
* by the event utility (YAHOO.util.Event).
* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
* menu that is handling the event.
*/
_onTriggerContextMenu: function(p_oEvent, p_oMenu) {

    if (p_oEvent.type == "mousedown" && !p_oEvent.ctrlKey) {

        return;

    }


    var aXY;


    /*
        Prevent the browser's default context menu from appearing and 
        stop the propagation of the "contextmenu" event so that 
        other ContextMenu instances are not displayed.
    */

    Event.stopEvent(p_oEvent);


    this.contextEventTarget = Event.getTarget(p_oEvent);

    this.triggerContextMenuEvent.fire(p_oEvent);


    // Hide any other Menu instances that might be visible

    YAHOO.widget.MenuManager.hideVisible();
    


    if(!this._bCancelled) {

        // Position and display the context menu

        aXY = Event.getXY(p_oEvent);


        if (!YAHOO.util.Dom.inDocument(this.element)) {

            this.beforeShowEvent.subscribe(position, aXY);

        }
        else {

            this.cfg.setProperty("xy", aXY);
        
        }


        this.show();

    }

    this._bCancelled = false;

},



// Public methods


/**
* @method toString
* @description Returns a string representing the context menu.
* @return {String}
*/
toString: function() {

    var sReturnVal = "ContextMenu",
        sId = this.id;

    if(sId) {

        sReturnVal += (" " + sId);
    
    }

    return sReturnVal;

},


/**
* @method initDefaultConfig
* @description Initializes the class's configurable properties which can be 
* changed using the context menu's Config object ("cfg").
*/
initDefaultConfig: function() {

    ContextMenu.superclass.initDefaultConfig.call(this);

    /**
    * @config trigger
    * @description The HTML element(s) whose "contextmenu" event ("mousedown" 
    * for Opera) trigger the display of the context menu.  Can be a string 
    * representing the id attribute of the HTML element, an object reference 
    * for the HTML element, or an array of strings or HTML element references.
    * @default null
    * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
    * level-one-html.html#ID-58190037">HTMLElement</a>|Array
    */
    this.cfg.addProperty(DEFAULT_CONFIG.TRIGGER.key, 
        {
            handler: this.configTrigger, 
            suppressEvent: DEFAULT_CONFIG.TRIGGER.suppressEvent 
        }
    );

},


/**
* @method destroy
* @description Removes the context menu's <code>&#60;div&#62;</code> element 
* (and accompanying child nodes) from the document.
*/
destroy: function() {

    // Remove the DOM event handlers from the current trigger(s)

    this._removeEventHandlers();


    // Continue with the superclass implementation of this method

    ContextMenu.superclass.destroy.call(this);

},



// Public event handlers for configuration properties


/**
* @method configTrigger
* @description Event handler for when the value of the "trigger" configuration 
* property changes. 
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context 
* menu that fired the event.
*/
configTrigger: function(p_sType, p_aArgs, p_oMenu) {
    
    var oTrigger = p_aArgs[0];

    if(oTrigger) {

        /*
            If there is a current "trigger" - remove the event handlers 
            from that element(s) before assigning new ones
        */

        if(this._oTrigger) {
        
            this._removeEventHandlers();

        }

        this._oTrigger = oTrigger;


        /*
            Listen for the "mousedown" event in Opera b/c it does not 
            support the "contextmenu" event
        */ 
  
        Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, 
            this._onTriggerContextMenu, this, true);


        /*
            Assign a "click" event handler to the trigger element(s) for
            Opera to prevent default browser behaviors.
        */

        if(YAHOO.env.ua.opera) {
        
            Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, 
                this, true);

        }

    }
    else {
   
        this._removeEventHandlers();
    
    }
    
}

}); // END YAHOO.lang.extend

}());



/**
* Creates an item for a context menu.
* 
* @param {String} p_oObject String specifying the text of the context menu item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
* <code>&#60;li&#62;</code> element of the context menu item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
* specifying the <code>&#60;optgroup&#62;</code> element of the context 
* menu item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
* the <code>&#60;option&#62;</code> element of the context menu item.
* @param {Object} p_oConfig Optional. Object literal specifying the 
* configuration for the context menu item. See configuration class 
* documentation for more details.
* @class ContextMenuItem
* @constructor
* @extends YAHOO.widget.MenuItem
* @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
* are of type YAHOO.widget.MenuItem.
*/
YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
(function () {


/**
* Horizontal collection of items, each of which can contain a submenu.
* 
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;div&#62;</code> element of the menu bar.
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;select&#62;</code> element to be used as the data source for the 
* menu bar.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying 
* the <code>&#60;div&#62;</code> element of the menu bar.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object 
* specifying the <code>&#60;select&#62;</code> element to be used as the data 
* source for the menu bar.
* @param {Object} p_oConfig Optional. Object literal specifying the 
* configuration for the menu bar. See configuration class documentation for
* more details.
* @class MenuBar
* @constructor
* @extends YAHOO.widget.Menu
* @namespace YAHOO.widget
*/
YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {

    YAHOO.widget.MenuBar.superclass.constructor.call(this, 
        p_oElement, p_oConfig);

};


/**
* @method checkPosition
* @description Checks to make sure that the value of the "position" property 
* is one of the supported strings. Returns true if the position is supported.
* @private
* @param {Object} p_sPosition String specifying the position of the menu.
* @return {Boolean}
*/
function checkPosition(p_sPosition) {

    if (typeof p_sPosition == "string") {

        return ("dynamic,static".indexOf((p_sPosition.toLowerCase())) != -1);

    }

}


var Event = YAHOO.util.Event,
    MenuBar = YAHOO.widget.MenuBar,

    /**
    * Constant representing the MenuBar's configuration properties
    * @property DEFAULT_CONFIG
    * @private
    * @final
    * @type Object
    */
    DEFAULT_CONFIG = {
    
        "POSITION": { 
            key: "position", 
            value: "static", 
            validator: checkPosition, 
            supercedes: ["visible"] 
        }, 
    
        "SUBMENU_ALIGNMENT": { 
            key: "submenualignment", 
            value: ["tl","bl"],
            suppressEvent: true 
        },
    
        "AUTO_SUBMENU_DISPLAY": { 
            key: "autosubmenudisplay", 
            value: false, 
            validator: YAHOO.lang.isBoolean,
            suppressEvent: true
        }
    
    };



YAHOO.lang.extend(MenuBar, YAHOO.widget.Menu, {

/**
* @method init
* @description The MenuBar class's initialization method. This method is 
* automatically called by the constructor, and sets up all DOM references for 
* pre-existing markup, and creates required markup if it is not already present.
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;div&#62;</code> element of the menu bar.
* @param {String} p_oElement String specifying the id attribute of the 
* <code>&#60;select&#62;</code> element to be used as the data source for the 
* menu bar.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying 
* the <code>&#60;div&#62;</code> element of the menu bar.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object 
* specifying the <code>&#60;select&#62;</code> element to be used as the data 
* source for the menu bar.
* @param {Object} p_oConfig Optional. Object literal specifying the 
* configuration for the menu bar. See configuration class documentation for
* more details.
*/
init: function(p_oElement, p_oConfig) {

    if(!this.ITEM_TYPE) {

        this.ITEM_TYPE = YAHOO.widget.MenuBarItem;

    }


    // Call the init of the superclass (YAHOO.widget.Menu)

    MenuBar.superclass.init.call(this, p_oElement);


    this.beforeInitEvent.fire(MenuBar);


    if(p_oConfig) {

        this.cfg.applyConfig(p_oConfig, true);

    }

    this.initEvent.fire(MenuBar);

},



// Constants


/**
* @property CSS_CLASS_NAME
* @description String representing the CSS class(es) to be applied to the menu 
* bar's <code>&#60;div&#62;</code> element.
* @default "yuimenubar"
* @final
* @type String
*/
CSS_CLASS_NAME: "yuimenubar",



// Protected event handlers


/**
* @method _onKeyDown
* @description "keydown" Custom Event handler for the menu bar.
* @private
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar 
* that fired the event.
*/
_onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {

    var oEvent = p_aArgs[0],
        oItem = p_aArgs[1],
        oSubmenu,
        oItemCfg,
        oNextItem;


    if(oItem && !oItem.cfg.getProperty("disabled")) {

        oItemCfg = oItem.cfg;

        switch(oEvent.keyCode) {
    
            case 37:    // Left arrow
            case 39:    // Right arrow
    
                if(oItem == this.activeItem && 
                    !oItemCfg.getProperty("selected")) {
    
                    oItemCfg.setProperty("selected", true);
    
                }
                else {
    
                    oNextItem = (oEvent.keyCode == 37) ? 
                        oItem.getPreviousEnabledSibling() : 
                        oItem.getNextEnabledSibling();
            
                    if(oNextItem) {
    
                        this.clearActiveItem();
    
                        oNextItem.cfg.setProperty("selected", true);
    
    
                        if(this.cfg.getProperty("autosubmenudisplay")) {
                        
                            oSubmenu = oNextItem.cfg.getProperty("submenu");
                            
                            if(oSubmenu) {
                        
                                oSubmenu.show();
                            
                            }
                
                        }           
    
                        oNextItem.focus();
    
                    }
    
                }
    
                Event.preventDefault(oEvent);
    
            break;
    
            case 40:    // Down arrow
    
                if(this.activeItem != oItem) {
    
                    this.clearActiveItem();
    
                    oItemCfg.setProperty("selected", true);
                    oItem.focus();
                
                }
    
                oSubmenu = oItemCfg.getProperty("submenu");
    
                if(oSubmenu) {
    
                    if(oSubmenu.cfg.getProperty("visible")) {
    
                        oSubmenu.setInitialSelection();
                        oSubmenu.setInitialFocus();
                    
                    }
                    else {
    
                        oSubmenu.show();
                    
                    }
    
                }
    
                Event.preventDefault(oEvent);
    
            break;
    
        }

    }


    if(oEvent.keyCode == 27 && this.activeItem) { // Esc key

        oSubmenu = this.activeItem.cfg.getProperty("submenu");

        if(oSubmenu && oSubmenu.cfg.getProperty("visible")) {
        
            oSubmenu.hide();
            this.activeItem.focus();
        
        }
        else {

            this.activeItem.cfg.setProperty("selected", false);
            this.activeItem.blur();
    
        }

        Event.preventDefault(oEvent);
    
    }

},


/**
* @method _onClick
* @description "click" event handler for the menu bar.
* @protected
* @param {String} p_sType String representing the name of the event that 
* was fired.
* @param {Array} p_aArgs Array of arguments sent when the event was fired.
* @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar 
* that fired the event.
*/
_onClick: function(p_sType, p_aArgs, p_oMenuBar) {

    MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);

    var oItem = p_aArgs[1],
        oEvent,
        oTarget,
        oActiveItem,
        oConfig,
        oSubmenu;
    

    if(oItem && !oItem.cfg.getProperty("disabled")) {

        oEvent = p_aArgs[0];
        oTarget = Event.getTarget(oEvent);
        oActiveItem = this.activeItem;
        oConfig = this.cfg;


        // Hide any other submenus that might be visible
    
        if(oActiveItem && oActiveItem != oItem) {
    
            this.clearActiveItem();
    
        }

    
        oItem.cfg.setProperty("selected", true);
    

        // Show the submenu for the item
    
        oSubmenu = oItem.cfg.getProperty("submenu");


        if(oSubmenu) {
        
            if(oSubmenu.cfg.getProperty("visible")) {
            
                oSubmenu.hide();
            
            }
            else {
            
                oSubmenu.show();                    
            
            }
        
        }
    
    }

},



// Public methods


/**
* @method toString
* @description Returns a string representing the menu bar.
* @return {String}
*/
toString: function() {

    var sReturnVal = "MenuBar",
        sId = this.id;

    if(sId) {

        sReturnVal += (" " + sId);
    
    }

    return sReturnVal;

},


/**
* @description Initializes the class's configurable properties which can be
* changed using the menu bar's Config object ("cfg").
* @method initDefaultConfig
*/
initDefaultConfig: function() {

    MenuBar.superclass.initDefaultConfig.call(this);

    var oConfig = this.cfg;

	// Add configuration properties


    /*
        Set the default value for the "position" configuration property
        to "static" by re-adding the property.
    */


    /**
    * @config position
    * @description String indicating how a menu bar should be positioned on the 
    * screen.  Possible values are "static" and "dynamic."  Static menu bars 
    * are visible by default and reside in the normal flow of the document 
    * (CSS position: static).  Dynamic menu bars are hidden by default, reside
    * out of the normal flow of the document (CSS position: absolute), and can 
    * overlay other elements on the screen.
    * @default static
    * @type String
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.POSITION.key, 
        {
            handler: this.configPosition, 
            value: DEFAULT_CONFIG.POSITION.value, 
            validator: DEFAULT_CONFIG.POSITION.validator,
            supercedes: DEFAULT_CONFIG.POSITION.supercedes
        }
    );


    /*
        Set the default value for the "submenualignment" configuration property
        to ["tl","bl"] by re-adding the property.
    */

    /**
    * @config submenualignment
    * @description Array defining how submenus should be aligned to their 
    * parent menu bar item. The format is: [itemCorner, submenuCorner].
    * @default ["tl","bl"]
    * @type Array
    */
    oConfig.addProperty(
        DEFAULT_CONFIG.SUBMENU_ALIGNMENT.key, 
        {
            value: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.value,
            suppressEvent: DEFAULT_CONFIG.SUBMENU_ALIGNMENT.suppressEvent
        }
    );


    /*
        Change the default value for the "autosubmenudisplay" configuration 
        property to "false" by re-adding the property.
    */

    /**
    * @config autosubmenudisplay
    * @description Boolean indicating if submenus are automatically made 
    * visible when the user mouses over the menu bar's items.
    * @default false
    * @type Boolean
    */
	oConfig.addProperty(
	   DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.key, 
	   {
	       value: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.value, 
	       validator: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.validator,
	       suppressEvent: DEFAULT_CONFIG.AUTO_SUBMENU_DISPLAY.suppressEvent
       } 
    );

}
 
}); // END YAHOO.lang.extend

}());



/**
* Creates an item for a menu bar.
* 
* @param {String} p_oObject String specifying the text of the menu bar item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
* <code>&#60;li&#62;</code> element of the menu bar item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
* specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
* the <code>&#60;option&#62;</code> element of the menu bar item.
* @param {Object} p_oConfig Optional. Object literal specifying the 
* configuration for the menu bar item. See configuration class documentation 
* for more details.
* @class MenuBarItem
* @constructor
* @extends YAHOO.widget.MenuItem
*/
YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {

    YAHOO.widget.MenuBarItem.superclass.constructor.call(this, 
        p_oObject, p_oConfig);

};

YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {



/**
* @method init
* @description The MenuBarItem class's initialization method. This method is 
* automatically called by the constructor, and sets up all DOM references for 
* pre-existing markup, and creates required markup if it is not already present.
* @param {String} p_oObject String specifying the text of the menu bar item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the 
* <code>&#60;li&#62;</code> element of the menu bar item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object 
* specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
* @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
* one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying 
* the <code>&#60;option&#62;</code> element of the menu bar item.
* @param {Object} p_oConfig Optional. Object literal specifying the 
* configuration for the menu bar item. See configuration class documentation 
* for more details.
*/
init: function(p_oObject, p_oConfig) {

    if(!this.SUBMENU_TYPE) {

        this.SUBMENU_TYPE = YAHOO.widget.Menu;

    }


    /* 
        Call the init of the superclass (YAHOO.widget.MenuItem)
        Note: We don't pass the user config in here yet 
        because we only want it executed once, at the lowest 
        subclass level.
    */ 

    YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);  


    var oConfig = this.cfg;

    if(p_oConfig) {

        oConfig.applyConfig(p_oConfig, true);

    }

    oConfig.fireQueue();

},



// Constants


/**
* @property CSS_CLASS_NAME
* @description String representing the CSS class(es) to be applied to the 
* <code>&#60;li&#62;</code> element of the menu bar item.
* @default "yuimenubaritem"
* @final
* @type String
*/
CSS_CLASS_NAME: "yuimenubaritem",


/**
* @property CSS_LABEL_CLASS_NAME
* @description String representing the CSS class(es) to be applied to the 
* menu bar item's <code>&#60;a&#62;</code> element.
* @default "yuimenubaritemlabel"
* @final
* @type String
*/
CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",



// Public methods


/**
* @method toString
* @description Returns a string representing the menu bar item.
* @return {String}
*/
toString: function() {

    var sReturnVal = "MenuBarItem";

    if(this.cfg && this.cfg.getProperty("text")) {

        sReturnVal += (": " + this.cfg.getProperty("text"));

    }

    return sReturnVal;

}
    
}); // END YAHOO.lang.extend
YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.5.2", build: "1076"});
/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.5.2
*/
/**
* @module button
* @description <p>The Button Control enables the creation of rich, graphical 
* buttons that function like traditional HTML form buttons.  <em>Unlike</em> 
* tradition HTML form buttons, buttons created with the Button Control can have 
* a label that is different from its value.  With the inclusion of the optional 
* <a href="module_menu.html">Menu Control</a>, the Button Control can also be
* used to create menu buttons and split buttons, controls that are not 
* available natively in HTML.  The Button Control can also be thought of as a 
* way to create more visually engaging implementations of the browser's 
* default radio-button and check-box controls.</p>
* <p>The Button Control supports the following types:</p>
* <dl>
* <dt>push</dt>
* <dd>Basic push button that can execute a user-specified command when 
* pressed.</dd>
* <dt>link</dt>
* <dd>Navigates to a specified url when pressed.</dd>
* <dt>submit</dt>
* <dd>Submits the parent form when pressed.</dd>
* <dt>reset</dt>
* <dd>Resets the parent form when pressed.</dd>
* <dt>checkbox</dt>
* <dd>Maintains a "checked" state that can be toggled on and off.</dd>
* <dt>radio</dt>
* <dd>Maintains a "checked" state that can be toggled on and off.  Use with 
* the ButtonGroup class to create a set of controls that are mutually 
* exclusive; checking one button in the set will uncheck all others in 
* the group.</dd>
* <dt>menu</dt>
* <dd>When pressed will show/hide a menu.</dd>
* <dt>split</dt>
* <dd>Can execute a user-specified command or display a menu when pressed.</dd>
* </dl>
* @title Button
* @namespace YAHOO.widget
* @requires yahoo, dom, element, event
* @optional container, menu
*/


(function () {


    /**
    * The Button class creates a rich, graphical button.
    * @param {String} p_oElement String specifying the id attribute of the 
    * <code>&#60;input&#62;</code>, <code>&#60;button&#62;</code>,
    * <code>&#60;a&#62;</code>, or <code>&#60;span&#62;</code> element to 
    * be used to create the button.
    * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://www.w3.org
    * /TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-34812697">
    * HTMLButtonElement</a>|<a href="
    * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#
    * ID-33759296">HTMLElement</a>} p_oElement Object reference for the 
    * <code>&#60;input&#62;</code>, <code>&#60;button&#62;</code>, 
    * <code>&#60;a&#62;</code>, or <code>&#60;span&#62;</code> element to be 
    * used to create the button.
    * @param {Object} p_oElement Object literal specifying a set of   
    * configuration attributes used to create the button.
    * @param {Object} p_oAttributes Optional. Object literal specifying a set  
    * of configuration attributes used to create the button.
    * @namespace YAHOO.widget
    * @class Button
    * @constructor
    * @extends YAHOO.util.Element
    */



    // Shorthard for utilities

    var Dom = YAHOO.util.Dom,
        Event = YAHOO.util.Event,
        Lang = YAHOO.lang,
        UA = YAHOO.env.ua,
        Overlay = YAHOO.widget.Overlay,
        Menu = YAHOO.widget.Menu,
    
    
        // Private member variables
    
        m_oButtons = {},    // Collection of all Button instances
        m_oOverlayManager = null,   // YAHOO.widget.OverlayManager instance
        m_oSubmitTrigger = null,    // The button that submitted the form 
        m_oFocusedButton = null;    // The button that has focus



    // Private methods

    
    
    /**
    * @method createInputElement
    * @description Creates an <code>&#60;input&#62;</code> element of the 
    * specified type.
    * @private
    * @param {String} p_sType String specifying the type of 
    * <code>&#60;input&#62;</code> element to create.
    * @param {String} p_sName String specifying the name of 
    * <code>&#60;input&#62;</code> element to create.
    * @param {String} p_sValue String specifying the value of 
    * <code>&#60;input&#62;</code> element to create.
    * @param {String} p_bChecked Boolean specifying if the  
    * <code>&#60;input&#62;</code> element is to be checked.
    * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-6043025">HTMLInputElement</a>}
    */
    function createInputElement(p_sType, p_sName, p_sValue, p_bChecked) {
    
        var oInput,
            sInput;
    
        if (Lang.isString(p_sType) && Lang.isString(p_sName)) {
        
            if (UA.ie) {
        
                /*
                    For IE it is necessary to create the element with the 
                    "type," "name," "value," and "checked" properties set all 
                    at once.
                */
            
                sInput = "<input type=\"" + p_sType + "\" name=\"" + 
                    p_sName + "\"";
        
                if (p_bChecked) {
        
                    sInput += " checked";
                
                }
                
                sInput += ">";
        
                oInput = document.createElement(sInput);
        
            }
            else {
            
                oInput = document.createElement("input");
                oInput.name = p_sName;
                oInput.type = p_sType;
        
                if (p_bChecked) {
        
                    oInput.checked = true;
                
                }
        
            }
        
            oInput.value = p_sValue;
            
            return oInput;
        
        }
    
    }
    
    
    /**
    * @method setAttributesFromSrcElement
    * @description Gets the values for all the attributes of the source element 
    * (either <code>&#60;input&#62;</code> or <code>&#60;a&#62;</code>) that 
    * map to Button configuration attributes and sets them into a collection 
    * that is passed to the Button constructor.
    * @private
    * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://www.w3.org/
    * TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-
    * 48250443">HTMLAnchorElement</a>} p_oElement Object reference to the HTML 
    * element (either <code>&#60;input&#62;</code> or <code>&#60;span&#62;
    * </code>) used to create the button.
    * @param {Object} p_oAttributes Object reference for the collection of 
    * configuration attributes used to create the button.
    */
    function setAttributesFromSrcElement(p_oElement, p_oAttributes) {
    
        var sSrcElementNodeName = p_oElement.nodeName.toUpperCase(),
            me = this,
            oAttribute,
            oRootNode,
            sText;
            
    
        /**
        * @method setAttributeFromDOMAttribute
        * @description Gets the value of the specified DOM attribute and sets it 
        * into the collection of configuration attributes used to configure 
        * the button.
        * @private
        * @param {String} p_sAttribute String representing the name of the 
        * attribute to retrieve from the DOM element.
        */
        function setAttributeFromDOMAttribute(p_sAttribute) {
    
            if (!(p_sAttribute in p_oAttributes)) {
    
                /*
                    Need to use "getAttributeNode" instead of "getAttribute" 
                    because using "getAttribute," IE will return the innerText 
                    of a <code>&#60;button&#62;</code> for the value attribute  
                    rather than the value of the "value" attribute.
                */
        
                oAttribute = p_oElement.getAttributeNode(p_sAttribute);
        
    
                if (oAttribute && ("value" in oAttribute)) {
    
    
                    p_oAttributes[p_sAttribute] = oAttribute.value;
    
                }
    
            }
        
        }
    
    
        /**
        * @method setFormElementProperties
        * @description Gets the value of the attributes from the form element  
        * and sets them into the collection of configuration attributes used to 
        * configure the button.
        * @private
        */
        function setFormElementProperties() {
    
            setAttributeFromDOMAttribute("type");
    
            if (p_oAttributes.type == "button") {
            
                p_oAttributes.type = "push";
            
            }
    
            if (!("disabled" in p_oAttributes)) {
    
                p_oAttributes.disabled = p_oElement.disabled;
    
            }
    
            setAttributeFromDOMAttribute("name");
            setAttributeFromDOMAttribute("value");
            setAttributeFromDOMAttribute("title");
    
        }

    
        switch (sSrcElementNodeName) {
        
        case "A":
            
            p_oAttributes.type = "link";
            
            setAttributeFromDOMAttribute("href");
            setAttributeFromDOMAttribute("target");
        
            break;
    
        case "INPUT":

            setFormElementProperties();

            if (!("checked" in p_oAttributes)) {
    
                p_oAttributes.checked = p_oElement.checked;
    
            }

            break;

        case "BUTTON":

            setFormElementProperties();

            oRootNode = p_oElement.parentNode.parentNode;

            if (Dom.hasClass(oRootNode, this.CSS_CLASS_NAME + "-checked")) {
            
                p_oAttributes.checked = true;
            
            }

            if (Dom.hasClass(oRootNode, this.CSS_CLASS_NAME + "-disabled")) {

                p_oAttributes.disabled = true;
            
            }

            p_oElement.removeAttribute("value");

            p_oElement.setAttribute("type", "button");

            break;
        
        }

        p_oElement.removeAttribute("id");
        p_oElement.removeAttribute("name");
        
        if (!("tabindex" in p_oAttributes)) {

            p_oAttributes.tabindex = p_oElement.tabIndex;

        }
    
        if (!("label" in p_oAttributes)) {
    
            // Set the "label" property
        
            sText = sSrcElementNodeName == "INPUT" ? 
                            p_oElement.value : p_oElement.innerHTML;
        
    
            if (sText && sText.length > 0) {
                
                p_oAttributes.label = sText;
                
            } 
    
        }
    
    }
    
    
    /**
    * @method initConfig
    * @description Initializes the set of configuration attributes that are 
    * used to instantiate the button.
    * @private
    * @param {Object} Object representing the button's set of 
    * configuration attributes.
    */
    function initConfig(p_oConfig) {
    
        var oAttributes = p_oConfig.attributes,
            oSrcElement = oAttributes.srcelement,
            sSrcElementNodeName = oSrcElement.nodeName.toUpperCase(),
            me = this;
    
    
        if (sSrcElementNodeName == this.NODE_NAME) {
    
            p_oConfig.element = oSrcElement;
            p_oConfig.id = oSrcElement.id;

            Dom.getElementsBy(function (p_oElement) {
            
                switch (p_oElement.nodeName.toUpperCase()) {
                
                case "BUTTON":
                case "A":
                case "INPUT":

                    setAttributesFromSrcElement.call(me, p_oElement, 
                        oAttributes);

                    break;                        
                
                }
            
            }, "*", oSrcElement);
        
        }
        else {
    
            switch (sSrcElementNodeName) {

            case "BUTTON":
            case "A":
            case "INPUT":

                setAttributesFromSrcElement.call(this, oSrcElement, 
                    oAttributes);

                break;

            }
        
        }
    
    }



    //  Constructor

    YAHOO.widget.Button = function (p_oElement, p_oAttributes) {
    
		if (!Overlay && YAHOO.widget.Overlay) {
		
			Overlay = YAHOO.widget.Overlay;
		
		}


		if (!Menu && YAHOO.widget.Menu) {
		
			Menu = YAHOO.widget.Menu;
		
		}


        var fnSuperClass = YAHOO.widget.Button.superclass.constructor,
            oConfig,
            oElement;
    
        if (arguments.length == 1 && !Lang.isString(p_oElement) && 
            !p_oElement.nodeName) {
    
            if (!p_oElement.id) {
    
                p_oElement.id = Dom.generateId();
    
    
            }
    
    
    
            fnSuperClass.call(this, 
                (this.createButtonElement(p_oElement.type)),
                p_oElement);
    
        }
        else {
    
            oConfig = { element: null, attributes: (p_oAttributes || {}) };
    
    
            if (Lang.isString(p_oElement)) {
    
                oElement = Dom.get(p_oElement);
    
                if (oElement) {

                    if (!oConfig.attributes.id) {
                    
                        oConfig.attributes.id = p_oElement;
                    
                    }
    
                
                
                
                    oConfig.attributes.srcelement = oElement;
                
                    initConfig.call(this, oConfig);
                
                
                    if (!oConfig.element) {
                
                
                        oConfig.element = 
                            this.createButtonElement(oConfig.attributes.type);
                
                    }
                
                    fnSuperClass.call(this, oConfig.element, 
                        oConfig.attributes);
    
                }
    
            }
            else if (p_oElement.nodeName) {
    
                if (!oConfig.attributes.id) {
    
                    if (p_oElement.id) {
        
                        oConfig.attributes.id = p_oElement.id;
                    
                    }
                    else {
        
                        oConfig.attributes.id = Dom.generateId();
        
        
                    }
    
                }
    
    
    
    
    
                oConfig.attributes.srcelement = p_oElement;
        
                initConfig.call(this, oConfig);
        
        
                if (!oConfig.element) {
    
            
                    oConfig.element = 
                        this.createButtonElement(oConfig.attributes.type);
            
                }
            
                fnSuperClass.call(this, oConfig.element, oConfig.attributes);
            
            }
    
        }
    
    };



    YAHOO.extend(YAHOO.widget.Button, YAHOO.util.Element, {
    
    
        // Protected properties
        
        
        /** 
        * @property _button
        * @description Object reference to the button's internal 
        * <code>&#60;a&#62;</code> or <code>&#60;button&#62;</code> element.
        * @default null
        * @protected
        * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-48250443">HTMLAnchorElement</a>|<a href="
        * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html
        * #ID-34812697">HTMLButtonElement</a>
        */
        _button: null,
        
        
        /** 
        * @property _menu
        * @description Object reference to the button's menu.
        * @default null
        * @protected
        * @type {<a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>|
        * <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>}
        */
        _menu: null,
        
        
        /** 
        * @property _hiddenFields
        * @description Object reference to the <code>&#60;input&#62;</code>  
        * element, or array of HTML form elements used to represent the button
        *  when its parent form is submitted.
        * @default null
        * @protected
        * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array
        */
        _hiddenFields: null,
        
        
        /** 
        * @property _onclickAttributeValue
        * @description Object reference to the button's current value for the 
        * "onclick" configuration attribute.
        * @default null
        * @protected
        * @type Object
        */
        _onclickAttributeValue: null,
        
        
        /** 
        * @property _activationKeyPressed
        * @description Boolean indicating if the key(s) that toggle the button's 
        * "active" state have been pressed.
        * @default false
        * @protected
        * @type Boolean
        */
        _activationKeyPressed: false,
        
        
        /** 
        * @property _activationButtonPressed
        * @description Boolean indicating if the mouse button that toggles 
        * the button's "active" state has been pressed.
        * @default false
        * @protected
        * @type Boolean
        */
        _activationButtonPressed: false,
        
        
        /** 
        * @property _hasKeyEventHandlers
        * @description Boolean indicating if the button's "blur", "keydown" and 
        * "keyup" event handlers are assigned
        * @default false
        * @protected
        * @type Boolean
        */
        _hasKeyEventHandlers: false,
        
        
        /** 
        * @property _hasMouseEventHandlers
        * @description Boolean indicating if the button's "mouseout," 
        * "mousedown," and "mouseup" event handlers are assigned
        * @default false
        * @protected
        * @type Boolean
        */
        _hasMouseEventHandlers: false,
        
        
        
        // Constants
        
        
        /**
        * @property NODE_NAME
        * @description The name of the node to be used for the button's 
        * root element.
        * @default "SPAN"
        * @final
        * @type String
        */
        NODE_NAME: "SPAN",
        
        
        /**
        * @property CHECK_ACTIVATION_KEYS
        * @description Array of numbers representing keys that (when pressed) 
        * toggle the button's "checked" attribute.
        * @default [32]
        * @final
        * @type Array
        */
        CHECK_ACTIVATION_KEYS: [32],
        
        
        /**
        * @property ACTIVATION_KEYS
        * @description Array of numbers representing keys that (when presed) 
        * toggle the button's "active" state.
        * @default [13, 32]
        * @final
        * @type Array
        */
        ACTIVATION_KEYS: [13, 32],
        
        
        /**
        * @property OPTION_AREA_WIDTH
        * @description Width (in pixels) of the area of a split button that  
        * when pressed will display a menu.
        * @default 20
        * @final
        * @type Number
        */
        OPTION_AREA_WIDTH: 20,
        
        
        /**
        * @property CSS_CLASS_NAME
        * @description String representing the CSS class(es) to be applied to  
        * the button's root element.
        * @default "yui-button"
        * @final
        * @type String
        */
        CSS_CLASS_NAME: "yui-button",
        
        
        /**
        * @property RADIO_DEFAULT_TITLE
        * @description String representing the default title applied to buttons 
        * of type "radio." 
        * @default "Unchecked.  Click to check."
        * @final
        * @type String
        */
        RADIO_DEFAULT_TITLE: "Unchecked.  Click to check.",
        
        
        /**
        * @property RADIO_CHECKED_TITLE
        * @description String representing the title applied to buttons of 
        * type "radio" when checked.
        * @default "Checked.  Click another button to uncheck"
        * @final
        * @type String
        */
        RADIO_CHECKED_TITLE: "Checked.  Click another button to uncheck",
        
        
        /**
        * @property CHECKBOX_DEFAULT_TITLE
        * @description String representing the default title applied to 
        * buttons of type "checkbox." 
        * @default "Unchecked.  Click to check."
        * @final
        * @type String
        */
        CHECKBOX_DEFAULT_TITLE: "Unchecked.  Click to check.",
        
        
        /**
        * @property CHECKBOX_CHECKED_TITLE
        * @description String representing the title applied to buttons of type 
        * "checkbox" when checked.
        * @default "Checked.  Click to uncheck."
        * @final
        * @type String
        */
        CHECKBOX_CHECKED_TITLE: "Checked.  Click to uncheck.",
        
        
        /**
        * @property MENUBUTTON_DEFAULT_TITLE
        * @description String representing the default title applied to 
        * buttons of type "menu." 
        * @default "Menu collapsed.  Click to expand."
        * @final
        * @type String
        */
        MENUBUTTON_DEFAULT_TITLE: "Menu collapsed.  Click to expand.",
        
        
        /**
        * @property MENUBUTTON_MENU_VISIBLE_TITLE
        * @description String representing the title applied to buttons of type 
        * "menu" when the button's menu is visible. 
        * @default "Menu expanded.  Click or press Esc to collapse."
        * @final
        * @type String
        */
        MENUBUTTON_MENU_VISIBLE_TITLE: 
            "Menu expanded.  Click or press Esc to collapse.",
        
        
        /**
        * @property SPLITBUTTON_DEFAULT_TITLE
        * @description  String representing the default title applied to 
        * buttons of type "split." 
        * @default "Menu collapsed.  Click inside option region or press 
        * Ctrl + Shift + M to show the menu."
        * @final
        * @type String
        */
        SPLITBUTTON_DEFAULT_TITLE: ("Menu collapsed.  Click inside option " + 
            "region or press Ctrl + Shift + M to show the menu."),
        
        
        /**
        * @property SPLITBUTTON_OPTION_VISIBLE_TITLE
        * @description String representing the title applied to buttons of type 
        * "split" when the button's menu is visible. 
        * @default "Menu expanded.  Press Esc or Ctrl + Shift + M to hide 
        * the menu."
        * @final
        * @type String
        */
        SPLITBUTTON_OPTION_VISIBLE_TITLE: 
            "Menu expanded.  Press Esc or Ctrl + Shift + M to hide the menu.",
        
        
        /**
        * @property SUBMIT_TITLE
        * @description String representing the title applied to buttons of 
        * type "submit." 
        * @default "Click to submit form."
        * @final
        * @type String
        */
        SUBMIT_TITLE: "Click to submit form.",
        
        
        
        // Protected attribute setter methods
        
        
        /**
        * @method _setType
        * @description Sets the value of the button's "type" attribute.
        * @protected
        * @param {String} p_sType String indicating the value for the button's 
        * "type" attribute.
        */
        _setType: function (p_sType) {
        
            if (p_sType == "split") {
        
                this.on("option", this._onOption);
        
            }
        
        },
        
        
        /**
        * @method _setLabel
        * @description Sets the value of the button's "label" attribute.
        * @protected
        * @param {String} p_sLabel String indicating the value for the button's 
        * "label" attribute.
        */
        _setLabel: function (p_sLabel) {

            this._button.innerHTML = p_sLabel;

            
            /*
                Remove and add the default class name from the root element
                for Gecko to ensure that the button shrinkwraps to the label.
                Without this the button will not be rendered at the correct 
                width when the label changes.  The most likely cause for this 
                bug is button's use of the Gecko-specific CSS display type of 
                "-moz-inline-box" to simulate "inline-block" supported by IE, 
                Safari and Opera.
            */
            
            var sClass,
                nGeckoVersion = UA.gecko;
				
            
            if (nGeckoVersion && nGeckoVersion < 1.9 && Dom.inDocument(this.get("element"))) {
            
                sClass = this.CSS_CLASS_NAME;                

                this.removeClass(sClass);
                
                Lang.later(0, this, this.addClass, sClass);

            }
        
        },
        
        
        /**
        * @method _setTabIndex
        * @description Sets the value of the button's "tabindex" attribute.
        * @protected
        * @param {Number} p_nTabIndex Number indicating the value for the 
        * button's "tabindex" attribute.
        */
        _setTabIndex: function (p_nTabIndex) {
        
            this._button.tabIndex = p_nTabIndex;
        
        },
        
        
        /**
        * @method _setTitle
        * @description Sets the value of the button's "title" attribute.
        * @protected
        * @param {String} p_nTabIndex Number indicating the value for 
        * the button's "title" attribute.
        */
        _setTitle: function (p_sTitle) {
        
            var sTitle = p_sTitle;
        
            if (this.get("type") != "link") {
        
                if (!sTitle) {
        
                    switch (this.get("type")) {
        
                    case "radio":
    
                        sTitle = this.RADIO_DEFAULT_TITLE;
    
                        break;
    
                    case "checkbox":
    
                        sTitle = this.CHECKBOX_DEFAULT_TITLE;
    
                        break;
                    
                    case "menu":
    
                        sTitle = this.MENUBUTTON_DEFAULT_TITLE;
    
                        break;
    
                    case "split":
    
                        sTitle = this.SPLITBUTTON_DEFAULT_TITLE;
    
                        break;
    
                    case "submit":
    
                        sTitle = this.SUBMIT_TITLE;
    
                        break;
        
                    }
        
                }
        
                this._button.title = sTitle;
        
            }
        
        },
        
        
        /**
        * @method _setDisabled
        * @description Sets the value of the button's "disabled" attribute.
        * @protected
        * @param {Boolean} p_bDisabled Boolean indicating the value for 
        * the button's "disabled" attribute.
        */
        _setDisabled: function (p_bDisabled) {
        
            if (this.get("type") != "link") {
        
                if (p_bDisabled) {
        
                    if (this._menu) {
        
                        this._menu.hide();
        
                    }
        
                    if (this.hasFocus()) {
                    
                        this.blur();
                    
                    }
        
                    this._button.setAttribute("disabled", "disabled");
        
                    this.addStateCSSClasses("disabled");

                    this.removeStateCSSClasses("hover");
                    this.removeStateCSSClasses("active");
                    this.removeStateCSSClasses("focus");
        
                }
                else {
        
                    this._button.removeAttribute("disabled");
        
                    this.removeStateCSSClasses("disabled");
                
                }
        
            }
        
        },

        
        /**
        * @method _setHref
        * @description Sets the value of the button's "href" attribute.
        * @protected
        * @param {String} p_sHref String indicating the value for the button's 
        * "href" attribute.
        */
        _setHref: function (p_sHref) {
        
            if (this.get("type") == "link") {
        
                this._button.href = p_sHref;
            
            }
        
        },
        
        
        /**
        * @method _setTarget
        * @description Sets the value of the button's "target" attribute.
        * @protected
        * @param {String} p_sTarget String indicating the value for the button's 
        * "target" attribute.
        */
        _setTarget: function (p_sTarget) {
        
            if (this.get("type") == "link") {
        
                this._button.setAttribute("target", p_sTarget);
            
            }
        
        },
        
        
        /**
        * @method _setChecked
        * @description Sets the value of the button's "target" attribute.
        * @protected
        * @param {Boolean} p_bChecked Boolean indicating the value for  
        * the button's "checked" attribute.
        */
        _setChecked: function (p_bChecked) {
        
            var sType = this.get("type"),
                sTitle;
        
            if (sType == "checkbox" || sType == "radio") {
        
                if (p_bChecked) {
        
                    this.addStateCSSClasses("checked");
                    
                    sTitle = (sType == "radio") ? 
                                this.RADIO_CHECKED_TITLE : 
                                this.CHECKBOX_CHECKED_TITLE;
                
                }
                else {

                    this.removeStateCSSClasses("checked");
        
                    sTitle = (sType == "radio") ? 
                                this.RADIO_DEFAULT_TITLE : 
                                this.CHECKBOX_DEFAULT_TITLE;
                
                }
        
                this.set("title", sTitle);
        
            }
        
        },
        
        
        /**
        * @method _setMenu
        * @description Sets the value of the button's "menu" attribute.
        * @protected
        * @param {Object} p_oMenu Object indicating the value for the button's 
        * "menu" attribute.
        */
        _setMenu: function (p_oMenu) {

            var bLazyLoad = this.get("lazyloadmenu"),
                oButtonElement = this.get("element"),
                sMenuCSSClassName,
        
                /*
                    Boolean indicating if the value of p_oMenu is an instance 
                    of YAHOO.widget.Menu or YAHOO.widget.Overlay.
                */
        
                bInstance = false,
        

                oMenu,
                oMenuElement,
                oSrcElement,
                aItems,
                nItems,
                oItem,
                i;
        
        
            if (!Overlay) {
        
        
                return false;
            
            }


            if (Menu) {
            
                sMenuCSSClassName = Menu.prototype.CSS_CLASS_NAME;
            
            }
        
        
            function onAppendTo() {

                oMenu.render(oButtonElement.parentNode);
                
                this.removeListener("appendTo", onAppendTo);
            
            }
        
        
            function initMenu() {
        
                if (oMenu) {

                    Dom.addClass(oMenu.element, this.get("menuclassname"));
                    Dom.addClass(oMenu.element, 
                            "yui-" + this.get("type") + "-button-menu");

                    oMenu.showEvent.subscribe(this._onMenuShow, null, this);
                    oMenu.hideEvent.subscribe(this._onMenuHide, null, this);
                    oMenu.renderEvent.subscribe(this._onMenuRender, null, this);
        
        
                    if (Menu && oMenu instanceof Menu) {
        
                        oMenu.keyDownEvent.subscribe(this._onMenuKeyDown, 
                            this, true);

                        oMenu.subscribe("click", this._onMenuClick, 
                            this, true);

                        oMenu.itemAddedEvent.subscribe(this._onMenuItemAdded, 
                            this, true);
        
                        oSrcElement = oMenu.srcElement;
        
                        if (oSrcElement && 
                            oSrcElement.nodeName.toUpperCase() == "SELECT") {
                
                            oSrcElement.style.display = "none";
                            oSrcElement.parentNode.removeChild(oSrcElement);
        
                        }
        
                    }
                    else if (Overlay && oMenu instanceof Overlay) {
        
                        if (!m_oOverlayManager) {
        
                            m_oOverlayManager = 
                                new YAHOO.widget.OverlayManager();
                        
                        }
                        
                        m_oOverlayManager.register(oMenu);
                        
                    }
        
        
                    this._menu = oMenu;

        
                    if (!bInstance) {
        
                        if (bLazyLoad && Menu && !(oMenu instanceof Menu)) {
        
                            /*
                                Mimic Menu's "lazyload" functionality by adding  
                                a "beforeshow" event listener that renders the 
                                Overlay instance before it is made visible by  
                                the button.
                            */
        
                            oMenu.beforeShowEvent.subscribe(
                                this._onOverlayBeforeShow, null, this);
            
                        }
                        else if (!bLazyLoad) {
        
                            if (Dom.inDocument(oButtonElement)) {
        
                                oMenu.render(oButtonElement.parentNode);
                            
                            }
                            else {
            
                                this.on("appendTo", onAppendTo);
                            
                            }
                        
                        }
                    
                    }
        
                }
        
            }
        
        
            if (p_oMenu && Menu && (p_oMenu instanceof Menu)) {
        
                oMenu = p_oMenu;
                aItems = oMenu.getItems();
                nItems = aItems.length;
                bInstance = true;
        
        
                if (nItems > 0) {
        
                    i = nItems - 1;
        
                    do {
        
                        oItem = aItems[i];
        
                        if (oItem) {
        
                            oItem.cfg.subscribeToConfigEvent("selected", 
                                this._onMenuItemSelected, 
                                oItem, 
                                this);
        
                        }
        
                    }
                    while (i--);
        
                }
        
                initMenu.call(this);
        
            }
            else if (Overlay && p_oMenu && (p_oMenu instanceof Overlay)) {
        
                oMenu = p_oMenu;
                bInstance = true;
        
                oMenu.cfg.setProperty("visible", false);
                oMenu.cfg.setProperty("context", [oButtonElement, "tl", "bl"]);
        
                initMenu.call(this);
        
            }
            else if (Menu && Lang.isArray(p_oMenu)) {
        
                this.on("appendTo", function () {
        
                    oMenu = new Menu(Dom.generateId(), { lazyload: bLazyLoad, 
                        itemdata: p_oMenu });
        
                    initMenu.call(this);
        
                });
        
            }
            else if (Lang.isString(p_oMenu)) {
        
                oMenuElement = Dom.get(p_oMenu);
        
                if (oMenuElement) {
        
                    if (Menu && Dom.hasClass(oMenuElement, sMenuCSSClassName) || 
                        oMenuElement.nodeName.toUpperCase() == "SELECT") {
            
                        oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad });
            
                        initMenu.call(this);
            
                    }
                    else if (Overlay) {
        
                        oMenu = new Overlay(p_oMenu, { visible: false, 
                            context: [oButtonElement, "tl", "bl"] });
            
                        initMenu.call(this);
            
                    }
        
                }
        
            }
            else if (p_oMenu && p_oMenu.nodeName) {
        
                if (Menu && Dom.hasClass(p_oMenu, sMenuCSSClassName) || 
                        p_oMenu.nodeName.toUpperCase() == "SELECT") {
        
                    oMenu = new Menu(p_oMenu, { lazyload: bLazyLoad });
                
                    initMenu.call(this);
        
                }
                else if (Overlay) {
        
                    if (!p_oMenu.id) {
                    
                        Dom.generateId(p_oMenu);
                    
                    }
        
                    oMenu = new Overlay(p_oMenu, { visible: false, 
                                    context: [oButtonElement, "tl", "bl"] });
        
                    initMenu.call(this);
                
                }
            
            }
        
        },
        
        
        /**
        * @method _setOnClick
        * @description Sets the value of the button's "onclick" attribute.
        * @protected
        * @param {Object} p_oObject Object indicating the value for the button's 
        * "onclick" attribute.
        */
        _setOnClick: function (p_oObject) {
        
            /*
                Remove any existing listeners if a "click" event handler 
                has already been specified.
            */
        
            if (this._onclickAttributeValue && 
                (this._onclickAttributeValue != p_oObject)) {
        
                this.removeListener("click", this._onclickAttributeValue.fn);
        
                this._onclickAttributeValue = null;
        
            }
        
        
            if (!this._onclickAttributeValue && 
                Lang.isObject(p_oObject) && 
                Lang.isFunction(p_oObject.fn)) {
        
                this.on("click", p_oObject.fn, p_oObject.obj, p_oObject.scope);
        
                this._onclickAttributeValue = p_oObject;
        
            }
        
        },
        
        
        /**
        * @method _setSelectedMenuItem
        * @description Sets the value of the button's 
        * "selectedMenuItem" attribute.
        * @protected
        * @param {Number} p_nIndex Number representing the index of the item 
        * in the button's menu that is currently selected.
        */
        _setSelectedMenuItem: function (p_nIndex) {

            var oMenu = this._menu,
                oMenuItem;


            if (Menu && oMenu && oMenu instanceof Menu) {

                oMenuItem = oMenu.getItem(p_nIndex);
                

                if (oMenuItem && !oMenuItem.cfg.getProperty("selected")) {
                
                    oMenuItem.cfg.setProperty("selected", true);
                
                }
            
            }

        },
        
        
        // Protected methods

        
        
        /**
        * @method _isActivationKey
        * @description Determines if the specified keycode is one that toggles  
        * the button's "active" state.
        * @protected
        * @param {Number} p_nKeyCode Number representing the keycode to 
        * be evaluated.
        * @return {Boolean}
        */
        _isActivationKey: function (p_nKeyCode) {
        
            var sType = this.get("type"),
                aKeyCodes = (sType == "checkbox" || sType == "radio") ? 
                    this.CHECK_ACTIVATION_KEYS : this.ACTIVATION_KEYS,
        
                nKeyCodes = aKeyCodes.length,
                i;
        
            if (nKeyCodes > 0) {
        
                i = nKeyCodes - 1;
        
                do {
        
                    if (p_nKeyCode == aKeyCodes[i]) {
        
                        return true;
        
                    }
        
                }
                while (i--);
            
            }
        
        },
        
        
        /**
        * @method _isSplitButtonOptionKey
        * @description Determines if the specified keycode is one that toggles  
        * the display of the split button's menu.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        * @return {Boolean}
        */
        _isSplitButtonOptionKey: function (p_oEvent) {

			var bShowMenu = (p_oEvent.ctrlKey && p_oEvent.shiftKey && 
								Event.getCharCode(p_oEvent) == 77);


			function onKeyPress(p_oEvent) {

				Event.preventDefault(p_oEvent);

				this.removeListener("keypress", onKeyPress);
			
			}


			/*
				It is necessary to add a "keypress" event listener to prevent Opera's default
				browser context menu from appearing when the user presses Ctrl + Shift + M.
			*/

			if (bShowMenu && UA.opera) {

        		this.on("keypress", onKeyPress);

			}
        
            return bShowMenu;
        
        },
        
        
        /**
        * @method _addListenersToForm
        * @description Adds event handlers to the button's form.
        * @protected
        */
        _addListenersToForm: function () {
        
            var oForm = this.getForm(),
                onFormKeyPress = YAHOO.widget.Button.onFormKeyPress,
                bHasKeyPressListener,
                oSrcElement,
                aListeners,
                nListeners,
                i;
        
        
            if (oForm) {
        
                Event.on(oForm, "reset", this._onFormReset, null, this);
                Event.on(oForm, "submit", this.createHiddenFields, null, this);
        
                oSrcElement = this.get("srcelement");
        
        
                if (this.get("type") == "submit" || 
                    (oSrcElement && oSrcElement.type == "submit")) 
                {
                
                    aListeners = Event.getListeners(oForm, "keypress");
                    bHasKeyPressListener = false;
            
                    if (aListeners) {
            
                        nListeners = aListeners.length;
        
                        if (nListeners > 0) {
            
                            i = nListeners - 1;
                            
                            do {
               
                                if (aListeners[i].fn == onFormKeyPress) {
                
                                    bHasKeyPressListener = true;
                                    break;
                                
                                }
                
                            }
                            while (i--);
                        
                        }
                    
                    }
            
            
                    if (!bHasKeyPressListener) {
               
                        Event.on(oForm, "keypress", onFormKeyPress);
            
                    }
        
                }
            
            }
        
        },
        
        
        
        /**
        * @method _showMenu
        * @description Shows the button's menu.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object 
        * passed back by the event utility (YAHOO.util.Event) that triggered 
        * the display of the menu.
        */
        _showMenu: function (p_oEvent) {

            if (YAHOO.widget.MenuManager) {

                YAHOO.widget.MenuManager.hideVisible();
            
            }

        
            if (m_oOverlayManager) {
        
                m_oOverlayManager.hideAll();
            
            }


            var nViewportOffset = Overlay.VIEWPORT_OFFSET,   
        
                oMenu = this._menu,
                oButton = this,
                oButtonEL = oButton.get("element"),
                bMenuFlipped = false,
                nButtonY = Dom.getY(oButtonEL),
                nScrollTop = Dom.getDocumentScrollTop(),
                nMenuMinScrollHeight,
                nMenuHeight,
                oMenuShadow;
    
    
            if (nScrollTop) {
        
                nButtonY = nButtonY - nScrollTop;
        
            }
        
        
            var nTopRegion = nButtonY,
                nBottomRegion = (Dom.getViewportHeight() - 
                    (nButtonY + oButtonEL.offsetHeight));
        

            /*
                 Uses the Button's position to calculate the availble height 
                 above and below it to display its corresponding Menu.
            */
        
            function getMenuDisplayRegionHeight() {
        
                if (bMenuFlipped) {
        
                    return (nTopRegion - nViewportOffset);
        
                }
                else {
        
                    return (nBottomRegion - nViewportOffset);
        
                }
        
            }

    
    
            /*
                Sets the Menu's "maxheight" configuration property and trys to 
                place the Menu in the best possible position (either above or 
                below its corresponding Button).
            */
        
            function sizeAndPositionMenu() {
        
                var nDisplayRegionHeight = getMenuDisplayRegionHeight();
        
        
                if (nMenuHeight > nDisplayRegionHeight) {
        
                    nMenuMinScrollHeight = oMenu.cfg.getProperty("minscrollheight");
        
        
                    if (nDisplayRegionHeight > nMenuMinScrollHeight) {
        
                        oMenu.cfg.setProperty("maxheight", 
                                    nDisplayRegionHeight);
            
        
                        if (bMenuFlipped) {
                        
                            oMenu.align("bl", "tl");
                        
                        }
						else {

							oMenu.align("tl", "bl");

						}
            
                    }
            
        
                    if (nDisplayRegionHeight < nMenuMinScrollHeight) {
                   
                        if (bMenuFlipped) {
            
                            /*
                                 All possible positions and values for the 
                                 "maxheight" configuration property have been 
                                 tried, but none were successful, so fall back 
                                 to the original size and position.
                            */
        
                            oMenu.cfg.setProperty("context", 
                                [oButtonEL, "tl", "bl"], true);

                            oMenu.align("tl", "bl");
                            
                        }
                        else {
            
                            oMenu.cfg.setProperty("context", 
                                [oButtonEL, "bl", "tl"], true);

                            oMenu.align("bl", "tl");
            
                            bMenuFlipped = true;
            
                            return sizeAndPositionMenu();
            
                        }
                    
                    }
                
                }
        
            }


            if (Menu && oMenu && (oMenu instanceof Menu)) {
        
                oMenu.cfg.applyConfig({ context: [oButtonEL, "tl", "bl"], clicktohide: false });
                    
                oMenu.cfg.fireQueue();
                
                oMenu.show();
                
                oMenu.cfg.setProperty("maxheight", 0);
            
                oMenu.align("tl", "bl");
        
        
                /*
                    Stop the propagation of the event so that the MenuManager 
                    doesn't blur the menu after it gets focus.
                */
        
                if (p_oEvent.type == "mousedown") {
        
                    Event.stopPropagation(p_oEvent);
        
                }
        
                
                nMenuHeight = oMenu.element.offsetHeight;
                
                oMenuShadow = oMenu.element.lastChild; 
        
                sizeAndPositionMenu();
        
                if (this.get("focusmenu")) {
        
                    this._menu.focus();
                
                }

            }
            else if (Overlay && oMenu && (oMenu instanceof Overlay)) {
        
                oMenu.show();
                oMenu.align("tl", "bl");
                
                var nDisplayRegionHeight = getMenuDisplayRegionHeight();

                nMenuHeight = oMenu.element.offsetHeight;


                if (nDisplayRegionHeight < nMenuHeight) {

                    oMenu.align("bl", "tl");

                    bMenuFlipped = true;

                    nDisplayRegionHeight = getMenuDisplayRegionHeight();

                    if (nDisplayRegionHeight < nMenuHeight) {

                        oMenu.align("tl", "bl");
                    
                    }

                }
        
            }
        
        },
        
        
        /**
        * @method _hideMenu
        * @description Hides the button's menu.
        * @protected
        */
        _hideMenu: function () {
        
            var oMenu = this._menu;
        
            if (oMenu) {
        
                oMenu.hide();
        
            }
        
        },
        
        
        
        
        // Protected event handlers
        
        
        /**
        * @method _onMouseOver
        * @description "mouseover" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onMouseOver: function (p_oEvent) {
        
            if (!this._hasMouseEventHandlers) {
        
                this.on("mouseout", this._onMouseOut);
                this.on("mousedown", this._onMouseDown);
                this.on("mouseup", this._onMouseUp);
        
                this._hasMouseEventHandlers = true;
        
            }
        
            this.addStateCSSClasses("hover");
        
            if (this._activationButtonPressed) {
        
                this.addStateCSSClasses("active");
        
            }
        
        
            if (this._bOptionPressed) {
        
                this.addStateCSSClasses("activeoption");
            
            }


            if (this._activationButtonPressed || this._bOptionPressed) {
        
                Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
        
            }

        },
        
        
        /**
        * @method _onMouseOut
        * @description "mouseout" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onMouseOut: function (p_oEvent) {
        
            this.removeStateCSSClasses("hover");
        
            if (this.get("type") != "menu") {
        
                this.removeStateCSSClasses("active");
        
            }
        
            if (this._activationButtonPressed || this._bOptionPressed) {
        
                Event.on(document, "mouseup", this._onDocumentMouseUp, 
                    null, this);
        
            }
            
        },
        
        
        /**
        * @method _onDocumentMouseUp
        * @description "mouseup" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onDocumentMouseUp: function (p_oEvent) {
        
            this._activationButtonPressed = false;
            this._bOptionPressed = false;
        
            var sType = this.get("type"),
                oTarget,
                oMenuElement;
        
            if (sType == "menu" || sType == "split") {

                oTarget = Event.getTarget(p_oEvent);
                oMenuElement = this._menu.element;
        
                if (oTarget != oMenuElement && 
                    !Dom.isAncestor(oMenuElement, oTarget)) {

                    this.removeStateCSSClasses((sType == "menu" ? 
                        "active" : "activeoption"));
            
                    this._hideMenu();

                }
        
            }
        
            Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
        
        },
        
        
        /**
        * @method _onMouseDown
        * @description "mousedown" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onMouseDown: function (p_oEvent) {
        
            var sType,
                oElement,
                nX,
                me;
        
        
            function onMouseUp() {
            
                this._hideMenu();
                this.removeListener("mouseup", onMouseUp);
            
            }
        
        
            if ((p_oEvent.which || p_oEvent.button) == 1) {
        
        
                if (!this.hasFocus()) {
                
                    this.focus();
                
                }
        
        
                sType = this.get("type");
        
        
                if (sType == "split") {
                
                    oElement = this.get("element");
                    nX = Event.getPageX(p_oEvent) - Dom.getX(oElement);
        
                    if ((oElement.offsetWidth - this.OPTION_AREA_WIDTH) < nX) {
                        
                        this.fireEvent("option", p_oEvent);
        
                    }
                    else {
        
                        this.addStateCSSClasses("active");
        
                        this._activationButtonPressed = true;
        
                    }
        
                }
                else if (sType == "menu") {
        
                    if (this.isActive()) {
        
                        this._hideMenu();
        
                        this._activationButtonPressed = false;
        
                    }
                    else {
        
                        this._showMenu(p_oEvent);
        
                        this._activationButtonPressed = true;
                    
                    }
        
                }
                else {
        
                    this.addStateCSSClasses("active");
        
                    this._activationButtonPressed = true;
                
                }
        
        
        
                if (sType == "split" || sType == "menu") {

                    me = this;
        
                    this._hideMenuTimerId = window.setTimeout(function () {
                    
                        me.on("mouseup", onMouseUp);
                    
                    }, 250);
        
                }
        
            }
            
        },
        
        
        /**
        * @method _onMouseUp
        * @description "mouseup" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onMouseUp: function (p_oEvent) {
        
            var sType = this.get("type");
        
        
            if (this._hideMenuTimerId) {
        
                window.clearTimeout(this._hideMenuTimerId);
        
            }
        
        
            if (sType == "checkbox" || sType == "radio") {
        
                this.set("checked", !(this.get("checked")));
            
            }
        
        
            this._activationButtonPressed = false;
            
        
            if (this.get("type") != "menu") {
        
                this.removeStateCSSClasses("active");
            
            }
            
        },
        
        
        /**
        * @method _onFocus
        * @description "focus" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onFocus: function (p_oEvent) {
        
            var oElement;
        
            this.addStateCSSClasses("focus");
        
            if (this._activationKeyPressed) {
        
                this.addStateCSSClasses("active");
           
            }
        
            m_oFocusedButton = this;
        
        
            if (!this._hasKeyEventHandlers) {
        
                oElement = this._button;
        
                Event.on(oElement, "blur", this._onBlur, null, this);
                Event.on(oElement, "keydown", this._onKeyDown, null, this);
                Event.on(oElement, "keyup", this._onKeyUp, null, this);
        
                this._hasKeyEventHandlers = true;
        
            }
        
        
            this.fireEvent("focus", p_oEvent);
        
        },
        
        
        /**
        * @method _onBlur
        * @description "blur" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onBlur: function (p_oEvent) {
        
            this.removeStateCSSClasses("focus");
        
            if (this.get("type") != "menu") {
        
                this.removeStateCSSClasses("active");

            }    
        
            if (this._activationKeyPressed) {
        
                Event.on(document, "keyup", this._onDocumentKeyUp, null, this);
        
            }
        
        
            m_oFocusedButton = null;
        
            this.fireEvent("blur", p_oEvent);
           
        },
        
        
        /**
        * @method _onDocumentKeyUp
        * @description "keyup" event handler for the document.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onDocumentKeyUp: function (p_oEvent) {
        
            if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
        
                this._activationKeyPressed = false;
                
                Event.removeListener(document, "keyup", this._onDocumentKeyUp);
            
            }
        
        },
        
        
        /**
        * @method _onKeyDown
        * @description "keydown" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onKeyDown: function (p_oEvent) {
        
            var oMenu = this._menu;
        
        
            if (this.get("type") == "split" && 
                this._isSplitButtonOptionKey(p_oEvent)) {
        
                this.fireEvent("option", p_oEvent);
        
            }
            else if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
        
                if (this.get("type") == "menu") {
        
                    this._showMenu(p_oEvent);
        
                }
                else {
        
                    this._activationKeyPressed = true;
                    
                    this.addStateCSSClasses("active");
                
                }
            
            }
        
        
            if (oMenu && oMenu.cfg.getProperty("visible") && 
                Event.getCharCode(p_oEvent) == 27) {
            
                oMenu.hide();
                this.focus();
            
            }
        
        },
        
        
        /**
        * @method _onKeyUp
        * @description "keyup" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onKeyUp: function (p_oEvent) {
        
            var sType;
        
            if (this._isActivationKey(Event.getCharCode(p_oEvent))) {
        
                sType = this.get("type");
        
                if (sType == "checkbox" || sType == "radio") {
        
                    this.set("checked", !(this.get("checked")));
                
                }
        
                this._activationKeyPressed = false;
        
                if (this.get("type") != "menu") {
        
                    this.removeStateCSSClasses("active");
        
                }
        
            }
        
        },
        
        
        /**
        * @method _onClick
        * @description "click" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onClick: function (p_oEvent) {
        
            var sType = this.get("type"),
                sTitle,
                oForm,
                oSrcElement,
                oElement,
                nX;
        
        
            switch (sType) {
        
            case "radio":
            case "checkbox":
    
                if (this.get("checked")) {
                    
                    sTitle = (sType == "radio") ? 
                                this.RADIO_CHECKED_TITLE : 
                                this.CHECKBOX_CHECKED_TITLE;
                
                }
                else {
                
                    sTitle = (sType == "radio") ? 
                                this.RADIO_DEFAULT_TITLE : 
                                this.CHECKBOX_DEFAULT_TITLE;
                
                }
                
                this.set("title", sTitle);
    
                break;
    
            case "submit":
    
                this.submitForm();
            
                break;
    
            case "reset":
    
                oForm = this.getForm();
    
                if (oForm) {
    
                    oForm.reset();
                
                }
    
                break;
    
            case "menu":
    
                sTitle = this._menu.cfg.getProperty("visible") ? 
                                this.MENUBUTTON_MENU_VISIBLE_TITLE : 
                                this.MENUBUTTON_DEFAULT_TITLE;
    
                this.set("title", sTitle);
    
                break;
    
            case "split":
    
                oElement = this.get("element");
                nX = Event.getPageX(p_oEvent) - Dom.getX(oElement);
    
                if ((oElement.offsetWidth - this.OPTION_AREA_WIDTH) < nX) {
    
                    return false;
                
                }
                else {
    
                    this._hideMenu();
        
                    oSrcElement = this.get("srcelement");
        
                    if (oSrcElement && oSrcElement.type == "submit") {
    
                        this.submitForm();
                    
                    }
                
                }
    
                sTitle = this._menu.cfg.getProperty("visible") ? 
                                this.SPLITBUTTON_OPTION_VISIBLE_TITLE : 
                                this.SPLITBUTTON_DEFAULT_TITLE;
    
                this.set("title", sTitle);
    
                break;
        
            }
        
        },
        
        
        /**
        * @method _onAppendTo
        * @description "appendTo" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onAppendTo: function (p_oEvent) {
        
            /*
                It is necessary to call "_addListenersToForm" using 
                "setTimeout" to make sure that the button's "form" property 
                returns a node reference.  Sometimes, if you try to get the 
                reference immediately after appending the field, it is null.
            */
        
            var me = this;
        
            window.setTimeout(function () {
        
                me._addListenersToForm();
        
            }, 0);
        
        },
        
        
        /**
        * @method _onFormReset
        * @description "reset" event handler for the button's form.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event 
        * object passed back by the event utility (YAHOO.util.Event).
        */
        _onFormReset: function (p_oEvent) {
        
            var sType = this.get("type"),
                oMenu = this._menu;
        
            if (sType == "checkbox" || sType == "radio") {
        
                this.resetValue("checked");
        
            }
        
        
            if (Menu && oMenu && (oMenu instanceof Menu)) {
        
                this.resetValue("selectedMenuItem");
        
            }
        
        },
        
        
        /**
        * @method _onDocumentMouseDown
        * @description "mousedown" event handler for the document.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onDocumentMouseDown: function (p_oEvent) {

            var oTarget = Event.getTarget(p_oEvent),
                oButtonElement = this.get("element"),
                oMenuElement = this._menu.element;
           
        
            if (oTarget != oButtonElement && 
                !Dom.isAncestor(oButtonElement, oTarget) && 
                oTarget != oMenuElement && 
                !Dom.isAncestor(oMenuElement, oTarget)) {
        
                this._hideMenu();
        
                Event.removeListener(document, "mousedown", 
                    this._onDocumentMouseDown);    
            
            }
        
        },
        
        
        /**
        * @method _onOption
        * @description "option" event handler for the button.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onOption: function (p_oEvent) {
        
            if (this.hasClass("yui-split-button-activeoption")) {
        
                this._hideMenu();
        
                this._bOptionPressed = false;
        
            }
            else {
        
                this._showMenu(p_oEvent);    
        
                this._bOptionPressed = true;
        
            }
        
        },
        
        
        /**
        * @method _onOverlayBeforeShow
        * @description "beforeshow" event handler for the 
        * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a> instance 
        * serving as the button's menu.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        */
        _onOverlayBeforeShow: function (p_sType) {
        
            var oMenu = this._menu;
        
            oMenu.render(this.get("element").parentNode);
            
            oMenu.beforeShowEvent.unsubscribe(this._onOverlayBeforeShow);
        
        },
        
        
        /**
        * @method _onMenuShow
        * @description "show" event handler for the button's menu.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        */
        _onMenuShow: function (p_sType) {
        
            Event.on(document, "mousedown", this._onDocumentMouseDown, 
                null, this);
        
            var sTitle,
                sState;
            
            if (this.get("type") == "split") {
        
                sTitle = this.SPLITBUTTON_OPTION_VISIBLE_TITLE;
                sState = "activeoption";
            
            }
            else {
        
                sTitle = this.MENUBUTTON_MENU_VISIBLE_TITLE;        
                sState = "active";
        
            }
        
            this.addStateCSSClasses(sState);
            this.set("title", sTitle);
        
        },
        
        
        /**
        * @method _onMenuHide
        * @description "hide" event handler for the button's menu.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        */
        _onMenuHide: function (p_sType) {
            
            var oMenu = this._menu,
                sTitle,
                sState;
        
            
            if (this.get("type") == "split") {
        
                sTitle = this.SPLITBUTTON_DEFAULT_TITLE;
                sState = "activeoption";
        
            }
            else {
        
                sTitle = this.MENUBUTTON_DEFAULT_TITLE;        
                sState = "active";
            }
        
        
            this.removeStateCSSClasses(sState);
            this.set("title", sTitle);
        
        
            if (this.get("type") == "split") {
        
                this._bOptionPressed = false;
            
            }
        
        },
        
        
        /**
        * @method _onMenuKeyDown
        * @description "keydown" event handler for the button's menu.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        */
        _onMenuKeyDown: function (p_sType, p_aArgs) {
        
            var oEvent = p_aArgs[0];
        
            if (Event.getCharCode(oEvent) == 27) {
        
                this.focus();
        
                if (this.get("type") == "split") {
                
                    this._bOptionPressed = false;
                
                }
        
            }
        
        },
        
        
        /**
        * @method _onMenuRender
        * @description "render" event handler for the button's menu.
        * @private
        * @param {String} p_sType String representing the name of the  
        * event thatwas fired.
        */
        _onMenuRender: function (p_sType) {
        
            var oButtonElement = this.get("element"),
                oButtonParent = oButtonElement.parentNode,
                oMenuElement = this._menu.element;
        
        
            if (oButtonParent != oMenuElement.parentNode) {
        
                oButtonParent.appendChild(oMenuElement);
            
            }

            this.set("selectedMenuItem", this.get("selectedMenuItem"));

        },
        
        
        /**
        * @method _onMenuItemSelected
        * @description "selectedchange" event handler for each item in the 
        * button's menu.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        * @param {MenuItem} p_oItem Object representing the menu item that
        * subscribed to the event.
        */
        _onMenuItemSelected: function (p_sType, p_aArgs, p_oItem) {

            var bSelected = p_aArgs[0];

            if (bSelected) {
            
                this.set("selectedMenuItem", p_oItem);

            }
        
        },
        
        
        /**
        * @method _onMenuItemAdded
        * @description "itemadded" event handler for the button's menu.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event
        * was fired.
        * @param {<a href="YAHOO.widget.MenuItem.html">
        * YAHOO.widget.MenuItem</a>} p_oItem Object representing the menu 
        * item that subscribed to the event.
        */
        _onMenuItemAdded: function (p_sType, p_aArgs, p_oItem) {
            
            var oItem = p_aArgs[0];
        
            oItem.cfg.subscribeToConfigEvent("selected", 
                this._onMenuItemSelected, oItem, this);
        
        },
        
        
        /**
        * @method _onMenuClick
        * @description "click" event handler for the button's menu.
        * @private
        * @param {String} p_sType String representing the name of the event  
        * that was fired.
        * @param {Array} p_aArgs Array of arguments sent when the event 
        * was fired.
        */
        _onMenuClick: function (p_sType, p_aArgs) {

            var oItem = p_aArgs[1],
                oSrcElement;
        
            if (oItem) {
        
                oSrcElement = this.get("srcelement");
            
                if (oSrcElement && oSrcElement.type == "submit") {
        
                    this.submitForm();
            
                }
            
                this._hideMenu();
            
            }
        
        },
        
        
        
        // Public methods
        
        
        /**
        * @method createButtonElement
        * @description Creates the button's HTML elements.
        * @param {String} p_sType String indicating the type of element 
        * to create.
        * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-58190037">HTMLElement</a>}
        */
        createButtonElement: function (p_sType) {
        
            var sNodeName = this.NODE_NAME,
                oElement = document.createElement(sNodeName);
        
            oElement.innerHTML =  "<" + sNodeName + " class=\"first-child\">" + 
                (p_sType == "link" ? "<a></a>" : 
                "<button type=\"button\"></button>") + "</" + sNodeName + ">";
        
            return oElement;
        
        },

        
        /**
        * @method addStateCSSClasses
        * @description Appends state-specific CSS classes to the button's root 
        * DOM element.
        */
        addStateCSSClasses: function (p_sState) {
        
            var sType = this.get("type");
        
            if (Lang.isString(p_sState)) {
        
                if (p_sState != "activeoption") {
        
                    this.addClass(this.CSS_CLASS_NAME + ("-" + p_sState));
        
                }
        
                this.addClass("yui-" + sType + ("-button-" + p_sState));
            
            }
        
        },
        
        
        /**
        * @method removeStateCSSClasses
        * @description Removes state-specific CSS classes to the button's root 
        * DOM element.
        */
        removeStateCSSClasses: function (p_sState) {
        
            var sType = this.get("type");
        
            if (Lang.isString(p_sState)) {
        
                this.removeClass(this.CSS_CLASS_NAME + ("-" + p_sState));
                this.removeClass("yui-" + sType + ("-button-" + p_sState));
            
            }
        
        },
        
        
        /**
        * @method createHiddenFields
        * @description Creates the button's hidden form field and appends it 
        * to its parent form.
        * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array}
        */
        createHiddenFields: function () {
        
            this.removeHiddenFields();
        
            var oForm = this.getForm(),
                oButtonField,
                sType,     
                bCheckable,
                oMenu,
                oMenuItem,
                sName,
                oValue,
                oMenuField;
        
        
            if (oForm && !this.get("disabled")) {
        
                sType = this.get("type");
                bCheckable = (sType == "checkbox" || sType == "radio");
        
        
                if (bCheckable || (m_oSubmitTrigger == this)) {
                
        
                    oButtonField = createInputElement(
                                    (bCheckable ? sType : "hidden"),
                                    this.get("name"),
                                    this.get("value"),
                                    this.get("checked"));
            
            
                    if (oButtonField) {
            
                        if (bCheckable) {
            
                            oButtonField.style.display = "none";
            
                        }
            
                        oForm.appendChild(oButtonField);
            
                    }
        
                }
                    
        
                oMenu = this._menu;
            
            
                if (Menu && oMenu && (oMenu instanceof Menu)) {
        
        
                    oMenuField = oMenu.srcElement;
                    oMenuItem = this.get("selectedMenuItem");

                    if (oMenuItem) {

                        if (oMenuField && 
                            oMenuField.nodeName.toUpperCase() == "SELECT") {
            
                            oForm.appendChild(oMenuField);
                            oMenuField.selectedIndex = oMenuItem.index;
            
                        }
                        else {
            
                            oValue = (oMenuItem.value === null || 
                                        oMenuItem.value === "") ? 
                                        oMenuItem.cfg.getProperty("text") : 
                                        oMenuItem.value;
            
                            sName = this.get("name");
            
                            if (oValue && sName) {
            
                                oMenuField = createInputElement("hidden", 
                                                    (sName + "_options"),
                                                    oValue);
            
                                oForm.appendChild(oMenuField);
            
                            }
            
                        }  
                    
                    }
        
                }
            
            
                if (oButtonField && oMenuField) {
        
                    this._hiddenFields = [oButtonField, oMenuField];
        
                }
                else if (!oButtonField && oMenuField) {
        
                    this._hiddenFields = oMenuField;
                
                }
                else if (oButtonField && !oMenuField) {
        
                    this._hiddenFields = oButtonField;
                
                }
        
        
                return this._hiddenFields;
        
            }
        
        },
        
        
        /**
        * @method removeHiddenFields
        * @description Removes the button's hidden form field(s) from its 
        * parent form.
        */
        removeHiddenFields: function () {
        
            var oField = this._hiddenFields,
                nFields,
                i;
        
            function removeChild(p_oElement) {
        
                if (Dom.inDocument(p_oElement)) {
        
                    p_oElement.parentNode.removeChild(p_oElement);
                
                }
                
            }
            
        
            if (oField) {
        
                if (Lang.isArray(oField)) {
        
                    nFields = oField.length;
                    
                    if (nFields > 0) {
                    
                        i = nFields - 1;
                        
                        do {
        
                            removeChild(oField[i]);
        
                        }
                        while (i--);
                    
                    }
                
                }
                else {
        
                    removeChild(oField);
        
                }
        
                this._hiddenFields = null;
            
            }
        
        },
        
        
        /**
        * @method submitForm
        * @description Submits the form to which the button belongs.  Returns  
        * true if the form was submitted successfully, false if the submission 
        * was cancelled.
        * @protected
        * @return {Boolean}
        */
        submitForm: function () {
        
            var oForm = this.getForm(),
        
                oSrcElement = this.get("srcelement"),
        
                /*
                    Boolean indicating if the event fired successfully 
                    (was not cancelled by any handlers)
                */
        
                bSubmitForm = false,
                
                oEvent;
        
        
            if (oForm) {
        
                if (this.get("type") == "submit" || 
                    (oSrcElement && oSrcElement.type == "submit")) 
                {
        
                    m_oSubmitTrigger = this;
                    
                }
        
        
                if (UA.ie) {
        
                    bSubmitForm = oForm.fireEvent("onsubmit");
        
                }
                else {  // Gecko, Opera, and Safari
        
                    oEvent = document.createEvent("HTMLEvents");
                    oEvent.initEvent("submit", true, true);
        
                    bSubmitForm = oForm.dispatchEvent(oEvent);
        
                }
        
        
                /*
                    In IE and Safari, dispatching a "submit" event to a form 
                    WILL cause the form's "submit" event to fire, but WILL NOT 
                    submit the form.  Therefore, we need to call the "submit" 
                    method as well.
                */
              
                if ((UA.ie || UA.webkit) && bSubmitForm) {
        
                    oForm.submit();
                
                }
            
            }
        
            return bSubmitForm;
            
        },
        
        
        /**
        * @method init
        * @description The Button class's initialization method.
        * @param {String} p_oElement String specifying the id attribute of the 
        * <code>&#60;input&#62;</code>, <code>&#60;button&#62;</code>,
        * <code>&#60;a&#62;</code>, or <code>&#60;span&#62;</code> element to 
        * be used to create the button.
        * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-6043025">HTMLInputElement</a>|<a href="http://
        * www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html
        * #ID-34812697">HTMLButtonElement</a>|<a href="http://www.w3.org/TR
        * /2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-33759296">
        * HTMLElement</a>} p_oElement Object reference for the 
        * <code>&#60;input&#62;</code>, <code>&#60;button&#62;</code>, 
        * <code>&#60;a&#62;</code>, or <code>&#60;span&#62;</code> element to be 
        * used to create the button.
        * @param {Object} p_oElement Object literal specifying a set of 
        * configuration attributes used to create the button.
        * @param {Object} p_oAttributes Optional. Object literal specifying a 
        * set of configuration attributes used to create the button.
        */
        init: function (p_oElement, p_oAttributes) {
        
            var sNodeName = p_oAttributes.type == "link" ? "a" : "button",
                oSrcElement = p_oAttributes.srcelement,
                oButton = p_oElement.getElementsByTagName(sNodeName)[0],
                oInput;
        

            if (!oButton) {

                oInput = p_oElement.getElementsByTagName("input")[0];


                if (oInput) {

                    oButton = document.createElement("button");
                    oButton.setAttribute("type", "button");

                    oInput.parentNode.replaceChild(oButton, oInput);
                
                }

            }

            this._button = oButton;
        

            YAHOO.widget.Button.superclass.init.call(this, p_oElement, 
                p_oAttributes);
        
        
            m_oButtons[this.get("id")] = this;
        
        
            this.addClass(this.CSS_CLASS_NAME);
            
            this.addClass("yui-" + this.get("type") + "-button");
        
            Event.on(this._button, "focus", this._onFocus, null, this);
            this.on("mouseover", this._onMouseOver);
            this.on("click", this._onClick);
            this.on("appendTo", this._onAppendTo);
            
        
            var oContainer = this.get("container"),
                oElement = this.get("element"),
                bElInDoc = Dom.inDocument(oElement),
                oParentNode;


            if (oContainer) {
        
                if (oSrcElement && oSrcElement != oElement) {
                
                    oParentNode = oSrcElement.parentNode;

                    if (oParentNode) {
                    
                        oParentNode.removeChild(oSrcElement);
                    
                    }

                }
        
                if (Lang.isString(oContainer)) {
        
                    Event.onContentReady(oContainer, function () {
        
                        this.appendTo(oContainer);
                    
                    }, null, this);
        
                }
                else {
        
                    this.appendTo(oContainer);
        
                }
        
            }
            else if (!bElInDoc && oSrcElement && oSrcElement != oElement) {

                oParentNode = oSrcElement.parentNode;
        
                if (oParentNode) {
        
                    this.fireEvent("beforeAppendTo", {
                        type: "beforeAppendTo",
                        target: oParentNode
                    });
            
                    oParentNode.replaceChild(oElement, oSrcElement);
            
                    this.fireEvent("appendTo", {
                        type: "appendTo",
                        target: oParentNode
                    });
                
                }
        
            }
            else if (this.get("type") != "link" && bElInDoc && oSrcElement && 
                oSrcElement == oElement) {
        
                this._addListenersToForm();
        
            }
        
        
        },
        
        
        /**
        * @method initAttributes
        * @description Initializes all of the configuration attributes used to  
        * create the button.
        * @param {Object} p_oAttributes Object literal specifying a set of 
        * configuration attributes used to create the button.
        */
        initAttributes: function (p_oAttributes) {
        
            var oAttributes = p_oAttributes || {};
        
            YAHOO.widget.Button.superclass.initAttributes.call(this, 
                oAttributes);
        
        
            /**
            * @attribute type
            * @description String specifying the button's type.  Possible 
            * values are: "push," "link," "submit," "reset," "checkbox," 
            * "radio," "menu," and "split."
            * @default "push"
            * @type String
            */
            this.setAttributeConfig("type", {
        
                value: (oAttributes.type || "push"),
                validator: Lang.isString,
                writeOnce: true,
                method: this._setType
        
            });
        
        
            /**
            * @attribute label
            * @description String specifying the button's text label 
            * or innerHTML.
            * @default null
            * @type String
            */
            this.setAttributeConfig("label", {
        
                value: oAttributes.label,
                validator: Lang.isString,
                method: this._setLabel
        
            });
        
        
            /**
            * @attribute value
            * @description Object specifying the value for the button.
            * @default null
            * @type Object
            */
            this.setAttributeConfig("value", {
        
                value: oAttributes.value
        
            });
        
        
            /**
            * @attribute name
            * @description String specifying the name for the button.
            * @default null
            * @type String
            */
            this.setAttributeConfig("name", {
        
                value: oAttributes.name,
                validator: Lang.isString
        
            });
        
        
            /**
            * @attribute tabindex
            * @description Number specifying the tabindex for the button.
            * @default null
            * @type Number
            */
            this.setAttributeConfig("tabindex", {
        
                value: oAttributes.tabindex,
                validator: Lang.isNumber,
                method: this._setTabIndex
        
            });
        
        
            /**
            * @attribute title
            * @description String specifying the title for the button.
            * @default null
            * @type String
            */
            this.configureAttribute("title", {
        
                value: oAttributes.title,
                validator: Lang.isString,
                method: this._setTitle
        
            });
        
        
            /**
            * @attribute disabled
            * @description Boolean indicating if the button should be disabled.  
            * (Disabled buttons are dimmed and will not respond to user input 
            * or fire events.  Does not apply to button's of type "link.")
            * @default false
            * @type Boolean
            */
            this.setAttributeConfig("disabled", {
        
                value: (oAttributes.disabled || false),
                validator: Lang.isBoolean,
                method: this._setDisabled
        
            });
        
        
            /**
            * @attribute href
            * @description String specifying the href for the button.  Applies
            * only to buttons of type "link."
            * @type String
            */
            this.setAttributeConfig("href", {
        
                value: oAttributes.href,
                validator: Lang.isString,
                method: this._setHref
        
            });
        
        
            /**
            * @attribute target
            * @description String specifying the target for the button.  
            * Applies only to buttons of type "link."
            * @type String
            */
            this.setAttributeConfig("target", {
        
                value: oAttributes.target,
                validator: Lang.isString,
                method: this._setTarget
        
            });
        
        
            /**
            * @attribute checked
            * @description Boolean indicating if the button is checked. 
            * Applies only to buttons of type "radio" and "checkbox."
            * @default false
            * @type Boolean
            */
            this.setAttributeConfig("checked", {
        
                value: (oAttributes.checked || false),
                validator: Lang.isBoolean,
                method: this._setChecked
        
            });
        
        
            /**
            * @attribute container
            * @description HTML element reference or string specifying the id 
            * attribute of the HTML element that the button's markup should be 
            * rendered into.
            * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
            * level-one-html.html#ID-58190037">HTMLElement</a>|String
            * @default null
            */
            this.setAttributeConfig("container", {
        
                value: oAttributes.container,
                writeOnce: true
        
            });
        
        
            /**
            * @attribute srcelement
            * @description Object reference to the HTML element (either 
            * <code>&#60;input&#62;</code> or <code>&#60;span&#62;</code>) 
            * used to create the button.
            * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
            * level-one-html.html#ID-58190037">HTMLElement</a>|String
            * @default null
            */
            this.setAttributeConfig("srcelement", {
        
                value: oAttributes.srcelement,
                writeOnce: true
        
            });
        
        
            /**
            * @attribute menu
            * @description Object specifying the menu for the button.  
            * The value can be one of the following:
            * <ul>
            * <li>Object specifying a <a href="YAHOO.widget.Menu.html">
            * YAHOO.widget.Menu</a> instance.</li>
            * <li>Object specifying a <a href="YAHOO.widget.Overlay.html">
            * YAHOO.widget.Overlay</a> instance.</li>
            * <li>String specifying the id attribute of the <code>&#60;div&#62;
            * </code> element used to create the menu.  By default the menu 
            * will be created as an instance of 
            * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>.  
            * If the <a href="YAHOO.widget.Menu.html#CSS_CLASS_NAME">
            * default CSS class name for YAHOO.widget.Menu</a> is applied to 
            * the <code>&#60;div&#62;</code> element, it will be created as an
            * instance of <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu
            * </a>.</li><li>String specifying the id attribute of the 
            * <code>&#60;select&#62;</code> element used to create the menu.
            * </li><li>Object specifying the <code>&#60;div&#62;</code> element
            * used to create the menu.</li>
            * <li>Object specifying the <code>&#60;select&#62;</code> element
            * used to create the menu.</li>
            * <li>Array of object literals, each representing a set of 
            * <a href="YAHOO.widget.MenuItem.html">YAHOO.widget.MenuItem</a> 
            * configuration attributes.</li>
            * <li>Array of strings representing the text labels for each menu 
            * item in the menu.</li>
            * </ul>
            * @type <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>|<a 
            * href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>|<a 
            * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
            * one-html.html#ID-58190037">HTMLElement</a>|String|Array
            * @default null
            */
            this.setAttributeConfig("menu", {
        
                value: null,
                method: this._setMenu,
                writeOnce: true
            
            });
        
        
            /**
            * @attribute lazyloadmenu
            * @description Boolean indicating the value to set for the 
            * <a href="YAHOO.widget.Menu.html#lazyLoad">"lazyload"</a>
            * configuration property of the button's menu.  Setting 
            * "lazyloadmenu" to <code>true </code> will defer rendering of 
            * the button's menu until the first time it is made visible.  
            * If "lazyloadmenu" is set to <code>false</code>, the button's 
            * menu will be rendered immediately if the button is in the 
            * document, or in response to the button's "appendTo" event if 
            * the button is not yet in the document.  In either case, the 
            * menu is rendered into the button's parent HTML element.  
            * <em>This attribute does not apply if a 
            * <a href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a> or 
            * <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a> 
            * instance is passed as the value of the button's "menu" 
            * configuration attribute. <a href="YAHOO.widget.Menu.html">
            * YAHOO.widget.Menu</a> or <a href="YAHOO.widget.Overlay.html">
            * YAHOO.widget.Overlay</a> instances should be rendered before 
            * being set as the value for the "menu" configuration 
            * attribute.</em>
            * @default true
            * @type Boolean
            */
            this.setAttributeConfig("lazyloadmenu", {
        
                value: (oAttributes.lazyloadmenu === false ? false : true),
                validator: Lang.isBoolean,
                writeOnce: true
        
            });


            /**
            * @attribute menuclassname
            * @description String representing the CSS class name to be 
            * applied to the root element of the button's menu.
            * @type String
            * @default "yui-button-menu"
            */
            this.setAttributeConfig("menuclassname", {
        
                value: (oAttributes.menuclassname || "yui-button-menu"),
                validator: Lang.isString,
                method: this._setMenuClassName,
                writeOnce: true
        
            });        


            /**
            * @attribute selectedMenuItem
            * @description Object representing the item in the button's menu 
            * that is currently selected.
            * @type Number
            * @default null
            */
            this.setAttributeConfig("selectedMenuItem", {
        
                value: null,
                method: this._setSelectedMenuItem
        
            });
        
        
            /**
            * @attribute onclick
            * @description Object literal representing the code to be executed  
            * when the button is clicked.  Format:<br> <code> {<br> 
            * <strong>fn:</strong> Function,   &#47;&#47; The handler to call 
            * when the event fires.<br> <strong>obj:</strong> Object, 
            * &#47;&#47; An object to pass back to the handler.<br> 
            * <strong>scope:</strong> Object &#47;&#47;  The object to use 
            * for the scope of the handler.<br> } </code>
            * @type Object
            * @default null
            */
            this.setAttributeConfig("onclick", {
        
                value: oAttributes.onclick,
                method: this._setOnClick
            
            });


            /**
            * @attribute focusmenu
            * @description Boolean indicating whether or not the button's menu 
            * should be focused when it is made visible.
            * @type Boolean
            * @default true
            */
            this.setAttributeConfig("focusmenu", {
        
                value: (oAttributes.focusmenu === false ? false : true),
                validator: Lang.isBoolean
        
            });

        },
        
        
        /**
        * @method focus
        * @description Causes the button to receive the focus and fires the 
        * button's "focus" event.
        */
        focus: function () {
        
            if (!this.get("disabled")) {
        
                this._button.focus();
            
            }
        
        },
        
        
        /**
        * @method blur
        * @description Causes the button to lose focus and fires the button's
        * "blur" event.
        */
        blur: function () {
        
            if (!this.get("disabled")) {
        
                this._button.blur();
        
            }
        
        },
        
        
        /**
        * @method hasFocus
        * @description Returns a boolean indicating whether or not the button 
        * has focus.
        * @return {Boolean}
        */
        hasFocus: function () {
        
            return (m_oFocusedButton == this);
        
        },
        
        
        /**
        * @method isActive
        * @description Returns a boolean indicating whether or not the button 
        * is active.
        * @return {Boolean}
        */
        isActive: function () {
        
            return this.hasClass(this.CSS_CLASS_NAME + "-active");
        
        },
        
        
        /**
        * @method getMenu
        * @description Returns a reference to the button's menu.
        * @return {<a href="YAHOO.widget.Overlay.html">
        * YAHOO.widget.Overlay</a>|<a 
        * href="YAHOO.widget.Menu.html">YAHOO.widget.Menu</a>}
        */
        getMenu: function () {
        
            return this._menu;
        
        },
        
        
        /**
        * @method getForm
        * @description Returns a reference to the button's parent form.
        * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-
        * 20000929/level-one-html.html#ID-40002357">HTMLFormElement</a>}
        */
        getForm: function () {
        
            return this._button.form;
        
        },
        
        
        /** 
        * @method getHiddenFields
        * @description Returns an <code>&#60;input&#62;</code> element or 
        * array of form elements used to represent the button when its parent 
        * form is submitted.  
        * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-6043025">HTMLInputElement</a>|Array}
        */
        getHiddenFields: function () {
        
            return this._hiddenFields;
        
        },
        
        
        /**
        * @method destroy
        * @description Removes the button's element from its parent element and 
        * removes all event handlers.
        */
        destroy: function () {
        
        
            var oElement = this.get("element"),
                oParentNode = oElement.parentNode,
                oMenu = this._menu,
                aButtons;
        
            if (oMenu) {
        

                if (m_oOverlayManager && m_oOverlayManager.find(oMenu)) {

                    m_oOverlayManager.remove(oMenu);

                }
        
                oMenu.destroy();
        
            }
        
        
            Event.purgeElement(oElement);
            Event.purgeElement(this._button);
            Event.removeListener(document, "mouseup", this._onDocumentMouseUp);
            Event.removeListener(document, "keyup", this._onDocumentKeyUp);
            Event.removeListener(document, "mousedown", 
                this._onDocumentMouseDown);
        
        
            var oForm = this.getForm();
            
            if (oForm) {
        
                Event.removeListener(oForm, "reset", this._onFormReset);
                Event.removeListener(oForm, "submit", this.createHiddenFields);
        
            }


            this.unsubscribeAll();

            if (oParentNode) {

                oParentNode.removeChild(oElement);
            
            }
        
        
            delete m_oButtons[this.get("id")];

            aButtons = Dom.getElementsByClassName(this.CSS_CLASS_NAME, 
                                this.NODE_NAME, oForm); 

            if (Lang.isArray(aButtons) && aButtons.length === 0) {

                Event.removeListener(oForm, "keypress", 
                        YAHOO.widget.Button.onFormKeyPress);

            }

        
        },
        
        
        fireEvent: function (p_sType , p_aArgs) {
        
			var sType = arguments[0];
		
			//  Disabled buttons should not respond to DOM events
		
			if (this.DOM_EVENTS[sType] && this.get("disabled")) {
		
				return;
		
			}
		
			return YAHOO.widget.Button.superclass.fireEvent.apply(this, arguments);
        
        },
        
        
        /**
        * @method toString
        * @description Returns a string representing the button.
        * @return {String}
        */
        toString: function () {
        
            return ("Button " + this.get("id"));
        
        }
    
    });
    
    
    /**
    * @method YAHOO.widget.Button.onFormKeyPress
    * @description "keypress" event handler for the button's form.
    * @param {Event} p_oEvent Object representing the DOM event object passed 
    * back by the event utility (YAHOO.util.Event).
    */
    YAHOO.widget.Button.onFormKeyPress = function (p_oEvent) {
    
        var oTarget = Event.getTarget(p_oEvent),
            nCharCode = Event.getCharCode(p_oEvent),
            sNodeName = oTarget.nodeName && oTarget.nodeName.toUpperCase(),
            sType = oTarget.type,
    
            /*
                Boolean indicating if the form contains any enabled or 
                disabled YUI submit buttons
            */
    
            bFormContainsYUIButtons = false,
    
            oButton,
    
            oYUISubmitButton,   // The form's first, enabled YUI submit button
    
            /*
                 The form's first, enabled HTML submit button that precedes any 
                 YUI submit button
            */
    
            oPrecedingSubmitButton,
            
    
            /*
                 The form's first, enabled HTML submit button that follows a 
                 YUI button
            */
            
            oFollowingSubmitButton; 
    
    
        function isSubmitButton(p_oElement) {
    
            var sId,
                oSrcElement;
    
            switch (p_oElement.nodeName.toUpperCase()) {
    
            case "INPUT":
            case "BUTTON":
            
                if (p_oElement.type == "submit" && !p_oElement.disabled) {
                    
                    if (!bFormContainsYUIButtons && 
                        !oPrecedingSubmitButton) {

                        oPrecedingSubmitButton = p_oElement;

                    }
                    
                    if (oYUISubmitButton && !oFollowingSubmitButton) {
                    
                        oFollowingSubmitButton = p_oElement;
                    
                    }
                
                }

                break;
            

            default:
            
                sId = p_oElement.id;
    
                if (sId) {
    
                    oButton = m_oButtons[sId];
        
                    if (oButton) {

                        bFormContainsYUIButtons = true;
        
                        if (!oButton.get("disabled")) {

                            oSrcElement = oButton.get("srcelement");
    
                            if (!oYUISubmitButton &&
                                (oButton.get("type") == "submit" || 
                                (oSrcElement && oSrcElement.type == "submit"))) 
                            {

                                oYUISubmitButton = oButton;
                            
                            }
                        
                        }
                        
                    }
                
                }

                break;
    
            }
    
        }
    
    
        if (nCharCode == 13 && ((sNodeName == "INPUT" && (sType == "text" || 
            sType == "password" || sType == "checkbox" || sType == "radio" || 
            sType == "file")) || sNodeName == "SELECT"))
        {
    
            Dom.getElementsBy(isSubmitButton, "*", this);
    
    
            if (oPrecedingSubmitButton) {
    
                /*
                     Need to set focus to the first enabled submit button
                     to make sure that IE includes its name and value 
                     in the form's data set.
                */
    
                oPrecedingSubmitButton.focus();
            
            }
            else if (!oPrecedingSubmitButton && oYUISubmitButton) {
    
                if (oFollowingSubmitButton) {
    
                    /*
                        Need to call "preventDefault" to ensure that 
                        the name and value of the regular submit button 
                        following the YUI button doesn't get added to the 
                        form's data set when it is submitted.
                    */
    
                    Event.preventDefault(p_oEvent);
                
                }
    
                oYUISubmitButton.submitForm();
    
            }
            
        }
    
    };
    
    
    /**
    * @method YAHOO.widget.Button.addHiddenFieldsToForm
    * @description Searches the specified form and adds hidden fields for  
    * instances of YAHOO.widget.Button that are of type "radio," "checkbox," 
    * "menu," and "split."
    * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
    * one-html.html#ID-40002357">HTMLFormElement</a>} p_oForm Object reference 
    * for the form to search.
    */
    YAHOO.widget.Button.addHiddenFieldsToForm = function (p_oForm) {
    
        var aButtons = Dom.getElementsByClassName(
                            YAHOO.widget.Button.prototype.CSS_CLASS_NAME, 
                            "*", 
                            p_oForm),
    
            nButtons = aButtons.length,
            oButton,
            sId,
            i;
    
        if (nButtons > 0) {
    
    
            for (i = 0; i < nButtons; i++) {
    
                sId = aButtons[i].id;
    
                if (sId) {
    
                    oButton = m_oButtons[sId];
        
                    if (oButton) {
           
                        oButton.createHiddenFields();
                        
                    }
                
                }
            
            }
    
        }
    
    };
    

    /**
    * @method YAHOO.widget.Button.getButton
    * @description Returns a button with the specified id.
    * @param {String} p_sId String specifying the id of the root node of the 
    * HTML element representing the button to be retrieved.
    * @return {YAHOO.widget.Button}
    */
    YAHOO.widget.Button.getButton = function (p_sId) {

        var oButton = m_oButtons[p_sId];

        if (oButton) {
        
            return oButton;
        
        }

    };
    
    
    // Events
    
    
    /**
    * @event focus
    * @description Fires when the menu item receives focus.  Passes back a  
    * single object representing the original DOM event object passed back by 
    * the event utility (YAHOO.util.Event) when the event was fired.  See 
    * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> 
    * for more information on listening for this event.
    * @type YAHOO.util.CustomEvent
    */
    
    
    /**
    * @event blur
    * @description Fires when the menu item loses the input focus.  Passes back  
    * a single object representing the original DOM event object passed back by 
    * the event utility (YAHOO.util.Event) when the event was fired.  See 
    * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for  
    * more information on listening for this event.
    * @type YAHOO.util.CustomEvent
    */
    
    
    /**
    * @event option
    * @description Fires when the user invokes the button's option.  Passes 
    * back a single object representing the original DOM event (either 
    * "mousedown" or "keydown") that caused the "option" event to fire.  See 
    * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> 
    * for more information on listening for this event.
    * @type YAHOO.util.CustomEvent
    */

})();
(function () {

    // Shorthard for utilities
    
    var Dom = YAHOO.util.Dom,
        Event = YAHOO.util.Event,
        Lang = YAHOO.lang,
        Button = YAHOO.widget.Button,  
    
        // Private collection of radio buttons
    
        m_oButtons = {};



    /**
    * The ButtonGroup class creates a set of buttons that are mutually 
    * exclusive; checking one button in the set will uncheck all others in the 
    * button group.
    * @param {String} p_oElement String specifying the id attribute of the 
    * <code>&#60;div&#62;</code> element of the button group.
    * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
    * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object 
    * specifying the <code>&#60;div&#62;</code> element of the button group.
    * @param {Object} p_oElement Object literal specifying a set of 
    * configuration attributes used to create the button group.
    * @param {Object} p_oAttributes Optional. Object literal specifying a set 
    * of configuration attributes used to create the button group.
    * @namespace YAHOO.widget
    * @class ButtonGroup
    * @constructor
    * @extends YAHOO.util.Element
    */
    YAHOO.widget.ButtonGroup = function (p_oElement, p_oAttributes) {
    
        var fnSuperClass = YAHOO.widget.ButtonGroup.superclass.constructor,
            sNodeName,
            oElement,
            sId;
    
        if (arguments.length == 1 && !Lang.isString(p_oElement) && 
            !p_oElement.nodeName) {
    
            if (!p_oElement.id) {
    
                sId = Dom.generateId();
    
                p_oElement.id = sId;
    
    
            }
    
    
    
            fnSuperClass.call(this, (this._createGroupElement()), p_oElement);
    
        }
        else if (Lang.isString(p_oElement)) {
    
            oElement = Dom.get(p_oElement);
    
            if (oElement) {
            
                if (oElement.nodeName.toUpperCase() == this.NODE_NAME) {
    
            
                    fnSuperClass.call(this, oElement, p_oAttributes);
    
                }
    
            }
        
        }
        else {
    
            sNodeName = p_oElement.nodeName.toUpperCase();
    
            if (sNodeName && sNodeName == this.NODE_NAME) {
        
                if (!p_oElement.id) {
        
                    p_oElement.id = Dom.generateId();
        
        
                }
        
        
                fnSuperClass.call(this, p_oElement, p_oAttributes);
    
            }
    
        }
    
    };
    
    
    YAHOO.extend(YAHOO.widget.ButtonGroup, YAHOO.util.Element, {
    
    
        // Protected properties
        
        
        /** 
        * @property _buttons
        * @description Array of buttons in the button group.
        * @default null
        * @protected
        * @type Array
        */
        _buttons: null,
        
        
        
        // Constants
        
        
        /**
        * @property NODE_NAME
        * @description The name of the tag to be used for the button 
        * group's element. 
        * @default "DIV"
        * @final
        * @type String
        */
        NODE_NAME: "DIV",
        
        
        /**
        * @property CSS_CLASS_NAME
        * @description String representing the CSS class(es) to be applied  
        * to the button group's element.
        * @default "yui-buttongroup"
        * @final
        * @type String
        */
        CSS_CLASS_NAME: "yui-buttongroup",
    
    
    
        // Protected methods
        
        
        /**
        * @method _createGroupElement
        * @description Creates the button group's element.
        * @protected
        * @return {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-22445964">HTMLDivElement</a>}
        */
        _createGroupElement: function () {
        
            var oElement = document.createElement(this.NODE_NAME);
        
            return oElement;
        
        },
        
        
        
        // Protected attribute setter methods
        
        
        /**
        * @method _setDisabled
        * @description Sets the value of the button groups's 
        * "disabled" attribute.
        * @protected
        * @param {Boolean} p_bDisabled Boolean indicating the value for
        * the button group's "disabled" attribute.
        */
        _setDisabled: function (p_bDisabled) {
        
            var nButtons = this.getCount(),
                i;
        
            if (nButtons > 0) {
        
                i = nButtons - 1;
                
                do {
        
                    this._buttons[i].set("disabled", p_bDisabled);
                
                }
                while (i--);
        
            }
        
        },
        
        
        
        // Protected event handlers
        
        
        /**
        * @method _onKeyDown
        * @description "keydown" event handler for the button group.
        * @protected
        * @param {Event} p_oEvent Object representing the DOM event object  
        * passed back by the event utility (YAHOO.util.Event).
        */
        _onKeyDown: function (p_oEvent) {
        
            var oTarget = Event.getTarget(p_oEvent),
                nCharCode = Event.getCharCode(p_oEvent),
                sId = oTarget.parentNode.parentNode.id,
                oButton = m_oButtons[sId],
                nIndex = -1;
        
        
            if (nCharCode == 37 || nCharCode == 38) {
        
                nIndex = (oButton.index === 0) ? 
                            (this._buttons.length - 1) : (oButton.index - 1);
            
            }
            else if (nCharCode == 39 || nCharCode == 40) {
        
                nIndex = (oButton.index === (this._buttons.length - 1)) ? 
                            0 : (oButton.index + 1);
        
            }
        
        
            if (nIndex > -1) {
        
                this.check(nIndex);
                this.getButton(nIndex).focus();
            
            }        
        
        },
        
        
        /**
        * @method _onAppendTo
        * @description "appendTo" event handler for the button group.
        * @protected
        * @param {Event} p_oEvent Object representing the event that was fired.
        */
        _onAppendTo: function (p_oEvent) {
        
            var aButtons = this._buttons,
                nButtons = aButtons.length,
                i;
        
            for (i = 0; i < nButtons; i++) {
        
                aButtons[i].appendTo(this.get("element"));
        
            }
        
        },
        
        
        /**
        * @method _onButtonCheckedChange
        * @description "checkedChange" event handler for each button in the 
        * button group.
        * @protected
        * @param {Event} p_oEvent Object representing the event that was fired.
        * @param {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}  
        * p_oButton Object representing the button that fired the event.
        */
        _onButtonCheckedChange: function (p_oEvent, p_oButton) {
        
            var bChecked = p_oEvent.newValue,
                oCheckedButton = this.get("checkedButton");
        
            if (bChecked && oCheckedButton != p_oButton) {
        
                if (oCheckedButton) {
        
                    oCheckedButton.set("checked", false, true);
        
                }
        
                this.set("checkedButton", p_oButton);
                this.set("value", p_oButton.get("value"));
        
            }
            else if (oCheckedButton && !oCheckedButton.set("checked")) {
        
                oCheckedButton.set("checked", true, true);
        
            }
           
        },
        
        
        
        // Public methods
        
        
        /**
        * @method init
        * @description The ButtonGroup class's initialization method.
        * @param {String} p_oElement String specifying the id attribute of the 
        * <code>&#60;div&#62;</code> element of the button group.
        * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object 
        * specifying the <code>&#60;div&#62;</code> element of the button group.
        * @param {Object} p_oElement Object literal specifying a set of  
        * configuration attributes used to create the button group.
        * @param {Object} p_oAttributes Optional. Object literal specifying a
        * set of configuration attributes used to create the button group.
        */
        init: function (p_oElement, p_oAttributes) {
        
            this._buttons = [];
        
            YAHOO.widget.ButtonGroup.superclass.init.call(this, p_oElement, 
                    p_oAttributes);
        
            this.addClass(this.CSS_CLASS_NAME);
        
        
            var aButtons = this.getElementsByClassName("yui-radio-button");
        
        
            if (aButtons.length > 0) {
        
        
                this.addButtons(aButtons);
        
            }
        
        
        
            function isRadioButton(p_oElement) {
        
                return (p_oElement.type == "radio");
        
            }
        
            aButtons = 
                Dom.getElementsBy(isRadioButton, "input", this.get("element"));
        
        
            if (aButtons.length > 0) {
        
        
                this.addButtons(aButtons);
        
            }
        
            this.on("keydown", this._onKeyDown);
            this.on("appendTo", this._onAppendTo);
        

            var oContainer = this.get("container");

            if (oContainer) {
        
                if (Lang.isString(oContainer)) {
        
                    Event.onContentReady(oContainer, function () {
        
                        this.appendTo(oContainer);            
                    
                    }, null, this);
        
                }
                else {
        
                    this.appendTo(oContainer);
        
                }
        
            }
        
        
        
        },
        
        
        /**
        * @method initAttributes
        * @description Initializes all of the configuration attributes used to  
        * create the button group.
        * @param {Object} p_oAttributes Object literal specifying a set of 
        * configuration attributes used to create the button group.
        */
        initAttributes: function (p_oAttributes) {
        
            var oAttributes = p_oAttributes || {};
        
            YAHOO.widget.ButtonGroup.superclass.initAttributes.call(
                this, oAttributes);
        
        
            /**
            * @attribute name
            * @description String specifying the name for the button group.  
            * This name will be applied to each button in the button group.
            * @default null
            * @type String
            */
            this.setAttributeConfig("name", {
        
                value: oAttributes.name,
                validator: Lang.isString
        
            });
        
        
            /**
            * @attribute disabled
            * @description Boolean indicating if the button group should be 
            * disabled.  Disabling the button group will disable each button 
            * in the button group.  Disabled buttons are dimmed and will not 
            * respond to user input or fire events.
            * @default false
            * @type Boolean
            */
            this.setAttributeConfig("disabled", {
        
                value: (oAttributes.disabled || false),
                validator: Lang.isBoolean,
                method: this._setDisabled
        
            });
        
        
            /**
            * @attribute value
            * @description Object specifying the value for the button group.
            * @default null
            * @type Object
            */
            this.setAttributeConfig("value", {
        
                value: oAttributes.value
        
            });
        
        
            /**
            * @attribute container
            * @description HTML element reference or string specifying the id 
            * attribute of the HTML element that the button group's markup
            * should be rendered into.
            * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
            * level-one-html.html#ID-58190037">HTMLElement</a>|String
            * @default null
            */
            this.setAttributeConfig("container", {
        
                value: oAttributes.container,
                writeOnce: true
        
            });
        
        
            /**
            * @attribute checkedButton
            * @description Reference for the button in the button group that 
            * is checked.
            * @type {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
            * @default null
            */
            this.setAttributeConfig("checkedButton", {
        
                value: null
        
            });
        
        },
        
        
        /**
        * @method addButton
        * @description Adds the button to the button group.
        * @param {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}  
        * p_oButton Object reference for the <a href="YAHOO.widget.Button.html">
        * YAHOO.widget.Button</a> instance to be added to the button group.
        * @param {String} p_oButton String specifying the id attribute of the 
        * <code>&#60;input&#62;</code> or <code>&#60;span&#62;</code> element 
        * to be used to create the button to be added to the button group.
        * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
        * level-one-html.html#ID-6043025">HTMLInputElement</a>|<a href="
        * http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#
        * ID-33759296">HTMLElement</a>} p_oButton Object reference for the 
        * <code>&#60;input&#62;</code> or <code>&#60;span&#62;</code> element 
        * to be used to create the button to be added to the button group.
        * @param {Object} p_oButton Object literal specifying a set of 
        * <a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a> 
        * configuration attributes used to configure the button to be added to 
        * the button group.
        * @return {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>} 
        */
        addButton: function (p_oButton) {
        
            var oButton,
                oButtonElement,
                oGroupElement,
                nIndex,
                sButtonName,
                sGroupName;
        
        
            if (p_oButton instanceof Button && 
                p_oButton.get("type") == "radio") {
        
                oButton = p_oButton;
        
            }
            else if (!Lang.isString(p_oButton) && !p_oButton.nodeName) {
        
                p_oButton.type = "radio";
        
                oButton = new Button(p_oButton);

            }
            else {
        
                oButton = new Button(p_oButton, { type: "radio" });
        
            }
        
        
            if (oButton) {
        
                nIndex = this._buttons.length;
                sButtonName = oButton.get("name");
                sGroupName = this.get("name");
        
                oButton.index = nIndex;
        
                this._buttons[nIndex] = oButton;
                m_oButtons[oButton.get("id")] = oButton;
        
        
                if (sButtonName != sGroupName) {
        
                    oButton.set("name", sGroupName);
                
                }
        
        
                if (this.get("disabled")) {
        
                    oButton.set("disabled", true);
        
                }
        
        
                if (oButton.get("checked")) {
        
                    this.set("checkedButton", oButton);
        
                }

                
                oButtonElement = oButton.get("element");
                oGroupElement = this.get("element");
                
                if (oButtonElement.parentNode != oGroupElement) {
                
                    oGroupElement.appendChild(oButtonElement);
                
                }
        
                
                oButton.on("checkedChange", 
                    this._onButtonCheckedChange, oButton, this);
        
        
                return oButton;
        
            }
        
        },
        
        
        /**
        * @method addButtons
        * @description Adds the array of buttons to the button group.
        * @param {Array} p_aButtons Array of <a href="YAHOO.widget.Button.html">
        * YAHOO.widget.Button</a> instances to be added 
        * to the button group.
        * @param {Array} p_aButtons Array of strings specifying the id 
        * attribute of the <code>&#60;input&#62;</code> or <code>&#60;span&#62;
        * </code> elements to be used to create the buttons to be added to the 
        * button group.
        * @param {Array} p_aButtons Array of object references for the 
        * <code>&#60;input&#62;</code> or <code>&#60;span&#62;</code> elements 
        * to be used to create the buttons to be added to the button group.
        * @param {Array} p_aButtons Array of object literals, each containing
        * a set of <a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>  
        * configuration attributes used to configure each button to be added 
        * to the button group.
        * @return {Array}
        */
        addButtons: function (p_aButtons) {
    
            var nButtons,
                oButton,
                aButtons,
                i;
        
            if (Lang.isArray(p_aButtons)) {
            
                nButtons = p_aButtons.length;
                aButtons = [];
        
                if (nButtons > 0) {
        
                    for (i = 0; i < nButtons; i++) {
        
                        oButton = this.addButton(p_aButtons[i]);
                        
                        if (oButton) {
        
                            aButtons[aButtons.length] = oButton;
        
                        }
                    
                    }
        
                    if (aButtons.length > 0) {
        
        
                        return aButtons;
        
                    }
                
                }
        
            }
        
        },
        
        
        /**
        * @method removeButton
        * @description Removes the button at the specified index from the 
        * button group.
        * @param {Number} p_nIndex Number specifying the index of the button 
        * to be removed from the button group.
        */
        removeButton: function (p_nIndex) {
        
            var oButton = this.getButton(p_nIndex),
                nButtons,
                i;
            
            if (oButton) {
        
        
                this._buttons.splice(p_nIndex, 1);
                delete m_oButtons[oButton.get("id")];
        
                oButton.removeListener("checkedChange", 
                    this._onButtonCheckedChange);

                oButton.destroy();
        
        
                nButtons = this._buttons.length;
                
                if (nButtons > 0) {
        
                    i = this._buttons.length - 1;
                    
                    do {
        
                        this._buttons[i].index = i;
        
                    }
                    while (i--);
                
                }
        
        
            }
        
        },
        
        
        /**
        * @method getButton
        * @description Returns the button at the specified index.
        * @param {Number} p_nIndex The index of the button to retrieve from the 
        * button group.
        * @return {<a href="YAHOO.widget.Button.html">YAHOO.widget.Button</a>}
        */
        getButton: function (p_nIndex) {
        
            if (Lang.isNumber(p_nIndex)) {
        
                return this._buttons[p_nIndex];
        
            }
        
        },
        
        
        /**
        * @method getButtons
        * @description Returns an array of the buttons in the button group.
        * @return {Array}
        */
        getButtons: function () {
        
            return this._buttons;
        
        },
        
        
        /**
        * @method getCount
        * @description Returns the number of buttons in the button group.
        * @return {Number}
        */
        getCount: function () {
        
            return this._buttons.length;
        
        },
        
        
        /**
        * @method focus
        * @description Sets focus to the button at the specified index.
        * @param {Number} p_nIndex Number indicating the index of the button 
        * to focus. 
        */
        focus: function (p_nIndex) {
        
            var oButton,
                nButtons,
                i;
        
            if (Lang.isNumber(p_nIndex)) {
        
                oButton = this._buttons[p_nIndex];
                
                if (oButton) {
        
                    oButton.focus();
        
                }
            
            }
            else {
        
                nButtons = this.getCount();
        
                for (i = 0; i < nButtons; i++) {
        
                    oButton = this._buttons[i];
        
                    if (!oButton.get("disabled")) {
        
                        oButton.focus();
                        break;
        
                    }
        
                }
        
            }
        
        },
        
        
        /**
        * @method check
        * @description Checks the button at the specified index.
        * @param {Number} p_nIndex Number indicating the index of the button 
        * to check. 
        */
        check: function (p_nIndex) {
        
            var oButton = this.getButton(p_nIndex);
            
            if (oButton) {
        
                oButton.set("checked", true);
            
            }
        
        },
        
        
        /**
        * @method destroy
        * @description Removes the button group's element from its parent 
        * element and removes all event handlers.
        */
        destroy: function () {
        
        
            var nButtons = this._buttons.length,
                oElement = this.get("element"),
                oParentNode = oElement.parentNode,
                i;
            
            if (nButtons > 0) {
        
                i = this._buttons.length - 1;
        
                do {
        
                    this._buttons[i].destroy();
        
                }
                while (i--);
            
            }
        
        
            Event.purgeElement(oElement);
            
        
            oParentNode.removeChild(oElement);
        
        },
        
        
        /**
        * @method toString
        * @description Returns a string representing the button group.
        * @return {String}
        */
        toString: function () {
        
            return ("ButtonGroup " + this.get("id"));
        
        }
    
    });

})();
YAHOO.register("button", YAHOO.widget.Button, {version: "2.5.2", build: "1076"});
/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.5.2
*/
(function() {
    /**
    * @private
    **/
var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event,
    Lang = YAHOO.lang;
    /**
     * @description <p>Creates a rich custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar</p>
     * @class ToolbarButtonAdvanced
     * @namespace YAHOO.widget
     * @requires yahoo, dom, element, event, container_core, menu, button
     * @beta
     * 
     * Provides a toolbar button based on the button and menu widgets.
     * @constructor
     * @param {String/HTMLElement} el The element to turn into a button.
     * @param {Object} attrs Object liternal containing configuration parameters.
    */
    if (YAHOO.widget.Button) {
        YAHOO.widget.ToolbarButtonAdvanced = YAHOO.widget.Button;
        /**
        * @property buttonType
        * @private
        * @description Tells if the Button is a Rich Button or a Simple Button
        */
        YAHOO.widget.ToolbarButtonAdvanced.prototype.buttonType = 'rich';
        /**
        * @method checkValue
        * @param {String} value The value of the option that we want to mark as selected
        * @description Select an option by value
        */
        YAHOO.widget.ToolbarButtonAdvanced.prototype.checkValue = function(value) {
            var _menuItems = this.getMenu().getItems();
            if (_menuItems.length === 0) {
                this.getMenu()._onBeforeShow();
                _menuItems = this.getMenu().getItems();
            }
            for (var i = 0; i < _menuItems.length; i++) {
                _menuItems[i].cfg.setProperty('checked', false);
                if (_menuItems[i].value == value) {
                    _menuItems[i].cfg.setProperty('checked', true);
                }
            }      
        };
    } else {
        YAHOO.widget.ToolbarButtonAdvanced = function() {};
    }


    /**
     * @description <p>Creates a basic custom Toolbar Button. Primarily used with the Rich Text Editor's Toolbar</p>
     * @class ToolbarButton
     * @namespace YAHOO.widget
     * @requires yahoo, dom, element, event
     * @Extends YAHOO.util.Element
     * @beta
     * 
     * Provides a toolbar button based on the button and menu widgets, <select> elements are used in place of menu's.
     * @constructor
     * @param {String/HTMLElement} el The element to turn into a button.
     * @param {Object} attrs Object liternal containing configuration parameters.
    */

    YAHOO.widget.ToolbarButton = function(el, attrs) {
        
        if (Lang.isObject(arguments[0]) && !Dom.get(el).nodeType) {
            attrs = el;
        }
        var local_attrs = (attrs || {});

        var oConfig = {
            element: null,
            attributes: local_attrs
        };

        if (!oConfig.attributes.type) {
            oConfig.attributes.type = 'push';
        }
        
        oConfig.element = document.createElement('span');
        oConfig.element.setAttribute('unselectable', 'on');
        oConfig.element.className = 'yui-button yui-' + oConfig.attributes.type + '-button';
        oConfig.element.innerHTML = '<span class="first-child"><a href="#">LABEL</a></span>';
        oConfig.element.firstChild.firstChild.tabIndex = '-1';
        oConfig.attributes.id = Dom.generateId();

        YAHOO.widget.ToolbarButton.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
    };

    YAHOO.extend(YAHOO.widget.ToolbarButton, YAHOO.util.Element, {
        /**
        * @property buttonType
        * @private
        * @description Tells if the Button is a Rich Button or a Simple Button
        */
        buttonType: 'normal',
        /**
        * @method _handleMouseOver
        * @private
        * @description Adds classes to the button elements on mouseover (hover)
        */
        _handleMouseOver: function() {
            if (!this.get('disabled')) {
                this.addClass('yui-button-hover');
                this.addClass('yui-' + this.get('type') + '-button-hover');
            }
        },
        /**
        * @method _handleMouseOut
        * @private
        * @description Removes classes from the button elements on mouseout (hover)
        */
        _handleMouseOut: function() {
            this.removeClass('yui-button-hover');
            this.removeClass('yui-' + this.get('type') + '-button-hover');
        },
        /**
        * @method checkValue
        * @param {String} value The value of the option that we want to mark as selected
        * @description Select an option by value
        */
        checkValue: function(value) {
            if (this.get('type') == 'menu') {
                var opts = this._button.options;
                for (var i = 0; i < opts.length; i++) {
                    if (opts[i].value == value) {
                        opts.selectedIndex = i;
                    }
                }
            }
        },
        /** 
        * @method init
        * @description The ToolbarButton class's initialization method
        */        
        init: function(p_oElement, p_oAttributes) {
            YAHOO.widget.ToolbarButton.superclass.init.call(this, p_oElement, p_oAttributes);

            this.on('mouseover', this._handleMouseOver, this, true);
            this.on('mouseout', this._handleMouseOut, this, true);
        },
        /**
        * @method initAttributes
        * @description Initializes all of the configuration attributes used to create 
        * the toolbar.
        * @param {Object} attr Object literal specifying a set of 
        * configuration attributes used to create the toolbar.
        */        
        initAttributes: function(attr) {
            YAHOO.widget.ToolbarButton.superclass.initAttributes.call(this, attr);
            /**
            * @attribute value
            * @description The value of the button
            * @type String
            */            
            this.setAttributeConfig('value', {
                value: attr.value
            });
            /**
            * @attribute menu
            * @description The menu attribute, see YAHOO.widget.Button
            * @type Object
            */            
            this.setAttributeConfig('menu', {
                value: attr.menu || false
            });
            /**
            * @attribute type
            * @description The type of button to create: push, menu, color, select, spin
            * @type String
            */            
            this.setAttributeConfig('type', {
                value: attr.type,
                writeOnce: true,
                method: function(type) {
                    var el, opt;
                    if (!this._button) {
                        this._button = this.get('element').getElementsByTagName('a')[0];
                    }
                    switch (type) {
                        case 'select':
                        case 'menu':
                            el = document.createElement('select');
                            var menu = this.get('menu');
                            for (var i = 0; i < menu.length; i++) {
                                opt = document.createElement('option');
                                opt.innerHTML = menu[i].text;
                                opt.value = menu[i].value;
                                if (menu[i].checked) {
                                    opt.selected = true;
                                }
                                el.appendChild(opt);
                            }
                            this._button.parentNode.replaceChild(el, this._button);
                            Event.on(el, 'change', this._handleSelect, this, true);
                            this._button = el;
                            break;
                    }
                }
            });

            /**
            * @attribute disabled
            * @description Set the button into a disabled state
            * @type String
            */            
            this.setAttributeConfig('disabled', {
                value: attr.disabled || false,
                method: function(disabled) {
                    if (disabled) {
                        this.addClass('yui-button-disabled');
                        this.addClass('yui-' + this.get('type') + '-button-disabled');
                        if (this.get('type') == 'color') {
                            this.get('menu').hide();
                        }                        
                    } else {
                        this.removeClass('yui-button-disabled');
                        this.removeClass('yui-' + this.get('type') + '-button-disabled');
                    }
                    if (this.get('type') == 'menu') {
                        this._button.disabled = disabled;
                    }
                }
            });

            /**
            * @attribute label
            * @description The text label for the button
            * @type String
            */            
            this.setAttributeConfig('label', {
                value: attr.label,
                method: function(label) {
                    if (!this._button) {
                        this._button = this.get('element').getElementsByTagName('a')[0];
                    }
                    if (this.get('type') == 'push') {
                        this._button.innerHTML = label;
                    }
                }
            });

            /**
            * @attribute title
            * @description The title of the button
            * @type String
            */            
            this.setAttributeConfig('title', {
                value: attr.title
            });

            /**
            * @config container
            * @description The container that the button is rendered to, handled by Toolbar
            * @type String
            */            
            this.setAttributeConfig('container', {
                value: null,
                writeOnce: true,
                method: function(cont) {
                    this.appendTo(cont);
                }
            });

        },
        /** 
        * @private
        * @method _handleSelect
        * @description The event fired when a change event gets fired on a select element
        * @param {Event} ev The change event.
        */        
        _handleSelect: function(ev) {
            var tar = Event.getTarget(ev);
            var value = tar.options[tar.selectedIndex].value;
            this.fireEvent('change', {type: 'change', value: value });
        },
        /** 
        * @method getMenu
        * @description A stub function to mimic YAHOO.widget.Button's getMenu method
        */        
        getMenu: function() {
            return this.get('menu');
        },
        /** 
        * @method destroy
        * @description Destroy the button
        */        
        destroy: function() {
            Event.purgeElement(this.get('element'), true);
            this.get('element').parentNode.removeChild(this.get('element'));
            //Brutal Object Destroy
            for (var i in this) {
                if (Lang.hasOwnProperty(this, i)) {
                    this[i] = null;
                }
            }       
        },
        /** 
        * @method fireEvent
        * @description Overridden fireEvent method to prevent DOM events from firing if the button is disabled.
        */        
        fireEvent: function (p_sType , p_aArgs) {
            //  Disabled buttons should not respond to DOM events
            if (this.DOM_EVENTS[p_sType] && this.get('disabled')) {
                return;
            }
        
            YAHOO.widget.ToolbarButton.superclass.fireEvent.call(this, p_sType, p_aArgs);
        },
        /**
        * @method toString
        * @description Returns a string representing the toolbar.
        * @return {String}
        */        
        toString: function() {
            return 'ToolbarButton (' + this.get('id') + ')';
        }
        
    });
})();
/**
 * @description <p>Creates a rich Toolbar widget based on Button. Primarily used with the Rich Text Editor</p>
 * @namespace YAHOO.widget
 * @requires yahoo, dom, element, event, toolbarbutton
 * @optional container_core, dragdrop
 * @beta
 */
(function() {
    /**
    * @private
    **/
var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event,
    Lang = YAHOO.lang;
    
    var getButton = function(id) {
        var button = id;
        if (Lang.isString(id)) {
            button = this.getButtonById(id);
        }
        if (Lang.isNumber(id)) {
            button = this.getButtonByIndex(id);
        }
        if ((!(button instanceof YAHOO.widget.ToolbarButton)) && (!(button instanceof YAHOO.widget.ToolbarButtonAdvanced))) {
            button = this.getButtonByValue(id);
        }
        if ((button instanceof YAHOO.widget.ToolbarButton) || (button instanceof YAHOO.widget.ToolbarButtonAdvanced)) {
            return button;
        }
        return false;
    };

    /**
     * Provides a rich toolbar widget based on the button and menu widgets
     * @constructor
     * @class Toolbar
     * @extends YAHOO.util.Element
     * @param {String/HTMLElement} el The element to turn into a toolbar.
     * @param {Object} attrs Object liternal containing configuration parameters.
    */
    YAHOO.widget.Toolbar = function(el, attrs) {
        
        if (Lang.isObject(arguments[0]) && !Dom.get(el).nodeType) {
            attrs = el;
        }
        var local_attrs = (attrs || {});

        var oConfig = {
            element: null,
            attributes: local_attrs
        };
        
        
        if (Lang.isString(el) && Dom.get(el)) {
            oConfig.element = Dom.get(el);
        } else if (Lang.isObject(el) && Dom.get(el) && Dom.get(el).nodeType) {  
            oConfig.element = Dom.get(el);
        }
        

        if (!oConfig.element) {
            oConfig.element = document.createElement('DIV');
            oConfig.element.id = Dom.generateId();
            
            if (local_attrs.container && Dom.get(local_attrs.container)) {
                Dom.get(local_attrs.container).appendChild(oConfig.element);
            }
        }
        

        if (!oConfig.element.id) {
            oConfig.element.id = ((Lang.isString(el)) ? el : Dom.generateId());
        }
        
        var fs = document.createElement('fieldset');
        var lg = document.createElement('legend');
        lg.innerHTML = 'Toolbar';
        fs.appendChild(lg);
        
        var cont = document.createElement('DIV');
        oConfig.attributes.cont = cont;
        Dom.addClass(cont, 'yui-toolbar-subcont');
        fs.appendChild(cont);
        oConfig.element.appendChild(fs);

        oConfig.element.tabIndex = -1;

        
        oConfig.attributes.element = oConfig.element;
        oConfig.attributes.id = oConfig.element.id;

        YAHOO.widget.Toolbar.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
         
    };

    /**
    * @method _addMenuClasses
    * @private
    * @description This method is called from Menu's renderEvent to add a few more classes to the menu items
    * @param {String} ev The event that fired.
    * @param {Array} na Array of event information.
    * @param {Object} o Button config object. 
    */

    function _addMenuClasses(ev, na, o) {
        Dom.addClass(this.element, 'yui-toolbar-' + o.get('value') + '-menu');
        if (Dom.hasClass(o._button.parentNode.parentNode, 'yui-toolbar-select')) {
            Dom.addClass(this.element, 'yui-toolbar-select-menu');
        }
        var items = this.getItems();
        for (var i = 0; i < items.length; i++) {
            Dom.addClass(items[i].element, 'yui-toolbar-' + o.get('value') + '-' + ((items[i].value) ? items[i].value.replace(/ /g, '-').toLowerCase() : items[i]._oText.nodeValue.replace(/ /g, '-').toLowerCase()));
            Dom.addClass(items[i].element, 'yui-toolbar-' + o.get('value') + '-' + ((items[i].value) ? items[i].value.replace(/ /g, '-') : items[i]._oText.nodeValue.replace(/ /g, '-')));
        }
    }

    YAHOO.extend(YAHOO.widget.Toolbar, YAHOO.util.Element, {
        /** 
        * @property buttonType
        * @description The default button to use
        * @type Object
        */
        buttonType: YAHOO.widget.ToolbarButton,
        /** 
        * @property dd
        * @description The DragDrop instance associated with the Toolbar
        * @type Object
        */
        dd: null,
        /** 
        * @property _colorData
        * @description Object reference containing colors hex and text values.
        * @type Object
        */
        _colorData: {
/* {{{ _colorData */
    '#111111': 'Obsidian',
    '#2D2D2D': 'Dark Gray',
    '#434343': 'Shale',
    '#5B5B5B': 'Flint',
    '#737373': 'Gray',
    '#8B8B8B': 'Concrete',
    '#A2A2A2': 'Gray',
    '#B9B9B9': 'Titanium',
    '#000000': 'Black',
    '#D0D0D0': 'Light Gray',
    '#E6E6E6': 'Silver',
    '#FFFFFF': 'White',
    '#BFBF00': 'Pumpkin',
    '#FFFF00': 'Yellow',
    '#FFFF40': 'Banana',
    '#FFFF80': 'Pale Yellow',
    '#FFFFBF': 'Butter',
    '#525330': 'Raw Siena',
    '#898A49': 'Mildew',
    '#AEA945': 'Olive',
    '#7F7F00': 'Paprika',
    '#C3BE71': 'Earth',
    '#E0DCAA': 'Khaki',
    '#FCFAE1': 'Cream',
    '#60BF00': 'Cactus',
    '#80FF00': 'Chartreuse',
    '#A0FF40': 'Green',
    '#C0FF80': 'Pale Lime',
    '#DFFFBF': 'Light Mint',
    '#3B5738': 'Green',
    '#668F5A': 'Lime Gray',
    '#7F9757': 'Yellow',
    '#407F00': 'Clover',
    '#8A9B55': 'Pistachio',
    '#B7C296': 'Light Jade',
    '#E6EBD5': 'Breakwater',
    '#00BF00': 'Spring Frost',
    '#00FF80': 'Pastel Green',
    '#40FFA0': 'Light Emerald',
    '#80FFC0': 'Sea Foam',
    '#BFFFDF': 'Sea Mist',
    '#033D21': 'Dark Forrest',
    '#438059': 'Moss',
    '#7FA37C': 'Medium Green',
    '#007F40': 'Pine',
    '#8DAE94': 'Yellow Gray Green',
    '#ACC6B5': 'Aqua Lung',
    '#DDEBE2': 'Sea Vapor',
    '#00BFBF': 'Fog',
    '#00FFFF': 'Cyan',
    '#40FFFF': 'Turquoise Blue',
    '#80FFFF': 'Light Aqua',
    '#BFFFFF': 'Pale Cyan',
    '#033D3D': 'Dark Teal',
    '#347D7E': 'Gray Turquoise',
    '#609A9F': 'Green Blue',
    '#007F7F': 'Seaweed',
    '#96BDC4': 'Green Gray',
    '#B5D1D7': 'Soapstone',
    '#E2F1F4': 'Light Turquoise',
    '#0060BF': 'Summer Sky',
    '#0080FF': 'Sky Blue',
    '#40A0FF': 'Electric Blue',
    '#80C0FF': 'Light Azure',
    '#BFDFFF': 'Ice Blue',
    '#1B2C48': 'Navy',
    '#385376': 'Biscay',
    '#57708F': 'Dusty Blue',
    '#00407F': 'Sea Blue',
    '#7792AC': 'Sky Blue Gray',
    '#A8BED1': 'Morning Sky',
    '#DEEBF6': 'Vapor',
    '#0000BF': 'Deep Blue',
    '#0000FF': 'Blue',
    '#4040FF': 'Cerulean Blue',
    '#8080FF': 'Evening Blue',
    '#BFBFFF': 'Light Blue',
    '#212143': 'Deep Indigo',
    '#373E68': 'Sea Blue',
    '#444F75': 'Night Blue',
    '#00007F': 'Indigo Blue',
    '#585E82': 'Dockside',
    '#8687A4': 'Blue Gray',
    '#D2D1E1': 'Light Blue Gray',
    '#6000BF': 'Neon Violet',
    '#8000FF': 'Blue Violet',
    '#A040FF': 'Violet Purple',
    '#C080FF': 'Violet Dusk',
    '#DFBFFF': 'Pale Lavender',
    '#302449': 'Cool Shale',
    '#54466F': 'Dark Indigo',
    '#655A7F': 'Dark Violet',
    '#40007F': 'Violet',
    '#726284': 'Smoky Violet',
    '#9E8FA9': 'Slate Gray',
    '#DCD1DF': 'Violet White',
    '#BF00BF': 'Royal Violet',
    '#FF00FF': 'Fuchsia',
    '#FF40FF': 'Magenta',
    '#FF80FF': 'Orchid',
    '#FFBFFF': 'Pale Magenta',
    '#4A234A': 'Dark Purple',
    '#794A72': 'Medium Purple',
    '#936386': 'Cool Granite',
    '#7F007F': 'Purple',
    '#9D7292': 'Purple Moon',
    '#C0A0B6': 'Pale Purple',
    '#ECDAE5': 'Pink Cloud',
    '#BF005F': 'Hot Pink',
    '#FF007F': 'Deep Pink',
    '#FF409F': 'Grape',
    '#FF80BF': 'Electric Pink',
    '#FFBFDF': 'Pink',
    '#451528': 'Purple Red',
    '#823857': 'Purple Dino',
    '#A94A76': 'Purple Gray',
    '#7F003F': 'Rose',
    '#BC6F95': 'Antique Mauve',
    '#D8A5BB': 'Cool Marble',
    '#F7DDE9': 'Pink Granite',
    '#C00000': 'Apple',
    '#FF0000': 'Fire Truck',
    '#FF4040': 'Pale Red',
    '#FF8080': 'Salmon',
    '#FFC0C0': 'Warm Pink',
    '#441415': 'Sepia',
    '#82393C': 'Rust',
    '#AA4D4E': 'Brick',
    '#800000': 'Brick Red',
    '#BC6E6E': 'Mauve',
    '#D8A3A4': 'Shrimp Pink',
    '#F8DDDD': 'Shell Pink',
    '#BF5F00': 'Dark Orange',
    '#FF7F00': 'Orange',
    '#FF9F40': 'Grapefruit',
    '#FFBF80': 'Canteloupe',
    '#FFDFBF': 'Wax',
    '#482C1B': 'Dark Brick',
    '#855A40': 'Dirt',
    '#B27C51': 'Tan',
    '#7F3F00': 'Nutmeg',
    '#C49B71': 'Mustard',
    '#E1C4A8': 'Pale Tan',
    '#FDEEE0': 'Marble'
/* }}} */
        },
        /** 
        * @property _colorPicker
        * @description The HTML Element containing the colorPicker
        * @type HTMLElement
        */
        _colorPicker: null,
        /** 
        * @property STR_COLLAPSE
        * @description String for Toolbar Collapse Button
        * @type String
        */
        STR_COLLAPSE: 'Collapse Toolbar',
        /** 
        * @property STR_SPIN_LABEL
        * @description String for spinbutton dynamic label. Note the {VALUE} will be replaced with YAHOO.lang.substitute
        * @type String
        */
        STR_SPIN_LABEL: 'Spin Button with value {VALUE}. Use Control Shift Up Arrow and Control Shift Down arrow keys to increase or decrease the value.',
        /** 
        * @property STR_SPIN_UP
        * @description String for spinbutton up
        * @type String
        */
        STR_SPIN_UP: 'Click to increase the value of this input',
        /** 
        * @property STR_SPIN_DOWN
        * @description String for spinbutton down
        * @type String
        */
        STR_SPIN_DOWN: 'Click to decrease the value of this input',
        /** 
        * @property _titlebar
        * @description Object reference to the titlebar
        * @type HTMLElement
        */
        _titlebar: null,
        /** 
        * @property browser
        * @description Standard browser detection
        * @type Object
        */
        browser: YAHOO.env.ua,
        /**
        * @protected
        * @property _buttonList
        * @description Internal property list of current buttons in the toolbar
        * @type Array
        */
        _buttonList: null,
        /**
        * @protected
        * @property _buttonGroupList
        * @description Internal property list of current button groups in the toolbar
        * @type Array
        */
        _buttonGroupList: null,
        /**
        * @protected
        * @property _sep
        * @description Internal reference to the separator HTML Element for cloning
        * @type HTMLElement
        */
        _sep: null,
        /**
        * @protected
        * @property _sepCount
        * @description Internal refernce for counting separators, so we can give them a useful class name for styling
        * @type Number
        */
        _sepCount: null,
        /**
        * @protected
        * @property draghandle
        * @type HTMLElement
        */
        _dragHandle: null,
        /**
        * @protected
        * @property _toolbarConfigs
        * @type Object
        */
        _toolbarConfigs: {
            renderer: true
        },
        /**
        * @protected
        * @property CLASS_CONTAINER
        * @description Default CSS class to apply to the toolbar container element
        * @type String
        */
        CLASS_CONTAINER: 'yui-toolbar-container',
        /**
        * @protected
        * @property CLASS_DRAGHANDLE
        * @description Default CSS class to apply to the toolbar's drag handle element
        * @type String
        */
        CLASS_DRAGHANDLE: 'yui-toolbar-draghandle',
        /**
        * @protected
        * @property CLASS_SEPARATOR
        * @description Default CSS class to apply to all separators in the toolbar
        * @type String
        */
        CLASS_SEPARATOR: 'yui-toolbar-separator',
        /**
        * @protected
        * @property CLASS_DISABLED
        * @description Default CSS class to apply when the toolbar is disabled
        * @type String
        */
        CLASS_DISABLED: 'yui-toolbar-disabled',
        /**
        * @protected
        * @property CLASS_PREFIX
        * @description Default prefix for dynamically created class names
        * @type String
        */
        CLASS_PREFIX: 'yui-toolbar',
        /** 
        * @method init
        * @description The Toolbar class's initialization method
        */
        init: function(p_oElement, p_oAttributes) {
            YAHOO.widget.Toolbar.superclass.init.call(this, p_oElement, p_oAttributes);

        },
        /**
        * @method initAttributes
        * @description Initializes all of the configuration attributes used to create 
        * the toolbar.
        * @param {Object} attr Object literal specifying a set of 
        * configuration attributes used to create the toolbar.
        */
        initAttributes: function(attr) {
            YAHOO.widget.Toolbar.superclass.initAttributes.call(this, attr);
            this.addClass(this.CLASS_CONTAINER);

            /**
            * @attribute buttonType
            * @description The buttonType to use (advanced or basic)
            * @type String
            */
            this.setAttributeConfig('buttonType', {
                value: attr.buttonType || 'basic',
                writeOnce: true,
                validator: function(type) {
                    switch (type) {
                        case 'advanced':
                        case 'basic':
                            return true;
                    }
                    return false;
                },
                method: function(type) {
                    if (type == 'advanced') {
                        if (YAHOO.widget.Button) {
                            this.buttonType = YAHOO.widget.ToolbarButtonAdvanced;
                        } else {
                            this.buttonType = YAHOO.widget.ToolbarButton;
                        }
                    } else {
                        this.buttonType = YAHOO.widget.ToolbarButton;
                    }
                }
            });


            /**
            * @attribute buttons
            * @description Object specifying the buttons to include in the toolbar
            * Example:
            * <code><pre>
            * {
            *   { id: 'b3', type: 'button', label: 'Underline', value: 'underline' },
            *   { type: 'separator' },
            *   { id: 'b4', type: 'menu', label: 'Align', value: 'align',
            *       menu: [
            *           { text: "Left", value: 'alignleft' },
            *           { text: "Center", value: 'aligncenter' },
            *           { text: "Right", value: 'alignright' }
            *       ]
            *   }
            * }
            * </pre></code>
            * @type Array
            */
            
            this.setAttributeConfig('buttons', {
                value: [],
                writeOnce: true,
                method: function(data) {
                    for (var i in data) {
                        if (Lang.hasOwnProperty(data, i)) {
                            if (data[i].type == 'separator') {
                                this.addSeparator();
                            } else if (data[i].group !== undefined) {
                                this.addButtonGroup(data[i]);
                            } else {
                                this.addButton(data[i]);
                            }
                        }
                    }
                }
            });

            /**
            * @attribute disabled
            * @description Boolean indicating if the toolbar should be disabled. It will also disable the draggable attribute if it is on.
            * @default false
            * @type Boolean
            */
            this.setAttributeConfig('disabled', {
                value: false,
                method: function(disabled) {
                    if (this.get('disabled') === disabled) {
                        return false;
                    }
                    if (disabled) {
                        this.addClass(this.CLASS_DISABLED);
                        this.set('draggable', false);
                        this.disableAllButtons();
                    } else {
                        this.removeClass(this.CLASS_DISABLED);
                        if (this._configs.draggable._initialConfig.value) {
                            //Draggable by default, set it back
                            this.set('draggable', true);
                        }
                        this.resetAllButtons();
                    }
                }
            });

            /**
            * @config cont
            * @description The container for the toolbar.
            * @type HTMLElement
            */
            this.setAttributeConfig('cont', {
                value: attr.cont,
                readOnly: true
            });


            /**
            * @attribute grouplabels
            * @description Boolean indicating if the toolbar should show the group label's text string.
            * @default true
            * @type Boolean
            */
            this.setAttributeConfig('grouplabels', {
                value: ((attr.grouplabels === false) ? false : true),
                method: function(grouplabels) {
                    if (grouplabels) {
                        Dom.removeClass(this.get('cont'), (this.CLASS_PREFIX + '-nogrouplabels'));
                    } else {
                        Dom.addClass(this.get('cont'), (this.CLASS_PREFIX + '-nogrouplabels'));
                    }
                }
            });
            /**
            * @attribute titlebar
            * @description Boolean indicating if the toolbar should have a titlebar. If
            * passed a string, it will use that as the titlebar text
            * @default false
            * @type Boolean or String
            */
            this.setAttributeConfig('titlebar', {
                value: false,
                method: function(titlebar) {
                    if (titlebar) {
                        if (this._titlebar && this._titlebar.parentNode) {
                            this._titlebar.parentNode.removeChild(this._titlebar);
                        }
                        this._titlebar = document.createElement('DIV');
                        this._titlebar.tabIndex = '-1';
                        Event.on(this._titlebar, 'focus', function() {
                            this._handleFocus();
                        }, this, true);
                        Dom.addClass(this._titlebar, this.CLASS_PREFIX + '-titlebar');
                        if (Lang.isString(titlebar)) {
                            var h2 = document.createElement('h2');
                            h2.tabIndex = '-1';
                            h2.innerHTML = '<a href="#" tabIndex="0">' + titlebar + '</a>';
                            this._titlebar.appendChild(h2);
                            Event.on(h2.firstChild, 'click', function(ev) {
                                Event.stopEvent(ev);
                            });
                            Event.on([h2, h2.firstChild], 'focus', function() {
                                this._handleFocus();
                            }, this, true);
                        }
                        if (this.get('firstChild')) {
                            this.insertBefore(this._titlebar, this.get('firstChild'));
                        } else {
                            this.appendChild(this._titlebar);
                        }
                        if (this.get('collapse')) {
                            this.set('collapse', true);
                        }
                    } else if (this._titlebar) {
                        if (this._titlebar && this._titlebar.parentNode) {
                            this._titlebar.parentNode.removeChild(this._titlebar);
                        }
                    }
                }
            });


            /**
            * @attribute collapse
            * @description Boolean indicating if the the titlebar should have a collapse button.
            * The collapse button will not remove the toolbar, it will minimize it to the titlebar
            * @default false
            * @type Boolean
            */
            this.setAttributeConfig('collapse', {
                value: false,
                method: function(collapse) {
                    if (this._titlebar) {
                        var collapseEl = null;
                        var el = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
                        if (collapse) {
                            if (el.length > 0) {
                                //There is already a collapse button
                                return true;
                            }
                            collapseEl = document.createElement('SPAN');
                            collapseEl.innerHTML = 'X';
                            collapseEl.title = this.STR_COLLAPSE;

                            Dom.addClass(collapseEl, 'collapse');
                            this._titlebar.appendChild(collapseEl);
                            Event.addListener(collapseEl, 'click', function() {
                                if (Dom.hasClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed')) {
                                    this.collapse(false); //Expand Toolbar
                                } else {
                                    this.collapse(); //Collapse Toolbar
                                }
                            }, this, true);
                        } else {
                            collapseEl = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
                            if (collapseEl[0]) {
                                if (Dom.hasClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed')) {
                                    //We are closed, reopen the titlebar..
                                    this.collapse(false); //Expand Toolbar
                                }
                                collapseEl[0].parentNode.removeChild(collapseEl[0]);
                            }
                        }
                    }
                }
            });

            /**
            * @attribute draggable
            * @description Boolean indicating if the toolbar should be draggable.  
            * @default false
            * @type Boolean
            */

            this.setAttributeConfig('draggable', {
                value: (attr.draggable || false),
                method: function(draggable) {
                    if (draggable && !this.get('titlebar')) {
                        if (!this._dragHandle) {
                            this._dragHandle = document.createElement('SPAN');
                            this._dragHandle.innerHTML = '|';
                            this._dragHandle.setAttribute('title', 'Click to drag the toolbar');
                            this._dragHandle.id = this.get('id') + '_draghandle';
                            Dom.addClass(this._dragHandle, this.CLASS_DRAGHANDLE);
                            if (this.get('cont').hasChildNodes()) {
                                this.get('cont').insertBefore(this._dragHandle, this.get('cont').firstChild);
                            } else {
                                this.get('cont').appendChild(this._dragHandle);
                            }
                            /**
                            * @property dd
                            * @description The DragDrop instance associated with the Toolbar
                            * @type Object
                            */
                            this.dd = new YAHOO.util.DD(this.get('id'));
                            this.dd.setHandleElId(this._dragHandle.id);
                            
                        }
                    } else {
                        if (this._dragHandle) {
                            this._dragHandle.parentNode.removeChild(this._dragHandle);
                            this._dragHandle = null;
                            this.dd = null;
                        }
                    }
                    if (this._titlebar) {
                        if (draggable) {
                            this.dd = new YAHOO.util.DD(this.get('id'));
                            this.dd.setHandleElId(this._titlebar);
                            Dom.addClass(this._titlebar, 'draggable');
                        } else {
                            Dom.removeClass(this._titlebar, 'draggable');
                            if (this.dd) {
                                this.dd.unreg();
                                this.dd = null;
                            }
                        }
                    }
                },
                validator: function(value) {
                    var ret = true;
                    if (!YAHOO.util.DD) {
                        ret = false;
                    }
                    return ret;
                }
            });

        },
        /**
        * @method addButtonGroup
        * @description Add a new button group to the toolbar. (uses addButton)
        * @param {Object} oGroup Object literal reference to the Groups Config (contains an array of button configs as well as the group label)
        */
        addButtonGroup: function(oGroup) {
            if (!this.get('element')) {
                this._queue[this._queue.length] = ['addButtonGroup', arguments];
                return false;
            }
            
            if (!this.hasClass(this.CLASS_PREFIX + '-grouped')) {
                this.addClass(this.CLASS_PREFIX + '-grouped');
            }
            var div = document.createElement('DIV');
            Dom.addClass(div, this.CLASS_PREFIX + '-group');
            Dom.addClass(div, this.CLASS_PREFIX + '-group-' + oGroup.group);
            if (oGroup.label) {
                var label = document.createElement('h3');
                label.innerHTML = oGroup.label;
                div.appendChild(label);
            }
            if (!this.get('grouplabels')) {
                Dom.addClass(this.get('cont'), this.CLASS_PREFIX, '-nogrouplabels');
            }

            this.get('cont').appendChild(div);

            //For accessibility, let's put all of the group buttons in an Unordered List
            var ul = document.createElement('ul');
            div.appendChild(ul);

            if (!this._buttonGroupList) {
                this._buttonGroupList = {};
            }
            
            this._buttonGroupList[oGroup.group] = ul;

            for (var i = 0; i < oGroup.buttons.length; i++) {
                var li = document.createElement('li');
                li.className = this.CLASS_PREFIX + '-groupitem';
                ul.appendChild(li);
                if ((oGroup.buttons[i].type !== undefined) && oGroup.buttons[i].type == 'separator') {
                    this.addSeparator(li);
                } else {
                    oGroup.buttons[i].container = li;
                    this.addButton(oGroup.buttons[i]);
                }
            }
        },
        /**
        * @method addButtonToGroup
        * @description Add a new button to a toolbar group. Buttons supported:
        *   push, split, menu, select, color, spin
        * @param {Object} oButton Object literal reference to the Button's Config
        * @param {String} group The Group identifier passed into the initial config
        * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
        */
        addButtonToGroup: function(oButton, group, after) {
            var groupCont = this._buttonGroupList[group];
            var li = document.createElement('li');
            li.className = this.CLASS_PREFIX + '-groupitem';
            oButton.container = li;
            this.addButton(oButton, after);
            groupCont.appendChild(li);
        },
        /**
        * @method addButton
        * @description Add a new button to the toolbar. Buttons supported:
        *   push, split, menu, select, color, spin
        * @param {Object} oButton Object literal reference to the Button's Config
        * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
        */
        addButton: function(oButton, after) {
            if (!this.get('element')) {
                this._queue[this._queue.length] = ['addButton', arguments];
                return false;
            }
            if (!this._buttonList) {
                this._buttonList = [];
            }
            if (!oButton.container) {
                oButton.container = this.get('cont');
            }

            if ((oButton.type == 'menu') || (oButton.type == 'split') || (oButton.type == 'select')) {
                if (Lang.isArray(oButton.menu)) {
                    for (var i in oButton.menu) {
                        if (Lang.hasOwnProperty(oButton.menu, i)) {
                            var funcObject = {
                                fn: function(ev, x, oMenu) {
                                    if (!oButton.menucmd) {
                                        oButton.menucmd = oButton.value;
                                    }
                                    oButton.value = ((oMenu.value) ? oMenu.value : oMenu._oText.nodeValue);
                                },
                                scope: this
                            };
                            oButton.menu[i].onclick = funcObject;
                        }
                    }
                }
            }
            var _oButton = {}, skip = false;
            for (var o in oButton) {
                if (Lang.hasOwnProperty(oButton, o)) {
                    if (!this._toolbarConfigs[o]) {
                        _oButton[o] = oButton[o];
                    }
                }
            }
            if (oButton.type == 'select') {
                _oButton.type = 'menu';
            }
            if (oButton.type == 'spin') {
                _oButton.type = 'push';
            }
            if (_oButton.type == 'color') {
                if (YAHOO.widget.Overlay) {
                    _oButton = this._makeColorButton(_oButton);
                } else {
                    skip = true;
                }
            }
            if (_oButton.menu) {
                if ((YAHOO.widget.Overlay) && (oButton.menu instanceof YAHOO.widget.Overlay)) {
                    oButton.menu.showEvent.subscribe(function() {
                        this._button = _oButton;
                    });
                } else {
                    for (var m = 0; m < _oButton.menu.length; m++) {
                        if (!_oButton.menu[m].value) {
                            _oButton.menu[m].value = _oButton.menu[m].text;
                        }
                    }
                    if (this.browser.webkit) {
                        _oButton.focusmenu = false;
                    }
                }
            }
            if (skip) {
                oButton = false;
            } else {
                //Add to .get('buttons') manually
                this._configs.buttons.value[this._configs.buttons.value.length] = oButton;
                
                var tmp = new this.buttonType(_oButton);
                tmp.get('element').tabIndex = '-1';
                tmp.get('element').setAttribute('role', 'button');
                tmp._selected = true;
                if (!tmp.buttonType) {
                    tmp.buttonType = 'rich';
                    tmp.checkValue = function(value) {
                        var _menuItems = this.getMenu().getItems();
                        if (_menuItems.length === 0) {
                            this.getMenu()._onBeforeShow();
                            _menuItems = this.getMenu().getItems();
                        }
                        for (var i = 0; i < _menuItems.length; i++) {
                            _menuItems[i].cfg.setProperty('checked', false);
                            if (_menuItems[i].value == value) {
                                _menuItems[i].cfg.setProperty('checked', true);
                            }
                        }      
                    };
                }
                
                if (this.get('disabled')) {
                    //Toolbar is disabled, disable the new button too!
                    tmp.set('disabled', true);
                }
                if (!oButton.id) {
                    oButton.id = tmp.get('id');
                }
                
                if (after) {
                    var el = tmp.get('element');
                    var nextSib = null;
                    if (after.get) {
                        nextSib = after.get('element').nextSibling;
                    } else if (after.nextSibling) {
                        nextSib = after.nextSibling;
                    }
                    if (nextSib) {
                        nextSib.parentNode.insertBefore(el, nextSib);
                    }
                }
                tmp.addClass(this.CLASS_PREFIX + '-' + tmp.get('value'));

                var icon = document.createElement('span');
                icon.className = this.CLASS_PREFIX + '-icon';
                tmp.get('element').insertBefore(icon, tmp.get('firstChild'));
                if (tmp._button.tagName.toLowerCase() == 'button') {
                    tmp.get('element').setAttribute('unselectable', 'on');
                    //Replace the Button HTML Element with an a href if it exists
                    var a = document.createElement('a');
                    a.innerHTML = tmp._button.innerHTML;
                    a.href = '#';
                    a.tabIndex = '-1';
                    Event.on(a, 'click', function(ev) {
                        Event.stopEvent(ev);
                    });
                    tmp._button.parentNode.replaceChild(a, tmp._button);
                    tmp._button = a;
                }

                if (oButton.type == 'select') {
                    if (tmp._button.tagName.toLowerCase() == 'select') {
                        icon.parentNode.removeChild(icon);
                        var iel = tmp._button;
                        var parEl = tmp.get('element');
                        parEl.parentNode.replaceChild(iel, parEl);
                    } else {
                        //Don't put a class on it if it's a real select element
                        tmp.addClass(this.CLASS_PREFIX + '-select');
                    }
                }
                if (oButton.type == 'spin') {
                    if (!Lang.isArray(oButton.range)) {
                        oButton.range = [ 10, 100 ];
                    }
                    this._makeSpinButton(tmp, oButton);
                }
                tmp.get('element').setAttribute('title', tmp.get('label'));
                if (oButton.type != 'spin') {
                    if ((YAHOO.widget.Overlay) && (_oButton.menu instanceof YAHOO.widget.Overlay)) {
                        var showPicker = function(ev) {
                            var exec = true;
                            if (ev.keyCode && (ev.keyCode == 9)) {
                                exec = false;
                            }
                            if (exec) {
                                if (this._colorPicker) {
                                    this._colorPicker._button = oButton.value;
                                }
                                var menuEL = tmp.getMenu().element;
                                if (Dom.getStyle(menuEL, 'visibility') == 'hidden') {
                                    tmp.getMenu().show();
                                } else {
                                    tmp.getMenu().hide();
                                }
                            }
                            YAHOO.util.Event.stopEvent(ev);
                        };
                        tmp.on('mousedown', showPicker, oButton, this);
                        tmp.on('keydown', showPicker, oButton, this);
                        
                    } else if ((oButton.type != 'menu') && (oButton.type != 'select')) {
                        tmp.on('keypress', this._buttonClick, oButton, this);
                        tmp.on('mousedown', function(ev) {
                            YAHOO.util.Event.stopEvent(ev);
                            this._buttonClick(ev, oButton);
                        }, oButton, this);
                        tmp.on('click', function(ev) {
                            YAHOO.util.Event.stopEvent(ev);
                        });
                    } else {
                        //Stop the mousedown event so we can trap the selection in the editor!
                        tmp.on('mousedown', function(ev) {
                            YAHOO.util.Event.stopEvent(ev);
                        });
                        tmp.on('click', function(ev) {
                            YAHOO.util.Event.stopEvent(ev);
                        });
                        tmp.on('change', function(ev) {
                            if (!oButton.menucmd) {
                                oButton.menucmd = oButton.value;
                            }
                            oButton.value = ev.value;
                            this._buttonClick(ev, oButton);
                        }, this, true);

                        var self = this;
                        //Hijack the mousedown event in the menu and make it fire a button click..
                        if (tmp.getMenu().mouseDownEvent) {
                            tmp.getMenu().mouseDownEvent.subscribe(function(ev, args) {
                                var oMenu = args[1];
                                YAHOO.util.Event.stopEvent(args[0]);
                                tmp._onMenuClick(args[0], tmp);
                                if (!oButton.menucmd) {
                                    oButton.menucmd = oButton.value;
                                }
                                oButton.value = ((oMenu.value) ? oMenu.value : oMenu._oText.nodeValue);
                                self._buttonClick.call(self, args[1], oButton);
                                tmp._hideMenu();
                                return false;
                            });
                            tmp.getMenu().clickEvent.subscribe(function(ev, args) {
                                YAHOO.util.Event.stopEvent(args[0]);
                            });
                            tmp.getMenu().mouseUpEvent.subscribe(function(ev, args) {
                                YAHOO.util.Event.stopEvent(args[0]);
                            });
                        }
                        
                    }
                } else {
                    //Stop the mousedown event so we can trap the selection in the editor!
                    tmp.on('mousedown', function(ev) {
                        YAHOO.util.Event.stopEvent(ev);
                    });
                    tmp.on('click', function(ev) {
                        YAHOO.util.Event.stopEvent(ev);
                    });
                }
                if (this.browser.ie) {
                    /*
                    //Add a couple of new events for IE
                    tmp.DOM_EVENTS.focusin = true;
                    tmp.DOM_EVENTS.focusout = true;
                    
                    //Stop them so we don't loose focus in the Editor
                    tmp.on('focusin', function(ev) {
                        YAHOO.util.Event.stopEvent(ev);
                    }, oButton, this);
                    
                    tmp.on('focusout', function(ev) {
                        YAHOO.util.Event.stopEvent(ev);
                    }, oButton, this);
                    tmp.on('click', function(ev) {
                        YAHOO.util.Event.stopEvent(ev);
                    }, oButton, this);
                    */
                }
                if (this.browser.webkit) {
                    //This will keep the document from gaining focus and the editor from loosing it..
                    //Forcefully remove the focus calls in button!
                    tmp.hasFocus = function() {
                        return true;
                    };
                }
                this._buttonList[this._buttonList.length] = tmp;
                if ((oButton.type == 'menu') || (oButton.type == 'split') || (oButton.type == 'select')) {
                    if (Lang.isArray(oButton.menu)) {
                        var menu = tmp.getMenu();
                        if (menu.renderEvent) {
                            menu.renderEvent.subscribe(_addMenuClasses, tmp);
                            if (oButton.renderer) {
                                menu.renderEvent.subscribe(oButton.renderer, tmp);
                            }
                        }
                    }
                }
            }
            return oButton;
        },
        /**
        * @method addSeparator
        * @description Add a new button separator to the toolbar.
        * @param {HTMLElement} cont Optional HTML element to insert this button into.
        * @param {HTMLElement} after Optional HTML element to insert this button after in the DOM.
        */
        addSeparator: function(cont, after) {
            if (!this.get('element')) {
                this._queue[this._queue.length] = ['addSeparator', arguments];
                return false;
            }
            var sepCont = ((cont) ? cont : this.get('cont'));
            if (!this.get('element')) {
                this._queue[this._queue.length] = ['addSeparator', arguments];
                return false;
            }
            if (this._sepCount === null) {
                this._sepCount = 0;
            }
            if (!this._sep) {
                this._sep = document.createElement('SPAN');
                Dom.addClass(this._sep, this.CLASS_SEPARATOR);
                this._sep.innerHTML = '|';
            }
            var _sep = this._sep.cloneNode(true);
            this._sepCount++;
            Dom.addClass(_sep, this.CLASS_SEPARATOR + '-' + this._sepCount);
            if (after) {
                var nextSib = null;
                if (after.get) {
                    nextSib = after.get('element').nextSibling;
                } else if (after.nextSibling) {
                    nextSib = after.nextSibling;
                } else {
                    nextSib = after;
                }
                if (nextSib) {
                    if (nextSib == after) {
                        nextSib.parentNode.appendChild(_sep);
                    } else {
                        nextSib.parentNode.insertBefore(_sep, nextSib);
                    }
                }
            } else {
                sepCont.appendChild(_sep);
            }
            return _sep;
        },
        /**
        * @method _createColorPicker
        * @private
        * @description Creates the core DOM reference to the color picker menu item.
        * @param {String} id the id of the toolbar to prefix this DOM container with.
        */
        _createColorPicker: function(id) {
            if (Dom.get(id + '_colors')) {
               Dom.get(id + '_colors').parentNode.removeChild(Dom.get(id + '_colors'));
            }
            var picker = document.createElement('div');
            picker.className = 'yui-toolbar-colors';
            picker.id = id + '_colors';
            picker.style.display = 'none';
            Event.on(window, 'load', function() {
                document.body.appendChild(picker);
            }, this, true);

            this._colorPicker = picker;

            var html = '';
            for (var i in this._colorData) {
                if (Lang.hasOwnProperty(this._colorData, i)) {
                    html += '<a style="background-color: ' + i + '" href="#">' + i.replace('#', '') + '</a>';
                }
            }
            html += '<span><em>X</em><strong></strong></span>';
            window.setTimeout(function() {
                picker.innerHTML = html;
            }, 0);

            Event.on(picker, 'mouseover', function(ev) {
                var picker = this._colorPicker;
                var em = picker.getElementsByTagName('em')[0];
                var strong = picker.getElementsByTagName('strong')[0];
                var tar = Event.getTarget(ev);
                if (tar.tagName.toLowerCase() == 'a') {
                    em.style.backgroundColor = tar.style.backgroundColor;
                    strong.innerHTML = this._colorData['#' + tar.innerHTML] + '<br>' + tar.innerHTML;
                }
            }, this, true);
            Event.on(picker, 'focus', function(ev) {
                Event.stopEvent(ev);
            });
            Event.on(picker, 'click', function(ev) {
                Event.stopEvent(ev);
            });
            Event.on(picker, 'mousedown', function(ev) {
                Event.stopEvent(ev);
                var tar = Event.getTarget(ev);
                if (tar.tagName.toLowerCase() == 'a') {
                    var retVal = this.fireEvent('colorPickerClicked', { type: 'colorPickerClicked', target: this, button: this._colorPicker._button, color: tar.innerHTML, colorName: this._colorData['#' + tar.innerHTML] } );
                    if (retVal !== false) {
                        var info = {
                            color: tar.innerHTML,
                            colorName: this._colorData['#' + tar.innerHTML],
                            value: this._colorPicker._button 
                        };
                    
                        this.fireEvent('buttonClick', { type: 'buttonClick', target: this.get('element'), button: info });
                    }
                    this.getButtonByValue(this._colorPicker._button).getMenu().hide();
                }
            }, this, true);
        },
        /**
        * @method _resetColorPicker
        * @private
        * @description Clears the currently selected color or mouseover color in the color picker.
        */
        _resetColorPicker: function() {
            var em = this._colorPicker.getElementsByTagName('em')[0];
            var strong = this._colorPicker.getElementsByTagName('strong')[0];
            em.style.backgroundColor = 'transparent';
            strong.innerHTML = '';
        },
        /**
        * @method _makeColorButton
        * @private
        * @description Called to turn a "color" button into a menu button with an Overlay for the menu.
        * @param {Object} _oButton <a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> reference
        */
        _makeColorButton: function(_oButton) {
            if (!this._colorPicker) {   
                this._createColorPicker(this.get('id'));
            }
            _oButton.type = 'color';
            _oButton.menu = new YAHOO.widget.Overlay(this.get('id') + '_' + _oButton.value + '_menu', { visible: false, position: 'absolute', iframe: true });
            _oButton.menu.setBody('');
            _oButton.menu.render(this.get('cont'));
            Dom.addClass(_oButton.menu.element, 'yui-button-menu');
            Dom.addClass(_oButton.menu.element, 'yui-color-button-menu');
            _oButton.menu.beforeShowEvent.subscribe(function() {
                _oButton.menu.cfg.setProperty('zindex', 5); //Re Adjust the overlays zIndex.. not sure why.
                _oButton.menu.cfg.setProperty('context', [this.getButtonById(_oButton.id).get('element'), 'tl', 'bl']); //Re Adjust the overlay.. not sure why.
                //Move the DOM reference of the color picker to the Overlay that we are about to show.
                this._resetColorPicker();
                var _p = this._colorPicker;
                if (_p.parentNode) {
                    _p.parentNode.removeChild(_p);
                }
                _oButton.menu.setBody('');
                _oButton.menu.appendToBody(_p);
                this._colorPicker.style.display = 'block';
            }, this, true);
            return _oButton;
        },
        /**
        * @private
        * @method _makeSpinButton
        * @description Create a button similar to an OS Spin button.. It has an up/down arrow combo to scroll through a range of int values.
        * @param {Object} _button <a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> reference
        * @param {Object} oButton Object literal containing the buttons initial config
        */
        _makeSpinButton: function(_button, oButton) {
            _button.addClass(this.CLASS_PREFIX + '-spinbutton');
            var self = this,
                _par = _button._button.parentNode.parentNode, //parentNode of Button Element for appending child
                range = oButton.range,
                _b1 = document.createElement('a'),
                _b2 = document.createElement('a');
                _b1.href = '#';
                _b2.href = '#';
                _b1.tabIndex = '-1';
                _b2.tabIndex = '-1';
            
            //Setup the up and down arrows
            _b1.className = 'up';
            _b1.title = this.STR_SPIN_UP;
            _b1.innerHTML = this.STR_SPIN_UP;
            _b2.className = 'down';
            _b2.title = this.STR_SPIN_DOWN;
            _b2.innerHTML = this.STR_SPIN_DOWN;

            //Append them to the container
            _par.appendChild(_b1);
            _par.appendChild(_b2);
            
            var label = YAHOO.lang.substitute(this.STR_SPIN_LABEL, { VALUE: _button.get('label') });
            _button.set('title', label);

            var cleanVal = function(value) {
                value = ((value < range[0]) ? range[0] : value);
                value = ((value > range[1]) ? range[1] : value);
                return value;
            };

            var br = this.browser;
            var tbar = false;
            var strLabel = this.STR_SPIN_LABEL;
            if (this._titlebar && this._titlebar.firstChild) {
                tbar = this._titlebar.firstChild;
            }
            
            var _intUp = function(ev) {
                YAHOO.util.Event.stopEvent(ev);
                if (!_button.get('disabled') && (ev.keyCode != 9)) {
                    var value = parseInt(_button.get('label'), 10);
                    value++;
                    value = cleanVal(value);
                    _button.set('label', ''+value);
                    var label = YAHOO.lang.substitute(strLabel, { VALUE: _button.get('label') });
                    _button.set('title', label);
                    if (!br.webkit && tbar) {
                        //tbar.focus(); //We do this for accessibility, on the re-focus of the element, a screen reader will re-read the title that was just changed
                        //_button.focus();
                    }
                    self._buttonClick(ev, oButton);
                }
            };

            var _intDown = function(ev) {
                YAHOO.util.Event.stopEvent(ev);
                if (!_button.get('disabled') && (ev.keyCode != 9)) {
                    var value = parseInt(_button.get('label'), 10);
                    value--;
                    value = cleanVal(value);

                    _button.set('label', ''+value);
                    var label = YAHOO.lang.substitute(strLabel, { VALUE: _button.get('label') });
                    _button.set('title', label);
                    if (!br.webkit && tbar) {
                        //tbar.focus(); //We do this for accessibility, on the re-focus of the element, a screen reader will re-read the title that was just changed
                        //_button.focus();
                    }
                    self._buttonClick(ev, oButton);
                }
            };

            var _intKeyUp = function(ev) {
                if (ev.keyCode == 38) {
                    _intUp(ev);
                } else if (ev.keyCode == 40) {
                    _intDown(ev);
                } else if (ev.keyCode == 107 && ev.shiftKey) {  //Plus Key
                    _intUp(ev);
                } else if (ev.keyCode == 109 && ev.shiftKey) {  //Minus Key
                    _intDown(ev);
                }
            };

            //Handle arrow keys..
            _button.on('keydown', _intKeyUp, this, true);

            //Listen for the click on the up button and act on it
            //Listen for the click on the down button and act on it
            Event.on(_b1, 'mousedown',function(ev) {
                Event.stopEvent(ev);
            }, this, true);
            Event.on(_b2, 'mousedown', function(ev) {
                Event.stopEvent(ev);
            }, this, true);
            Event.on(_b1, 'click', _intUp, this, true);
            Event.on(_b2, 'click', _intDown, this, true);
        },
        /**
        * @protected
        * @method _buttonClick
        * @description Click handler for all buttons in the toolbar.
        * @param {String} ev The event that was passed in.
        * @param {Object} info Object literal of information about the button that was clicked.
        */
        _buttonClick: function(ev, info) {
            var doEvent = true;
            
            if (ev && ev.type == 'keypress') {
                if (ev.keyCode == 9) {
                    doEvent = false;
                } else if ((ev.keyCode === 13) || (ev.keyCode === 0) || (ev.keyCode === 32)) {
                } else {
                    doEvent = false;
                }
            }

            if (doEvent) {
                var fireNextEvent = true,
                    retValue = false;
                if (info.value) {
                    retValue = this.fireEvent(info.value + 'Click', { type: info.value + 'Click', target: this.get('element'), button: info });
                    if (retValue === false) {
                        fireNextEvent = false;
                    }
                }
                
                if (info.menucmd && fireNextEvent) {
                    retValue = this.fireEvent(info.menucmd + 'Click', { type: info.menucmd + 'Click', target: this.get('element'), button: info });
                    if (retValue === false) {
                        fireNextEvent = false;
                    }
                }
                if (fireNextEvent) {
                    this.fireEvent('buttonClick', { type: 'buttonClick', target: this.get('element'), button: info });
                }

                if (info.type == 'select') {
                    var button = this.getButtonById(info.id);
                    if (button.buttonType == 'rich') {
                        var txt = info.value;
                        for (var i = 0; i < info.menu.length; i++) {
                            if (info.menu[i].value == info.value) {
                                txt = info.menu[i].text;
                                break;
                            }
                        }
                        button.set('label', '<span class="yui-toolbar-' + info.menucmd + '-' + (info.value).replace(/ /g, '-').toLowerCase() + '">' + txt + '</span>');
                        var _items = button.getMenu().getItems();
                        for (var m = 0; m < _items.length; m++) {
                            if (_items[m].value.toLowerCase() == info.value.toLowerCase()) {
                                _items[m].cfg.setProperty('checked', true);
                            } else {
                                _items[m].cfg.setProperty('checked', false);
                            }
                        }
                    }
                }
                if (ev) {
                    Event.stopEvent(ev);
                }
            }
        },
        /**
        * @private
        * @property _keyNav
        * @description Flag to determine if the arrow nav listeners have been attached
        * @type Boolean
        */
        _keyNav: null,
        /**
        * @private
        * @property _navCounter
        * @description Internal counter for walking the buttons in the toolbar with the arrow keys
        * @type Number
        */
        _navCounter: null,
        /**
        * @private
        * @method _navigateButtons
        * @description Handles the navigation/focus of toolbar buttons with the Arrow Keys
        * @param {Event} ev The Key Event
        */
        _navigateButtons: function(ev) {
            switch (ev.keyCode) {
                case 37:
                case 39:
                    if (ev.keyCode == 37) {
                        this._navCounter--;
                    } else {
                        this._navCounter++;
                    }
                    if (this._navCounter > (this._buttonList.length - 1)) {
                        this._navCounter = 0;
                    }
                    if (this._navCounter < 0) {
                        this._navCounter = (this._buttonList.length - 1);
                    }
                    var el = this._buttonList[this._navCounter].get('element');
                    if (this.browser.ie) {
                        el = this._buttonList[this._navCounter].get('element').getElementsByTagName('a')[0];
                    }
                    if (this._buttonList[this._navCounter].get('disabled')) {
                        this._navigateButtons(ev);
                    } else {
                        el.focus();
                    }
                    break;
            }
        },
        /**
        * @private
        * @method _handleFocus
        * @description Sets up the listeners for the arrow key navigation
        */
        _handleFocus: function() {
            if (!this._keyNav) {
                var ev = 'keypress';
                if (this.browser.ie) {
                    ev = 'keydown';
                }
                Event.on(this.get('element'), ev, this._navigateButtons, this, true);
                this._keyNav = true;
                this._navCounter = -1;
            }
        },
        /**
        * @method getButtonById
        * @description Gets a button instance from the toolbar by is Dom id.
        * @param {String} id The Dom id to query for.
        * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a>}
        */
        getButtonById: function(id) {
            var len = this._buttonList.length;
            for (var i = 0; i < len; i++) {
                if (this._buttonList[i].get('id') == id) {
                    return this._buttonList[i];
                }
            }
            return false;
        },
        /**
        * @method getButtonByValue
        * @description Gets a button instance or a menuitem instance from the toolbar by it's value.
        * @param {String} value The button value to query for.
        * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a> or <a href="YAHOO.widget.MenuItem.html">YAHOO.widget.MenuItem</a>}
        */
        getButtonByValue: function(value) {
            var _buttons = this.get('buttons');
            var len = _buttons.length;
            for (var i = 0; i < len; i++) {
                if (_buttons[i].group !== undefined) {
                    for (var m = 0; m < _buttons[i].buttons.length; m++) {
                        if ((_buttons[i].buttons[m].value == value) || (_buttons[i].buttons[m].menucmd == value)) {
                            return this.getButtonById(_buttons[i].buttons[m].id);
                        }
                        if (_buttons[i].buttons[m].menu) { //Menu Button, loop through the values
                            for (var s = 0; s < _buttons[i].buttons[m].menu.length; s++) {
                                if (_buttons[i].buttons[m].menu[s].value == value) {
                                    return this.getButtonById(_buttons[i].buttons[m].id);
                                }
                            }
                        }
                    }
                } else {
                    if ((_buttons[i].value == value) || (_buttons[i].menucmd == value)) {
                        return this.getButtonById(_buttons[i].id);
                    }
                    if (_buttons[i].menu) { //Menu Button, loop through the values
                        for (var j = 0; j < _buttons[i].menu.length; j++) {
                            if (_buttons[i].menu[j].value == value) {
                                return this.getButtonById(_buttons[i].id);
                            }
                        }
                    }
                }
            }
            return false;
        },
        /**
        * @method getButtonByIndex
        * @description Gets a button instance from the toolbar by is index in _buttonList.
        * @param {Number} index The index of the button in _buttonList.
        * @return {<a href="YAHOO.widget.ToolbarButton.html">YAHOO.widget.ToolbarButton</a>}
        */
        getButtonByIndex: function(index) {
            if (this._buttonList[index]) {
                return this._buttonList[index];
            } else {
                return false;
            }
        },
        /**
        * @method getButtons
        * @description Returns an array of buttons in the current toolbar
        * @return {Array}
        */
        getButtons: function() {
            return this._buttonList;
        },
        /**
        * @method disableButton
        * @description Disables a button in the toolbar.
        * @param {String/Number} id Disable a button by it's id, index or value.
        * @return {Boolean}
        */
        disableButton: function(id) {
            var button = getButton.call(this, id);
            if (button) {
                button.set('disabled', true);
            } else {
                return false;
            }
        },
        /**
        * @method enableButton
        * @description Enables a button in the toolbar.
        * @param {String/Number} id Enable a button by it's id, index or value.
        * @return {Boolean}
        */
        enableButton: function(id) {
            if (this.get('disabled')) {
                return false;
            }
            var button = getButton.call(this, id);
            if (button) {
                if (button.get('disabled')) {
                    button.set('disabled', false);
                }
            } else {
                return false;
            }
        },
        /**
        * @method isSelected
        * @description Tells if a button is selected or not.
        * @param {String/Number} id A button by it's id, index or value.
        * @return {Boolean}
        */
        isSelected: function(id) {
            var button = getButton.call(this, id);
            if (button) {
                return button._selected;
            }
            return false;
        },
        /**
        * @method selectButton
        * @description Selects a button in the toolbar.
        * @param {String/Number} id Select a button by it's id, index or value.
        * @param {String} value If this is a Menu Button, check this item in the menu
        * @return {Boolean}
        */
        selectButton: function(id, value) {
            var button = getButton.call(this, id);
            if (button) {
                button.addClass('yui-button-selected');
                button.addClass('yui-button-' + button.get('value') + '-selected');
                button._selected = true;
                if (value) {
                    if (button.buttonType == 'rich') {
                        var _items = button.getMenu().getItems();
                        for (var m = 0; m < _items.length; m++) {
                            if (_items[m].value == value) {
                                _items[m].cfg.setProperty('checked', true);
                                button.set('label', '<span class="yui-toolbar-' + button.get('value') + '-' + (value).replace(/ /g, '-').toLowerCase() + '">' + _items[m]._oText.nodeValue + '</span>');
                            } else {
                                _items[m].cfg.setProperty('checked', false);
                            }
                        }
                    }
                }
            } else {
                return false;
            }
        },
        /**
        * @method deselectButton
        * @description Deselects a button in the toolbar.
        * @param {String/Number} id Deselect a button by it's id, index or value.
        * @return {Boolean}
        */
        deselectButton: function(id) {
            var button = getButton.call(this, id);
            if (button) {
                button.removeClass('yui-button-selected');
                button.removeClass('yui-button-' + button.get('value') + '-selected');
                button.removeClass('yui-button-hover');
                button._selected = false;
            } else {
                return false;
            }
        },
        /**
        * @method deselectAllButtons
        * @description Deselects all buttons in the toolbar.
        * @return {Boolean}
        */
        deselectAllButtons: function() {
            var len = this._buttonList.length;
            for (var i = 0; i < len; i++) {
                this.deselectButton(this._buttonList[i]);
            }
        },
        /**
        * @method disableAllButtons
        * @description Disables all buttons in the toolbar.
        * @return {Boolean}
        */
        disableAllButtons: function() {
            if (this.get('disabled')) {
                return false;
            }
            var len = this._buttonList.length;
            for (var i = 0; i < len; i++) {
                this.disableButton(this._buttonList[i]);
            }
        },
        /**
        * @method enableAllButtons
        * @description Enables all buttons in the toolbar.
        * @return {Boolean}
        */
        enableAllButtons: function() {
            if (this.get('disabled')) {
                return false;
            }
            var len = this._buttonList.length;
            for (var i = 0; i < len; i++) {
                this.enableButton(this._buttonList[i]);
            }
        },
        /**
        * @method resetAllButtons
        * @description Resets all buttons to their initial state.
        * @param {Object} _ex Except these buttons
        * @return {Boolean}
        */
        resetAllButtons: function(_ex) {
            if (!Lang.isObject(_ex)) {
                _ex = {};
            }
            if (this.get('disabled')) {
                return false;
            }
            var len = this._buttonList.length;
            for (var i = 0; i < len; i++) {
                var _button = this._buttonList[i];
                var disabled = _button._configs.disabled._initialConfig.value;
                if (_ex[_button.get('id')]) {
                    this.enableButton(_button);
                    this.selectButton(_button);
                } else {
                    if (disabled) {
                        this.disableButton(_button);
                    } else {
                        this.enableButton(_button);
                    }
                    this.deselectButton(_button);
                }
            }
        },
        /**
        * @method destroyButton
        * @description Destroy a button in the toolbar.
        * @param {String/Number} id Destroy a button by it's id or index.
        * @return {Boolean}
        */
        destroyButton: function(id) {
            var button = getButton.call(this, id);
            if (button) {
                var thisID = button.get('id');
                button.destroy();

                var len = this._buttonList.length;
                for (var i = 0; i < len; i++) {
                    if (this._buttonList[i].get('id') == thisID) {
                        this._buttonList[i] = null;
                    }
                }
            } else {
                return false;
            }
        },
        /**
        * @method destroy
        * @description Destroys the toolbar, all of it's elements and objects.
        * @return {Boolean}
        */
        destroy: function() {
            this.get('element').innerHTML = '';
            this.get('element').className = '';
            //Brutal Object Destroy
            for (var i in this) {
                if (Lang.hasOwnProperty(this, i)) {
                    this[i] = null;
                }
            }
            return true;
        },
        /**
        * @method collapse
        * @description Programatically collapse the toolbar.
        * @param {Boolean} collapse True to collapse, false to expand.
        */
        collapse: function(collapse) {
            var el = Dom.getElementsByClassName('collapse', 'span', this._titlebar);
            if (collapse === false) {
                Dom.removeClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed');
                if (el[0]) {
                    Dom.removeClass(el[0], 'collapsed');
                }
                this.fireEvent('toolbarExpanded', { type: 'toolbarExpanded', target: this });
            } else {
                if (el[0]) {
                    Dom.addClass(el[0], 'collapsed');
                }
                Dom.addClass(this.get('cont').parentNode, 'yui-toolbar-container-collapsed');
                this.fireEvent('toolbarCollapsed', { type: 'toolbarCollapsed', target: this });
            }
        },
        /**
        * @method toString
        * @description Returns a string representing the toolbar.
        * @return {String}
        */
        toString: function() {
            return 'Toolbar (#' + this.get('element').id + ') with ' + this._buttonList.length + ' buttons.';
        }
    });
/**
* @event buttonClick
* @param {Object} o The object passed to this handler is the button config used to create the button.
* @description Fires when any botton receives a click event. Passes back a single object representing the buttons config object. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event valueClick
* @param {Object} o The object passed to this handler is the button config used to create the button.
* @description This is a special dynamic event that is created and dispatched based on the value property
* of the button config. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* Example:
* <code><pre>
* buttons : [
*   { type: 'button', value: 'test', value: 'testButton' }
* ]</pre>
* </code>
* With the valueClick event you could subscribe to this buttons click event with this:
* tbar.in('testButtonClick', function() { alert('test button clicked'); })
* @type YAHOO.util.CustomEvent
*/
/**
* @event toolbarExpanded
* @description Fires when the toolbar is expanded via the collapse button. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event toolbarCollapsed
* @description Fires when the toolbar is collapsed via the collapse button. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
})();
/**
 * @description <p>The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.</p>
 * @namespace YAHOO.widget
 * @requires yahoo, dom, element, event, toolbar
 * @optional animation, container_core
 * @beta
 */

(function() {
var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event,
    Lang = YAHOO.lang,
    Toolbar = YAHOO.widget.Toolbar;

    /**
     * The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.
     * @constructor
     * @class SimpleEditor
     * @extends YAHOO.util.Element
     * @param {String/HTMLElement} el The textarea element to turn into an editor.
     * @param {Object} attrs Object liternal containing configuration parameters.
    */
    
    YAHOO.widget.SimpleEditor = function(el, attrs) {
        
        var o = {};
        if (Lang.isObject(el) && (!el.tagName) && !attrs) {
            Lang.augmentObject(o, el); //Break the config reference
            el = document.createElement('textarea');
            this.DOMReady = true;
            if (o.container) {
                var c = Dom.get(o.container);
                c.appendChild(el);
            } else {
                document.body.appendChild(el);
            }
        } else {
            if (attrs) {
                Lang.augmentObject(o, attrs); //Break the config reference
            }
        }

        var oConfig = {
            element: null,
            attributes: o
        }, id = null;

        if (Lang.isString(el)) {
            id = el;
        } else {
            if (oConfig.attributes.id) {
                id = oConfig.attributes.id;
            } else {
                id = Dom.generateId(el);
            }
        }
        oConfig.element = el;

        var element_cont = document.createElement('DIV');
        oConfig.attributes.element_cont = new YAHOO.util.Element(element_cont, {
            id: id + '_container'
        });
        var div = document.createElement('div');
        Dom.addClass(div, 'first-child');
        oConfig.attributes.element_cont.appendChild(div);
        
        if (!oConfig.attributes.toolbar_cont) {
            oConfig.attributes.toolbar_cont = document.createElement('DIV');
            oConfig.attributes.toolbar_cont.id = id + '_toolbar';
            div.appendChild(oConfig.attributes.toolbar_cont);
        }
        var editorWrapper = document.createElement('DIV');
        div.appendChild(editorWrapper);
        oConfig.attributes.editor_wrapper = editorWrapper;

        YAHOO.widget.SimpleEditor.superclass.constructor.call(this, oConfig.element, oConfig.attributes);
    };

    /**
    * @private
    * @method _cleanClassName
    * @description Makes a useable classname from dynamic data, by dropping it to lowercase and replacing spaces with -'s.
    * @param {String} str The classname to clean up
    * @return {String}
    */
    function _cleanClassName(str) {
        return str.replace(/ /g, '-').toLowerCase();
    }


    YAHOO.extend(YAHOO.widget.SimpleEditor, YAHOO.util.Element, {
        /**
        * @property _docType
        * @description The DOCTYPE to use in the editable container.
        * @type String
        */
        _docType: '<!DOCTYPE HTML PUBLIC "-/'+'/W3C/'+'/DTD HTML 4.01/'+'/EN" "http:/'+'/www.w3.org/TR/html4/strict.dtd">',
        /**
        * @property editorDirty
        * @description This flag will be set when certain things in the Editor happen. It is to be used by the developer to check to see if content has changed.
        * @type Boolean
        */
        editorDirty: null,
        /**
        * @property _defaultCSS
        * @description The default CSS used in the config for 'css'. This way you can add to the config like this: { css: YAHOO.widget.SimpleEditor.prototype._defaultCSS + 'ADD MYY CSS HERE' }
        * @type String
        */
        _defaultCSS: 'html { height: 95%; } body { padding: 7px; background-color: #fff; font:13px/1.22 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small; } a { color: blue; text-decoration: underline; cursor: text; } .warning-localfile { border-bottom: 1px dashed red !important; } .yui-busy { cursor: wait !important; } img.selected { border: 2px dotted #808080; } img { cursor: pointer !important; border: none; }',
        /**
        * @property _defaultToolbar
        * @private
        * @description Default toolbar config.
        * @type Object
        */
        _defaultToolbar: null,
        /**
        * @property _lastButton
        * @private
        * @description The last button pressed, so we don't disable it.
        * @type Object
        */
        _lastButton: null,
        /**
        * @property _baseHREF
        * @private
        * @description The base location of the editable page (this page) so that relative paths for image work.
        * @type String
        */
        _baseHREF: function() {
            var href = document.location.href;
            if (href.indexOf('?') !== -1) { //Remove the query string
                href = href.substring(0, href.indexOf('?'));
            }
            href = href.substring(0, href.lastIndexOf('/')) + '/';
            return href;
        }(),
        /**
        * @property _lastImage
        * @private
        * @description Safari reference for the last image selected (for styling as selected).
        * @type HTMLElement
        */
        _lastImage: null,
        /**
        * @property _blankImageLoaded
        * @private
        * @description Don't load the blank image more than once..
        * @type Boolean
        */
        _blankImageLoaded: null,
        /**
        * @property _fixNodesTimer
        * @private
        * @description Holder for the fixNodes timer
        * @type Date
        */
        _fixNodesTimer: null,
        /**
        * @property _nodeChangeTimer
        * @private
        * @description Holds a reference to the nodeChange setTimeout call
        * @type Number
        */
        _nodeChangeTimer: null,
        /**
        * @property _lastNodeChangeEvent
        * @private
        * @description Flag to determine the last event that fired a node change
        * @type Event
        */
        _lastNodeChangeEvent: null,
        /**
        * @property _lastNodeChange
        * @private
        * @description Flag to determine when the last node change was fired
        * @type Date
        */
        _lastNodeChange: 0,
        /**
        * @property _rendered
        * @private
        * @description Flag to determine if editor has been rendered or not
        * @type Boolean
        */
        _rendered: null,
        /**
        * @property DOMReady
        * @private
        * @description Flag to determine if DOM is ready or not
        * @type Boolean
        */
        DOMReady: null,
        /**
        * @property _selection
        * @private
        * @description Holder for caching iframe selections
        * @type Object
        */
        _selection: null,
        /**
        * @property _mask
        * @private
        * @description DOM Element holder for the editor Mask when disabled
        * @type Object
        */
        _mask: null,
        /**
        * @property _showingHiddenElements
        * @private
        * @description Status of the hidden elements button
        * @type Boolean
        */
        _showingHiddenElements: null,
        /**
        * @property currentWindow
        * @description A reference to the currently open EditorWindow
        * @type Object
        */
        currentWindow: null,
        /**
        * @property currentEvent
        * @description A reference to the current editor event
        * @type Event
        */
        currentEvent: null,
        /**
        * @property operaEvent
        * @private
        * @description setTimeout holder for Opera and Image DoubleClick event..
        * @type Object
        */
        operaEvent: null,
        /**
        * @property currentFont
        * @description A reference to the last font selected from the Toolbar
        * @type HTMLElement
        */
        currentFont: null,
        /**
        * @property currentElement
        * @description A reference to the current working element in the editor
        * @type Array
        */
        currentElement: null,
        /**
        * @property dompath
        * @description A reference to the dompath container for writing the current working dom path to.
        * @type HTMLElement
        */
        dompath: null,
        /**
        * @property beforeElement
        * @description A reference to the H2 placed before the editor for Accessibilty.
        * @type HTMLElement
        */
        beforeElement: null,
        /**
        * @property afterElement
        * @description A reference to the H2 placed after the editor for Accessibilty.
        * @type HTMLElement
        */
        afterElement: null,
        /**
        * @property invalidHTML
        * @description Contains a list of HTML elements that are invalid inside the editor. They will be removed when they are found. If you set the value of a key to "{ keepContents: true }", then the element will be replaced with a yui-non span to be filtered out when cleanHTML is called. The only tag that is ignored here is the span tag as it will force the Editor into a loop and freeze the browser. However.. all of these tags will be removed in the cleanHTML routine.
        * @type Object
        */
        invalidHTML: {
            form: true,
            input: true,
            button: true,
            select: true,
            link: true,
            html: true,
            body: true,
            iframe: true,
            script: true,
            style: true,
            textarea: true
        },
        /**
        * @property toolbar
        * @description Local property containing the <a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a> instance
        * @type <a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a>
        */
        toolbar: null,
        /**
        * @private
        * @property _contentTimer
        * @description setTimeout holder for documentReady check
        */
        _contentTimer: null,
        /**
        * @private
        * @property _contentTimerCounter
        * @description Counter to check the number of times the body is polled for before giving up
        * @type Number
        */
        _contentTimerCounter: 0,
        /**
        * @private
        * @property _disabled
        * @description The Toolbar items that should be disabled if there is no selection present in the editor.
        * @type Array
        */
        _disabled: [ 'createlink', 'fontname', 'fontsize', 'forecolor', 'backcolor' ],
        /**
        * @private
        * @property _alwaysDisabled
        * @description The Toolbar items that should ALWAYS be disabled event if there is a selection present in the editor.
        * @type Object
        */
        _alwaysDisabled: { },
        /**
        * @private
        * @property _alwaysEnabled
        * @description The Toolbar items that should ALWAYS be enabled event if there isn't a selection present in the editor.
        * @type Object
        */
        _alwaysEnabled: { },
        /**
        * @private
        * @property _semantic
        * @description The Toolbar commands that we should attempt to make tags out of instead of using styles.
        * @type Object
        */
        _semantic: { 'bold': true, 'italic' : true, 'underline' : true },
        /**
        * @private
        * @property _tag2cmd
        * @description A tag map of HTML tags to convert to the different types of commands so we can select the proper toolbar button.
        * @type Object
        */
        _tag2cmd: {
            'b': 'bold',
            'strong': 'bold',
            'i': 'italic',
            'em': 'italic',
            'u': 'underline',
            'sup': 'superscript',
            'sub': 'subscript',
            'img': 'insertimage',
            'a' : 'createlink',
            'ul' : 'insertunorderedlist',
            'ol' : 'insertorderedlist'
        },

        /**
        * @private _createIframe
        * @description Creates the DOM and YUI Element for the iFrame editor area.
        * @param {String} id The string ID to prefix the iframe with
        * @return {Object} iFrame object
        */
        _createIframe: function() {
            var ifrmDom = document.createElement('iframe');
            ifrmDom.id = this.get('id') + '_editor';
            var config = {
                border: '0',
                frameBorder: '0',
                marginWidth: '0',
                marginHeight: '0',
                leftMargin: '0',
                topMargin: '0',
                allowTransparency: 'true',
                width: '100%'
            };
            if (this.get('autoHeight')) {
                config.scrolling = 'no';
            }
            for (var i in config) {
                if (Lang.hasOwnProperty(config, i)) {
                    ifrmDom.setAttribute(i, config[i]);
                }
            }
            var isrc = 'javascript:;';
            if (this.browser.ie) {
                isrc = 'about:blank';
            }
            ifrmDom.setAttribute('src', isrc);
            var ifrm = new YAHOO.util.Element(ifrmDom);
            //ifrm.setStyle('zIndex', '-1');
            return ifrm;
        },
        /**
        * @private _isElement
        * @description Checks to see if an Element reference is a valid one and has a certain tag type
        * @param {HTMLElement} el The element to check
        * @param {String} tag The tag that the element needs to be
        * @return {Boolean}
        */
        _isElement: function(el, tag) {
            if (el && el.tagName && (el.tagName.toLowerCase() == tag)) {
                return true;
            }
            if (el && el.getAttribute && (el.getAttribute('tag') == tag)) {
                return true;
            }
            return false;
        },
        /**
        * @private _hasParent
        * @description Checks to see if an Element reference or one of it's parents is a valid one and has a certain tag type
        * @param {HTMLElement} el The element to check
        * @param {String} tag The tag that the element needs to be
        * @return HTMLElement
        */
        _hasParent: function(el, tag) {
            if (!el || !el.parentNode) {
                return false;
            }
            
            while (el.parentNode) {
                if (this._isElement(el, tag)) {
                    return el;
                }
                if (el.parentNode) {
                    el = el.parentNode;
                } else {
                    return false;
                }
            }
            return false;
        },
        /**
        * @private
        * @method _getDoc
        * @description Get the Document of the IFRAME
        * @return {Object}
        */
        _getDoc: function() {
            var value = false;
            if (this.get) {
                if (this.get('iframe')) {
                    if (this.get('iframe').get) {
                        if (this.get('iframe').get('element')) {
                            try {
                                if (this.get('iframe').get('element').contentWindow) {
                                    if (this.get('iframe').get('element').contentWindow.document) {
                                        value = this.get('iframe').get('element').contentWindow.document;
                                        return value;
                                    }
                                }
                            } catch (e) {}
                        }
                    }
                }
            }
            return false;
        },
        /**
        * @private
        * @method _getWindow
        * @description Get the Window of the IFRAME
        * @return {Object}
        */
        _getWindow: function() {
            return this.get('iframe').get('element').contentWindow;
        },
        /**
        * @private
        * @method _focusWindow
        * @description Attempt to set the focus of the iframes window.
        * @param {Boolean} onLoad Safari needs some special care to set the cursor in the iframe
        */
        _focusWindow: function(onLoad) {
            if (this.browser.webkit) {
                if (onLoad) {
                    /**
                    * @knownissue Safari Cursor Position
                    * @browser Safari 2.x
                    * @description Can't get Safari to place the cursor at the beginning of the text..
                    * This workaround at least set's the toolbar into the proper state.
                    */
                    this._getSelection().setBaseAndExtent(this._getDoc().body.firstChild, 0, this._getDoc().body.firstChild, 1);
                    if (this.browser.webkit3) {
                        this._getSelection().collapseToStart();
                    } else {
                        this._getSelection().collapse(false);
                    }
                } else {
                    this._getSelection().setBaseAndExtent(this._getDoc().body, 1, this._getDoc().body, 1);
                    if (this.browser.webkit3) {
                        this._getSelection().collapseToStart();
                    } else {
                        this._getSelection().collapse(false);
                    }
                }
                this._getWindow().focus();
            } else {
                this._getWindow().focus();
            }
        },
        /**
        * @private
        * @method _hasSelection
        * @description Determines if there is a selection in the editor document.
        * @return {Boolean}
        */
        _hasSelection: function() {
            var sel = this._getSelection();
            var range = this._getRange();
            var hasSel = false;

            if (!sel || !range) {
                return hasSel;
            }

            //Internet Explorer
            if (this.browser.ie || this.browser.opera) {
                if (range.text) {
                    hasSel = true;
                }
                if (range.html) {
                    hasSel = true;
                }
            } else {
                if (this.browser.webkit) {
                    if (sel+'' !== '') {
                        hasSel = true;
                    }
                } else {
                    if (sel && (sel.toString() !== '') && (sel !== undefined)) {
                        hasSel = true;
                    }
                }
            }
            return hasSel;
        },
        /**
        * @private
        * @method _getSelection
        * @description Handles the different selection objects across the A-Grade list.
        * @return {Object} Selection Object
        */
        _getSelection: function() {
            var _sel = null;
            if (this._getDoc() && this._getWindow()) {
                if (this._getDoc().selection) {
                    _sel = this._getDoc().selection;
                } else {
                    _sel = this._getWindow().getSelection();
                }
                //Handle Safari's lack of Selection Object
                if (this.browser.webkit) {
                    if (_sel.baseNode) {
                            this._selection = {};
                            this._selection.baseNode = _sel.baseNode;
                            this._selection.baseOffset = _sel.baseOffset;
                            this._selection.extentNode = _sel.extentNode;
                            this._selection.extentOffset = _sel.extentOffset;
                    } else if (this._selection !== null) {
                        _sel = this._getWindow().getSelection();
                        _sel.setBaseAndExtent(
                            this._selection.baseNode,
                            this._selection.baseOffset,
                            this._selection.extentNode,
                            this._selection.extentOffset);
                        this._selection = null;
                    }
                }
            }
            return _sel;
        },
        /**
        * @private
        * @method _selectNode
        * @description Places the highlight around a given node
        * @param {HTMLElement} node The node to select
        */
        _selectNode: function(node) {
            if (!node) {
                return false;
            }
            var sel = this._getSelection(),
                range = null;

            if (this.browser.ie) {
                try { //IE freaks out here sometimes..
                    range = this._getDoc().body.createTextRange();
                    range.moveToElementText(node);
                    range.select();
                } catch (e) {
                }
            } else if (this.browser.webkit) {
				sel.setBaseAndExtent(node, 0, node, node.innerText.length);
            } else if (this.browser.opera) {
                sel = this._getWindow().getSelection();
                range = this._getDoc().createRange();
                range.selectNode(node);
                sel.removeAllRanges();
                sel.addRange(range);
            } else {
                range = this._getDoc().createRange();
                range.selectNodeContents(node);
                sel.removeAllRanges();
                sel.addRange(range);
            }
        },
        /**
        * @private
        * @method _getRange
        * @description Handles the different range objects across the A-Grade list.
        * @return {Object} Range Object
        */
        _getRange: function() {
            var sel = this._getSelection();

            if (sel === null) {
                return null;
            }

            if (this.browser.webkit && !sel.getRangeAt) {
                var _range = this._getDoc().createRange();
                try {
                    _range.setStart(sel.anchorNode, sel.anchorOffset);
                    _range.setEnd(sel.focusNode, sel.focusOffset);
                } catch (e) {
                    _range = this._getWindow().getSelection()+'';
                }
                return _range;
            }

            if (this.browser.ie || this.browser.opera) {
                try {
                    return sel.createRange();
                } catch (e) {
                    return null;
                }
            }

            if (sel.rangeCount > 0) {
                return sel.getRangeAt(0);
            }
            return null;
        },
        /**
        * @private
        * @method _setDesignMode
        * @description Sets the designMode of the iFrame document.
        * @param {String} state This should be either on or off
        */
        _setDesignMode: function(state) {
            try {
                var set = true;
                //SourceForge Bug #1807057
                if (this.browser.ie && (state.toLowerCase() == 'off')) {
                    set = false;
                }
                if (set) {
                    this._getDoc().designMode = state;
                }
            } catch(e) { }
        },
        /**
        * @private
        * @method _toggleDesignMode
        * @description Toggles the designMode of the iFrame document on and off.
        * @return {String} The state that it was set to.
        */
        _toggleDesignMode: function() {
            var _dMode = this._getDoc().designMode.toLowerCase(),
                _state = 'on';
            if (_dMode == 'on') {
                _state = 'off';
            }
            this._setDesignMode(_state);
            return _state;
        },
        /**
        * @private
        * @method _initEditor
        * @description This method is fired from _checkLoaded when the document is ready. It turns on designMode and set's up the listeners.
        */
        _initEditor: function() {
            if (this.browser.ie) {
                this._getDoc().body.style.margin = '0';
            }
            if (!this.get('disabled')) {
                if (this._getDoc().designMode.toLowerCase() != 'on') {
                    this._setDesignMode('on');
                    this._contentTimerCounter = 0;
                }
            }
            if (!this._getDoc().body) {
                this._contentTimerCounter = 0;
                this._checkLoaded();
                return false;
            }
            
            this.toolbar.on('buttonClick', this._handleToolbarClick, this, true);
            //Setup Listeners on iFrame
            Event.on(this._getDoc(), 'mouseup', this._handleMouseUp, this, true);
            Event.on(this._getDoc(), 'mousedown', this._handleMouseDown, this, true);
            Event.on(this._getDoc(), 'click', this._handleClick, this, true);
            Event.on(this._getDoc(), 'dblclick', this._handleDoubleClick, this, true);
            Event.on(this._getDoc(), 'keypress', this._handleKeyPress, this, true);
            Event.on(this._getDoc(), 'keyup', this._handleKeyUp, this, true);
            Event.on(this._getDoc(), 'keydown', this._handleKeyDown, this, true);
            if (!this.get('disabled')) {
                this.toolbar.set('disabled', false);
            }
            this.fireEvent('editorContentLoaded', { type: 'editorLoaded', target: this });
            if (this.get('dompath')) {
                var self = this;
                setTimeout(function() {
                    self._writeDomPath.call(self);
                }, 150);
            }
            this.nodeChange(true);
            this._setBusy(true);
        },
        /**
        * @private
        * @method _checkLoaded
        * @description Called from a setTimeout loop to check if the iframes body.onload event has fired, then it will init the editor.
        */
        _checkLoaded: function() {
            this._contentTimerCounter++;
            if (this._contentTimer) {
                clearTimeout(this._contentTimer);
            }
            if (this._contentTimerCounter > 500) {
                return false;
            }
            var init = false;
            try {
                if (this._getDoc() && this._getDoc().body) {
                    if (this.browser.ie) {
                        if (this._getDoc().body.readyState == 'complete') {
                            init = true;
                        }
                    } else {
                        if (this._getDoc().body._rteLoaded === true) {
                            init = true;
                        }
                    }
                }
            } catch (e) {
                init = false;
            }

            if (init === true) {
                //The onload event has fired, clean up after ourselves and fire the _initEditor method
                this._initEditor();
            } else {
                var self = this;
                this._contentTimer = setTimeout(function() {
                    self._checkLoaded.call(self);
                }, 20);
            }
        },
        /**
        * @private
        * @method _setInitialContent
        * @description This method will open the iframes content document and write the textareas value into it, then start the body.onload checking.
        */
        _setInitialContent: function() {
            var html = Lang.substitute(this.get('html'), {
                TITLE: this.STR_TITLE,
                CONTENT: this._cleanIncomingHTML(this.get('element').value),
                CSS: this.get('css'),
                HIDDEN_CSS: ((this.get('hiddencss')) ? this.get('hiddencss') : '/* No Hidden CSS */'),
                EXTRA_CSS: ((this.get('extracss')) ? this.get('extracss') : '/* No Extra CSS */')
            }),
            check = true;
            if (document.compatMode != 'BackCompat') {
                html = this._docType + "\n" + html;
            } else {
            }

            if (this.browser.ie || this.browser.webkit || this.browser.opera || (navigator.userAgent.indexOf('Firefox/1.5') != -1)) {
                //Firefox 1.5 doesn't like setting designMode on an document created with a data url
                try {
                    //Adobe AIR Code
                    if (this.browser.air) {
                        var doc = this._getDoc().implementation.createHTMLDocument();
                        var origDoc = this._getDoc();
                        origDoc.open();
                        origDoc.close();
                        doc.open();
                        doc.write(html);
                        doc.close();
                        var node = origDoc.importNode(doc.getElementsByTagName("html")[0], true);
                        origDoc.replaceChild(node, origDoc.getElementsByTagName("html")[0]);
                        origDoc.body._rteLoaded = true;
                    } else {               
                        this._getDoc().open();
                        this._getDoc().write(html);
                        this._getDoc().close();
                    }
                } catch (e) {
                    //Safari will only be here if we are hidden
                    check = false;
                }
            } else {
                //This keeps Firefox 2 from writing the iframe to history preserving the back buttons functionality
                this.get('iframe').get('element').src = 'data:text/html;charset=utf-8,' + encodeURIComponent(html);
            }
            if (check) {
                this._checkLoaded();
            }
        },
        /**
        * @private
        * @method _setMarkupType
        * @param {String} action The action to take. Possible values are: css, default or semantic
        * @description This method will turn on/off the useCSS execCommand.
        */
        _setMarkupType: function(action) {
            switch (this.get('markup')) {
                case 'css':
                    this._setEditorStyle(true);
                    break;
                case 'default':
                    this._setEditorStyle(false);
                    break;
                case 'semantic':
                case 'xhtml':
                    if (this._semantic[action]) {
                        this._setEditorStyle(false);
                    } else {
                        this._setEditorStyle(true);
                    }
                    break;
            }
        },
        /**
        * Set the editor to use CSS instead of HTML
        * @param {Booleen} stat True/False
        */
        _setEditorStyle: function(stat) {
            try {
                this._getDoc().execCommand('useCSS', false, !stat);
            } catch (ex) {
            }
        },
        /**
        * @private
        * @method _getSelectedElement
        * @description This method will attempt to locate the element that was last interacted with, either via selection, location or event.
        * @return {HTMLElement} The currently selected element.
        */
        _getSelectedElement: function() {
            var doc = this._getDoc(),
                range = null,
                sel = null,
                elm = null;

            if (this.browser.ie) {
                this.currentEvent = this._getWindow().event; //Event utility assumes window.event, so we need to reset it to this._getWindow().event;
                range = this._getRange();
                if (range) {
                    elm = range.item ? range.item(0) : range.parentElement();
                    if (elm == doc.body) {
                        elm = null;
                    }
                }
                if ((this.currentEvent !== null) && (this.currentEvent.keyCode === 0)) {
                    elm = Event.getTarget(this.currentEvent);
                }
            } else {
                sel = this._getSelection();
                range = this._getRange();

                if (!sel || !range) {
                    return null;
                }
                if (!this._hasSelection()) {
                    if (sel.anchorNode && (sel.anchorNode.nodeType == 3)) {
                        if (sel.anchorNode.parentNode) { //next check parentNode
                            elm = sel.anchorNode.parentNode;
                        }
                        if (sel.anchorNode.nextSibling != sel.focusNode.nextSibling) {
                            elm = sel.anchorNode.nextSibling;
                        }
                    }
                    if (this._isElement(elm, 'br')) {
                        elm = null;
                    }
                    if (!elm) {
                        elm = range.commonAncestorContainer;
                        if (!range.collapsed) {
                            if (range.startContainer == range.endContainer) {
                                if (range.startOffset - range.endOffset < 2) {
                                    if (range.startContainer.hasChildNodes()) {
                                        elm = range.startContainer.childNodes[range.startOffset];
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (this.currentEvent !== null) {
                try {
                    switch (this.currentEvent.type) {
                        case 'click':
                        case 'mousedown':
                        case 'mouseup':
                            elm = Event.getTarget(this.currentEvent);
                            break;
                        default:
                            //Do nothing
                            break;
                    }
                } catch (e) {
                }
            } else if ((this.currentElement && this.currentElement[0]) && (!this.browser.ie)) {
                elm = this.currentElement[0];
            }
            if (this.browser.opera || this.browser.webkit) {
                if (this.currentEvent && !elm) {
                    elm = YAHOO.util.Event.getTarget(this.currentEvent);
                }
            }
            if (!elm || !elm.tagName) {
                elm = doc.body;
            }
            if (this._isElement(elm, 'html')) {
                //Safari sometimes gives us the HTML node back..
                elm = doc.body;
            }
            if (this._isElement(elm, 'body')) {
                //make sure that body means this body not the parent..
                elm = doc.body;
            }
            if (elm && !elm.parentNode) { //Not in document
                elm = doc.body;
            }
            if (elm === undefined) {
                elm = null;
            }
            return elm;
        },
        /**
        * @private
        * @method _getDomPath
        * @description This method will attempt to build the DOM path from the currently selected element.
        * @param HTMLElement el The element to start with, if not provided _getSelectedElement is used
        * @return {Array} An array of node references that will create the DOM Path.
        */
        _getDomPath: function(el) {
            if (!el) {
			    el = this._getSelectedElement();
            }
			var domPath = [];
            while (el !== null) {
                if (el.ownerDocument != this._getDoc()) {
                    el = null;
                    break;
                }
                //Check to see if we get el.nodeName and nodeType
                if (el.nodeName && el.nodeType && (el.nodeType == 1)) {
                    domPath[domPath.length] = el;
                }

                if (this._isElement(el, 'body')) {
                    break;
                }

                el = el.parentNode;
            }
            if (domPath.length === 0) {
                if (this._getDoc() && this._getDoc().body) {
                    domPath[0] = this._getDoc().body;
                }
            }
            return domPath.reverse();
        },
        /**
        * @private
        * @method _writeDomPath
        * @description Write the current DOM path out to the dompath container below the editor.
        */
        _writeDomPath: function() { 
            var path = this._getDomPath(),
                pathArr = [],
                classPath = '',
                pathStr = '';
            for (var i = 0; i < path.length; i++) {
                var tag = path[i].tagName.toLowerCase();
                if ((tag == 'ol') && (path[i].type)) {
                    tag += ':' + path[i].type;
                }
                if (Dom.hasClass(path[i], 'yui-tag')) {
                    tag = path[i].getAttribute('tag');
                }
                if ((this.get('markup') == 'semantic') || (this.get('markup') == 'xhtml')) {
                    switch (tag) {
                        case 'b': tag = 'strong'; break;
                        case 'i': tag = 'em'; break;
                    }
                }
                if (!Dom.hasClass(path[i], 'yui-non')) {
                    if (Dom.hasClass(path[i], 'yui-tag')) {
                        pathStr = tag;
                    } else {
                        classPath = ((path[i].className !== '') ? '.' + path[i].className.replace(/ /g, '.') : '');
                        if ((classPath.indexOf('yui') != -1) || (classPath.toLowerCase().indexOf('apple-style-span') != -1)) {
                            classPath = '';
                        }
                        pathStr = tag + ((path[i].id) ? '#' + path[i].id : '') + classPath;
                    }
                    switch (tag) {
                        case 'a':
                            if (path[i].getAttribute('href', 2)) {
                                pathStr += ':' + path[i].getAttribute('href', 2).replace('mailto:', '').replace('http:/'+'/', '').replace('https:/'+'/', ''); //May need to add others here ftp
                            }
                            break;
                        case 'img':
                            var h = path[i].height;
                            var w = path[i].width;
                            if (path[i].style.height) {
                                h = parseInt(path[i].style.height, 10);
                            }
                            if (path[i].style.width) {
                                w = parseInt(path[i].style.width, 10);
                            }
                            pathStr += '(' + h + 'x' + w + ')';
                        break;
                    }

                    if (pathStr.length > 10) {
                        pathStr = '<span title="' + pathStr + '">' + pathStr.substring(0, 10) + '...' + '</span>';
                    } else {
                        pathStr = '<span title="' + pathStr + '">' + pathStr + '</span>';
                    }
                    pathArr[pathArr.length] = pathStr;
                }
            }
            var str = pathArr.join(' ' + this.SEP_DOMPATH + ' ');
            //Prevent flickering
            if (this.dompath.innerHTML != str) {
                this.dompath.innerHTML = str;
            }
        },
        /**
        * @private
        * @method _fixNodes
        * @description Fix href and imgs as well as remove invalid HTML.
        */
        _fixNodes: function() {
            var doc = this._getDoc(),
                els = [];

            for (var v in this.invalidHTML) {
                if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) {
                    if (v.toLowerCase() != 'span') {
                        var tags = doc.body.getElementsByTagName(v);
                        if (tags.length) {
                            for (var i = 0; i < tags.length; i++) {
                                els.push(tags[i]);
                            }
                        }
                    }
                }
            }
            for (var h = 0; h < els.length; h++) {
                if (els[h].parentNode) {
                    if (Lang.isObject(this.invalidHTML[els[h].tagName.toLowerCase()]) && this.invalidHTML[els[h].tagName.toLowerCase()].keepContents) {
                        this._swapEl(els[h], 'span', function(el) {
                            el.className = 'yui-non';
                        });
                    } else {
                        els[h].parentNode.removeChild(els[h]);
                    }
                }
            }
            var imgs = this._getDoc().getElementsByTagName('img');
            Dom.addClass(imgs, 'yui-img');   
        },
        /**
        * @private
        * @method _isNonEditable
        * @param Event ev The Dom event being checked
        * @description Method is called at the beginning of all event handlers to check if this element or a parent element has the class yui-noedit (this.CLASS_NOEDIT) applied.
        * If it does, then this method will stop the event and return true. The event handlers will then return false and stop the nodeChange from occuring. This method will also
        * disable and enable the Editor's toolbar based on the noedit state.
        * @return Boolean
        */
        _isNonEditable: function(ev) {
            if (this.get('allowNoEdit')) {
                var el = Event.getTarget(ev);
                if (this._isElement(el, 'html')) {
                    el = null;
                }
                var path = this._getDomPath(el);
                for (var i = (path.length - 1); i > -1; i--) {
                    if (Dom.hasClass(path[i], this.CLASS_NOEDIT)) {
                        //if (this.toolbar.get('disabled') === false) {
                        //    this.toolbar.set('disabled', true);
                        //}
                        try {
                             this._getDoc().execCommand('enableObjectResizing', false, 'false');
                        } catch (e) {}
                        this.nodeChange();
                        Event.stopEvent(ev);
                        return true;
                    }
                }
                //if (this.toolbar.get('disabled') === true) {
                    //Should only happen once..
                    //this.toolbar.set('disabled', false);
                    try {
                         this._getDoc().execCommand('enableObjectResizing', false, 'true');
                    } catch (e) {}
                //}
            }
            return false;
        },
        /**
        * @private
        * @method _setCurrentEvent
        * @param {Event} ev The event to cache
        * @description Sets the current event property
        */
        _setCurrentEvent: function(ev) {
            this.currentEvent = ev;
        },
        /**
        * @private
        * @method _handleClick
        * @param {Event} ev The event we are working on.
        * @description Handles all click events inside the iFrame document.
        */
        _handleClick: function(ev) {
            if (this._isNonEditable(ev)) {
                return false;
            }
            this._setCurrentEvent(ev);
            if (this.currentWindow) {
                this.closeWindow();
            }
            if (YAHOO.widget.EditorInfo.window.win && YAHOO.widget.EditorInfo.window.scope) {
                YAHOO.widget.EditorInfo.window.scope.closeWindow.call(YAHOO.widget.EditorInfo.window.scope);
            }
            if (this.browser.webkit) {
                var tar =Event.getTarget(ev);
                if (this._isElement(tar, 'a') || this._isElement(tar.parentNode, 'a')) {
                    Event.stopEvent(ev);
                    this.nodeChange();
                }
            } else {
                this.nodeChange();
            }
        },
        /**
        * @private
        * @method _handleMouseUp
        * @param {Event} ev The event we are working on.
        * @description Handles all mouseup events inside the iFrame document.
        */
        _handleMouseUp: function(ev) {
            if (this._isNonEditable(ev)) {
                return false;
            }
            //Don't set current event for mouseup.
            //It get's fired after a menu is closed and gives up a bogus event to work with
            //this._setCurrentEvent(ev);
            var self = this;
            if (this.browser.opera < 9.5) {
                /**
                * @knownissue Opera appears to stop the MouseDown, Click and DoubleClick events on an image inside of a document with designMode on..
                * @browser Opera
                * @description This work around traps the MouseUp event and sets a timer to check if another MouseUp event fires in so many seconds. If another event is fired, they we internally fire the DoubleClick event.
                */
                var sel = Event.getTarget(ev);
                if (this._isElement(sel, 'img')) {
                    this.nodeChange();
                    if (this.operaEvent) {
                        clearTimeout(this.operaEvent);
                        this.operaEvent = null;
                        this._handleDoubleClick(ev);
                    } else {
                        this.operaEvent = window.setTimeout(function() {
                            self.operaEvent = false;
                        }, 700);
                    }
                }
            }
            //This will stop Safari from selecting the entire document if you select all the text in the editor
            if (this.browser.webkit || this.browser.opera) {
                if (this.browser.webkit) {
                    Event.stopEvent(ev);
                }
            }
            this.nodeChange();
            this.fireEvent('editorMouseUp', { type: 'editorMouseUp', target: this, ev: ev });
        },
        /**
        * @private
        * @method _handleMouseDown
        * @param {Event} ev The event we are working on.
        * @description Handles all mousedown events inside the iFrame document.
        */
        _handleMouseDown: function(ev) {
            if (this._isNonEditable(ev)) {
                return false;
            }
            this._setCurrentEvent(ev);
            var sel = Event.getTarget(ev);
            if (this.browser.webkit && this._hasSelection()) {
                var _sel = this._getSelection();
                if (!this.browser.webkit3) {
                    _sel.collapse(true);
                } else {
                    _sel.collapseToStart();
                }
            }
            if (this.browser.webkit && this._lastImage) {
                Dom.removeClass(this._lastImage, 'selected');
                this._lastImage = null;
            }
            if (this._isElement(sel, 'img') || this._isElement(sel, 'a')) {
                if (this.browser.webkit) {
                    Event.stopEvent(ev);
                    if (this._isElement(sel, 'img')) {
                        Dom.addClass(sel, 'selected');
                        this._lastImage = sel;
                    }
                }
                this.nodeChange();
            }
            this.fireEvent('editorMouseDown', { type: 'editorMouseDown', target: this, ev: ev });
        },
        /**
        * @private
        * @method _handleDoubleClick
        * @param {Event} ev The event we are working on.
        * @description Handles all doubleclick events inside the iFrame document.
        */
        _handleDoubleClick: function(ev) {
            if (this._isNonEditable(ev)) {
                return false;
            }
            this._setCurrentEvent(ev);
            
            //Opera 9.5 for Windows displays a context menu on doubleclick, this stops it
            if (this.browser.opera >= 9.5) {
                Event.preventDefault(ev);
            }

            var sel = Event.getTarget(ev);
            if (this._isElement(sel, 'img')) {
                this.currentElement[0] = sel;
                this.toolbar.fireEvent('insertimageClick', { type: 'insertimageClick', target: this.toolbar });
                this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
            } else if (this._hasParent(sel, 'a')) { //Handle elements inside an a
                this.currentElement[0] = this._hasParent(sel, 'a');
                this.toolbar.fireEvent('createlinkClick', { type: 'createlinkClick', target: this.toolbar });
                this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
            }
            this.nodeChange();
            this.editorDirty = false;
            this.fireEvent('editorDoubleClick', { type: 'editorDoubleClick', target: this, ev: ev });
        },
        /**
        * @private
        * @method _handleKeyUp
        * @param {Event} ev The event we are working on.
        * @description Handles all keyup events inside the iFrame document.
        */
        _handleKeyUp: function(ev) {
            if (this._isNonEditable(ev)) {
                return false;
            }
            this._setCurrentEvent(ev);
            switch (ev.keyCode) {
                case 37: //Left Arrow
                case 38: //Up Arrow
                case 39: //Right Arrow
                case 40: //Down Arrow
                case 46: //Forward Delete
                case 8: //Delete
                case 87: //W key if window is open
                    if ((ev.keyCode == 87) && this.currentWindow && ev.shiftKey && ev.ctrlKey) {
                        this.closeWindow();
                    } else {
                        if (!this.browser.ie) {
                            if (this._nodeChangeTimer) {
                                clearTimeout(this._nodeChangeTimer);
                            }
                            var self = this;
                            this._nodeChangeTimer = setTimeout(function() {
                                self._nodeChangeTimer = null;
                                self.nodeChange.call(self);
                            }, 100);
                        } else {
                            this.nodeChange();
                        }
                        this.editorDirty = true;
                    }
                    break;
            }
            this.fireEvent('editorKeyUp', { type: 'editorKeyUp', target: this, ev: ev });
        },
        /**
        * @private
        * @method _handleKeyPress
        * @param {Event} ev The event we are working on.
        * @description Handles all keypress events inside the iFrame document.
        */
        _handleKeyPress: function(ev) {
            if (this.get('allowNoEdit')) {
                if (ev && ev.keyCode && ((ev.keyCode == 46) || ev.keyCode == 63272)) {
                    //Forward delete key
                    Event.stopEvent(ev);
                }
            }
            if (this._isNonEditable(ev)) {
                return false;
            }
            this._setCurrentEvent(ev);
            if (this.browser.webkit) {
                if (!this.browser.webkit3) {
                    if (ev.keyCode && (ev.keyCode == 122) && (ev.metaKey)) {
                        //This is CMD + z (for undo)
                        if (this._hasParent(this._getSelectedElement(), 'li')) {
                            Event.stopEvent(ev);
                        }
                    }
                }
                /* This was removed because it crashes Safari 2.x in some cases
                if (ev.keyCode && (ev.keyCode == 8)) {
                    //Delete Key
                    if (this._isElement(this._getSelectedElement(), 'br')) {
                        var el = this._getSelectedElement();
                        el.parentNode.removeChild(el);
                    }
                }
                */
                this._listFix(ev);
            }
            this.fireEvent('editorKeyPress', { type: 'editorKeyPress', target: this, ev: ev });
        },
        /**
        * @private
        * @method _listFix
        * @param {Event} ev The event we are working on.
        * @description Handles the Enter key, Tab Key and Shift + Tab keys for List Items.
        */
        _listFix: function(ev) {
            var testLi = null, par = null, preContent = false, range = null;
            //Enter Key
            if (this.browser.webkit) {
                if (ev.keyCode && (ev.keyCode == 13)) {
                    if (this._hasParent(this._getSelectedElement(), 'li')) {
                        var tar = this._hasParent(this._getSelectedElement(), 'li');
                        var li = this._getDoc().createElement('li');
                        li.innerHTML = '<span class="yui-non">&nbsp;</span>&nbsp;';
                        if (tar.nextSibling) {
                            tar.parentNode.insertBefore(li, tar.nextSibling);
                        } else {
                            tar.parentNode.appendChild(li);
                        }
                        this.currentElement[0] = li;
                        this._selectNode(li.firstChild);
                        if (!this.browser.webkit3) {
                            tar.parentNode.style.display = 'list-item';
                            setTimeout(function() {
                                tar.parentNode.style.display = 'block';
                            }, 1);
                        }
                        Event.stopEvent(ev);
                    }
                }
            }
            //Shift + Tab Key
            if (ev.keyCode && ((!this.browser.webkit3 && (ev.keyCode == 25)) || ((this.browser.webkit3 || !this.browser.webkit) && ((ev.keyCode == 9) && ev.shiftKey)))) {
                testLi = this._getSelectedElement();
                if (this._hasParent(testLi, 'li')) {
                    testLi = this._hasParent(testLi, 'li');
                    if (this._hasParent(testLi, 'ul') || this._hasParent(testLi, 'ol')) {
                        par = this._hasParent(testLi, 'ul');
                        if (!par) {
                            par = this._hasParent(testLi, 'ol');
                        }
                        if (this._isElement(par.previousSibling, 'li')) {
                            par.removeChild(testLi);
                            par.parentNode.insertBefore(testLi, par.nextSibling);
                            if (this.browser.ie) {
                                range = this._getDoc().body.createTextRange();
                                range.moveToElementText(testLi);
                                range.collapse(false);
                                range.select();
                            }
                            if (this.browser.webkit) {
                                if (!this.browser.webkit3) {
                                    par.style.display = 'list-item';
                                    par.parentNode.style.display = 'list-item';
                                    setTimeout(function() {
                                        par.style.display = 'block';
                                        par.parentNode.style.display = 'block';
                                    }, 1);
                                }
                            }
                            Event.stopEvent(ev);
                        }
                    }
                }
            }
            //Tab Key
            if (ev.keyCode && ((ev.keyCode == 9) && (!ev.shiftKey))) {
                var preLi = this._getSelectedElement();
                if (this._hasParent(preLi, 'li')) {
                    preContent = this._hasParent(preLi, 'li').innerHTML;
                }
                if (this.browser.webkit) {
                    this._getDoc().execCommand('inserttext', false, '\t');
                }
                testLi = this._getSelectedElement();
                if (this._hasParent(testLi, 'li')) {
                    par = this._hasParent(testLi, 'li');
                    var newUl = this._getDoc().createElement(par.parentNode.tagName.toLowerCase());
                    if (this.browser.webkit) {
                        var span = Dom.getElementsByClassName('Apple-tab-span', 'span', par);
                        //Remove the span element that Safari puts in
                        if (span[0]) {
                            par.removeChild(span[0]);
                            par.innerHTML = Lang.trim(par.innerHTML);
                            //Put the HTML from the LI into this new LI
                            if (preContent) {
                                par.innerHTML = '<span class="yui-non">' + preContent + '</span>&nbsp;';
                            } else {
                                par.innerHTML = '<span class="yui-non">&nbsp;</span>&nbsp;';
                            }
                        }
                    } else {
                        if (preContent) {
                            par.innerHTML = preContent + '&nbsp;';
                        } else {
                            par.innerHTML = '&nbsp;';
                        }
                    }

                    par.parentNode.replaceChild(newUl, par);
                    newUl.appendChild(par);
                    if (this.browser.webkit) {
                        this._getSelection().setBaseAndExtent(par.firstChild, 1, par.firstChild, par.firstChild.innerText.length);
                        if (!this.browser.webkit3) {
                            par.parentNode.parentNode.style.display = 'list-item';
                            setTimeout(function() {
                                par.parentNode.parentNode.style.display = 'block';
                            }, 1);
                        }
                    } else if (this.browser.ie) {
                        range = this._getDoc().body.createTextRange();
                        range.moveToElementText(par);
                        range.collapse(false);
                        range.select();
                    } else {
                        this._selectNode(par);
                    }
                    Event.stopEvent(ev);
                }
                if (this.browser.webkit) {
                    Event.stopEvent(ev);
                }
                this.nodeChange();
            }
        },
        /**
        * @private
        * @method _handleKeyDown
        * @param {Event} ev The event we are working on.
        * @description Handles all keydown events inside the iFrame document.
        */
        _handleKeyDown: function(ev) {
            var tar = null, _range = null;        
            if (this._isNonEditable(ev)) {
                return false;
            }
            this._setCurrentEvent(ev);
            if (this.currentWindow) {
                this.closeWindow();
            }
            if (YAHOO.widget.EditorInfo.window.win && YAHOO.widget.EditorInfo.window.scope) {
                YAHOO.widget.EditorInfo.window.scope.closeWindow.call(YAHOO.widget.EditorInfo.window.scope);
            }
            var doExec = false,
                action = null,
                exec = false;

            if (ev.shiftKey && ev.ctrlKey) {
                doExec = true;
            }
            switch (ev.keyCode) {
                case 84: //Focus Toolbar Header -- Ctrl + Shift + T
                    if (ev.shiftKey && ev.ctrlKey) {
                        var h = this.toolbar.getElementsByTagName('h2')[0];
                        if (h) {
                            h.focus();
                        }
                        Event.stopEvent(ev);
                        doExec = false;
                    }
                    break;
                case 27: //Focus After Element - Ctrl + Shift + Esc
                    if (ev.shiftKey) {
                        this.afterElement.focus();
                        Event.stopEvent(ev);
                        exec = false;
                    }
                    break;
                case 76: //L
                    if (this._hasSelection()) {
                        if (ev.shiftKey && ev.ctrlKey) {
                            var makeLink = true;
                            if (this.get('limitCommands')) {
                                if (!this.toolbar.getButtonByValue('createlink')) {
                                    makeLink = false;
                                }
                            }
                            if (makeLink) {
                                this.execCommand('createlink', '');
                                this.toolbar.fireEvent('createlinkClick', { type: 'createlinkClick', target: this.toolbar });
                                this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
                                doExec = false;
                            }
                        }
                    }
                    break;
                case 65:
                    if (ev.metaKey && this.browser.webkit) {
                        Event.stopEvent(ev);
                        //Override Safari's select all and select the contents of the editor not the iframe as Safari would by default.
                        this._getSelection().setBaseAndExtent(this._getDoc().body, 1, this._getDoc().body, this._getDoc().body.innerHTML.length);
                    }
                    break;
                case 66: //B
                    action = 'bold';
                    break;
                case 73: //I
                    action = 'italic';
                    break;
                case 85: //U
                    action = 'underline';
                    break;
                case 9:
                    if (this.browser.ie) {
                        //Insert a tab in Internet Explorer
                        _range = this._getRange();
                        tar = this._getSelectedElement();
                        if (!this._isElement(tar, 'li')) {
                            if (_range) {
                                _range.pasteHTML('&nbsp;&nbsp;&nbsp;&nbsp;');
                                _range.collapse(false);
                                _range.select();
                            }
                            Event.stopEvent(ev);
                        }
                    }
                    //Firefox 3 code
                    if (this.browser.gecko > 1.8) {
                        tar = this._getSelectedElement();
                        if (this._isElement(tar, 'li')) {
                            if (ev.shiftKey) {
                                this._getDoc().execCommand('outdent', null, '');
                            } else {
                                this._getDoc().execCommand('indent', null, '');
                            }
                        } else if (!this._hasSelection()) {
                            this.execCommand('inserthtml', '&nbsp;&nbsp;&nbsp;&nbsp;');
                        }
                        Event.stopEvent(ev);
                    }
                    break;                
                case 13:
                    if (this.browser.ie) {
                        //Insert a <br> instead of a <p></p> in Internet Explorer
                        _range = this._getRange();
                        tar = this._getSelectedElement();
                        if (!this._isElement(tar, 'li')) {
                            if (_range) {
                                _range.pasteHTML('<br>');
                                _range.collapse(false);
                                _range.select();
                            }
                            Event.stopEvent(ev);
                        }
                    }
            }
            //if (!this.browser.gecko && !this.browser.webkit) {
            if (this.browser.ie) {
                this._listFix(ev);
            }
            if (doExec && action) {
                this.execCommand(action, null);
                Event.stopEvent(ev);
                this.nodeChange();
            }
            this.fireEvent('editorKeyDown', { type: 'editorKeyDown', target: this, ev: ev });
        },
        /**
        * @method nodeChange
        * @param {Boolean} force Optional paramenter to skip the threshold counter
        * @description Handles setting up the toolbar buttons, getting the Dom path, fixing nodes.
        */
        nodeChange: function(force) {
            var threshold = parseInt(this.get('nodeChangeThreshold'), 10);
            var thisNodeChange = Math.round(new Date().getTime() / 1000);
            if (force === true) {
                this._lastNodeChange = 0;
            }
            
            if ((this._lastNodeChange + threshold) < thisNodeChange) {
                var self = this;
                if (this._fixNodesTimer === null) {
                    this._fixNodesTimer = window.setTimeout(function() {
                        self._fixNodes.call(self);
                        self._fixNodesTimer = null;
                    }, 0);
                }
            }
            this._lastNodeChange = thisNodeChange;
            if (this.currentEvent) {
                this._lastNodeChangeEvent = this.currentEvent.type;
            }

            var beforeNodeChange = this.fireEvent('beforeNodeChange', { type: 'beforeNodeChange', target: this });
            if (beforeNodeChange === false) {
                return false;
            }
            if (this.get('dompath')) {
                this._writeDomPath();
            }
            //Check to see if we are disabled before continuing
            if (!this.get('disabled')) {
                if (this.STOP_NODE_CHANGE) {
                    //Reset this var for next action
                    this.STOP_NODE_CHANGE = false;
                    return false;
                } else {
                    var sel = this._getSelection(),
                        range = this._getRange(),
                        el = this._getSelectedElement(),
                        fn_button = this.toolbar.getButtonByValue('fontname'),
                        fs_button = this.toolbar.getButtonByValue('fontsize');

                    if (force !== true) {
                        this.editorDirty = true;
                    }

                    //Handle updating the toolbar with active buttons
                    var _ex = {};
                    if (this._lastButton) {
                        _ex[this._lastButton.id] = true;
                    }
                    if (!this._isElement(el, 'body')) {
                        if (fn_button) {
                            _ex[fn_button.get('id')] = true;
                        }
                        if (fs_button) {
                            _ex[fs_button.get('id')] = true;
                        }
                    }
                    this.toolbar.resetAllButtons(_ex);

                    //Handle disabled buttons
                    for (var d = 0; d < this._disabled.length; d++) {
                        var _button = this.toolbar.getButtonByValue(this._disabled[d]);
                        if (_button && _button.get) {
                            if (this._lastButton && (_button.get('id') === this._lastButton.id)) {
                                //Skip
                            } else {
                                if (!this._hasSelection()) {
                                    switch (this._disabled[d]) {
                                        case 'fontname':
                                        case 'fontsize':
                                            break;
                                        default:
                                            //No Selection - disable
                                            this.toolbar.disableButton(_button);
                                    }
                                } else {
                                    if (!this._alwaysDisabled[this._disabled[d]]) {
                                        this.toolbar.enableButton(_button);
                                    }
                                }
                                if (!this._alwaysEnabled[this._disabled[d]]) {
                                    this.toolbar.deselectButton(_button);
                                }
                            }
                        }
                    }
                    var path = this._getDomPath();
                    var tag = null, cmd = null;
                    for (var i = 0; i < path.length; i++) {
                        tag = path[i].tagName.toLowerCase();
                        if (path[i].getAttribute('tag')) {
                            tag = path[i].getAttribute('tag').toLowerCase();
                        }
                        cmd = this._tag2cmd[tag];
                        if (cmd === undefined) {
                            cmd = [];
                        }
                        if (!Lang.isArray(cmd)) {
                            cmd = [cmd];
                        }

                        //Bold and Italic styles
                        if (path[i].style.fontWeight.toLowerCase() == 'bold') {
                            cmd[cmd.length] = 'bold';
                        }
                        if (path[i].style.fontStyle.toLowerCase() == 'italic') {
                            cmd[cmd.length] = 'italic';
                        }
                        if (path[i].style.textDecoration.toLowerCase() == 'underline') {
                            cmd[cmd.length] = 'underline';
                        }
                        if (cmd.length > 0) {
                            for (var j = 0; j < cmd.length; j++) {
                                this.toolbar.selectButton(cmd[j]);
                                this.toolbar.enableButton(cmd[j]);
                            }
                        }
                        //Handle Alignment
                        switch (path[i].style.textAlign.toLowerCase()) {
                            case 'left':
                            case 'right':
                            case 'center':
                            case 'justify':
                                var alignType = path[i].style.textAlign.toLowerCase();
                                if (path[i].style.textAlign.toLowerCase() == 'justify') {
                                    alignType = 'full';
                                }
                                this.toolbar.selectButton('justify' + alignType);
                                this.toolbar.enableButton('justify' + alignType);
                                break;
                        }
                    }
                    //After for loop

                    //Reset Font Family and Size to the inital configs
                    if (fn_button) {
                        var family = fn_button._configs.label._initialConfig.value;
                        fn_button.set('label', '<span class="yui-toolbar-fontname-' + _cleanClassName(family) + '">' + family + '</span>');
                        this._updateMenuChecked('fontname', family);
                    }

                    if (fs_button) {
                        fs_button.set('label', fs_button._configs.label._initialConfig.value);
                    }

                    var hd_button = this.toolbar.getButtonByValue('heading');
                    if (hd_button) {
                        hd_button.set('label', hd_button._configs.label._initialConfig.value);
                        this._updateMenuChecked('heading', 'none');
                    }
                    var img_button = this.toolbar.getButtonByValue('insertimage');
                    if (img_button && this.currentWindow && (this.currentWindow.name == 'insertimage')) {
                        this.toolbar.disableButton(img_button);
                    }
                }
            }

            this.fireEvent('afterNodeChange', { type: 'afterNodeChange', target: this });
        },
        /**
        * @private
        * @method _updateMenuChecked
        * @param {Object} button The command identifier of the button you want to check
        * @param {String} value The value of the menu item you want to check
        * @param {<a href="YAHOO.widget.Toolbar.html">YAHOO.widget.Toolbar</a>} The Toolbar instance the button belongs to (defaults to this.toolbar) 
        * @description Gets the menu from a button instance, if the menu is not rendered it will render it. It will then search the menu for the specified value, unchecking all other items and checking the specified on.
        */
        _updateMenuChecked: function(button, value, tbar) {
            if (!tbar) {
                tbar = this.toolbar;
            }
            var _button = tbar.getButtonByValue(button);
            _button.checkValue(value);
        },
        /**
        * @private
        * @method _handleToolbarClick
        * @param {Event} ev The event that triggered the button click
        * @description This is an event handler attached to the Toolbar's buttonClick event. It will fire execCommand with the command identifier from the Toolbar Button.
        */
        _handleToolbarClick: function(ev) {
            var value = '';
            var str = '';
            var cmd = ev.button.value;
            if (ev.button.menucmd) {
                value = cmd;
                cmd = ev.button.menucmd;
            }
            this._lastButton = ev.button;
            if (this.STOP_EXEC_COMMAND) {
                this.STOP_EXEC_COMMAND = false;
                return false;
            } else {
                this.execCommand(cmd, value);
                if (!this.browser.webkit) {
                     var self = this;
                     setTimeout(function() {
                         self._focusWindow.call(self);
                     }, 5);
                 }
            }
            Event.stopEvent(ev);
        },
        /**
        * @private
        * @method _setupAfterElement
        * @description Creates the accessibility h2 header and places it after the iframe in the Dom for navigation.
        */
        _setupAfterElement: function() {
            if (!this.beforeElement) {
                this.beforeElement = document.createElement('h2');
                this.beforeElement.className = 'yui-editor-skipheader';
                this.beforeElement.tabIndex = '-1';
                this.beforeElement.innerHTML = this.STR_BEFORE_EDITOR;
                this.get('element_cont').get('firstChild').insertBefore(this.beforeElement, this.toolbar.get('nextSibling'));
            }
            if (!this.afterElement) {
                this.afterElement = document.createElement('h2');
                this.afterElement.className = 'yui-editor-skipheader';
                this.afterElement.tabIndex = '-1';
                this.afterElement.innerHTML = this.STR_LEAVE_EDITOR;
                this.get('element_cont').get('firstChild').appendChild(this.afterElement);
            }
        },
        /**
        * @private
        * @method _disableEditor
        * @param {Boolean} disabled Pass true to disable, false to enable
        * @description Creates a mask to place over the Editor.
        */
        _disableEditor: function(disabled) {
            if (disabled) {
                if (!this._mask) {
                    if (!!this.browser.ie) {
                        this._setDesignMode('off');
                    }
                    if (this.toolbar) {
                        this.toolbar.set('disabled', true);
                    }
                    this._mask = document.createElement('DIV');
                    Dom.setStyle(this._mask, 'height', '100%');
                    Dom.setStyle(this._mask, 'width', '100%');
                    Dom.setStyle(this._mask, 'position', 'absolute');
                    Dom.setStyle(this._mask, 'top', '0');
                    Dom.setStyle(this._mask, 'left', '0');
                    Dom.setStyle(this._mask, 'opacity', '.5');
                    Dom.addClass(this._mask, 'yui-editor-masked');
                    this.get('iframe').get('parentNode').appendChild(this._mask);
                }
            } else {
                if (this._mask) {
                    this._mask.parentNode.removeChild(this._mask);
                    this._mask = null;
                    if (this.toolbar) {
                        this.toolbar.set('disabled', false);
                    }
                    this._setDesignMode('on');
                    this._focusWindow();
                    var self = this;
                    window.setTimeout(function() {
                        self.nodeChange.call(self);
                    }, 100);
                }
            }
        },
        /**
        * @property EDITOR_PANEL_ID
        * @description HTML id to give the properties window in the DOM.
        * @type String
        */
        EDITOR_PANEL_ID: 'yui-editor-panel',
        /**
        * @property SEP_DOMPATH
        * @description The value to place in between the Dom path items
        * @type String
        */
        SEP_DOMPATH: '<',
        /**
        * @property STR_LEAVE_EDITOR
        * @description The accessibility string for the element after the iFrame
        * @type String
        */
        STR_LEAVE_EDITOR: 'You have left the Rich Text Editor.',
        /**
        * @property STR_BEFORE_EDITOR
        * @description The accessibility string for the element before the iFrame
        * @type String
        */
        STR_BEFORE_EDITOR: 'This text field can contain stylized text and graphics. To cycle through all formatting options, use the keyboard shortcut Control + Shift + T to place focus on the toolbar and navigate between option heading names. <h4>Common formatting keyboard shortcuts:</h4><ul><li>Control Shift B sets text to bold</li> <li>Control Shift I sets text to italic</li> <li>Control Shift U underlines text</li> <li>Control Shift L adds an HTML link</li> <li>To exit this text editor use the keyboard shortcut Control + Shift + ESC.</li></ul>',
        /**
        * @property STR_TITLE
        * @description The Title of the HTML document that is created in the iFrame
        * @type String
        */
        STR_TITLE: 'Rich Text Area.',
        /**
        * @property STR_IMAGE_HERE
        * @description The text to place in the URL textbox when using the blankimage.
        * @type String
        */
        STR_IMAGE_HERE: 'Image URL Here',
        /**
        * @property STR_LINK_URL
        * @description The label string for the Link URL.
        * @type String
        */
        STR_LINK_URL: 'Link URL',
        /**
        * @protected
        * @property STOP_EXEC_COMMAND
        * @description Set to true when you want the default execCommand function to not process anything
        * @type Boolean
        */
        STOP_EXEC_COMMAND: false,
        /**
        * @protected
        * @property STOP_NODE_CHANGE
        * @description Set to true when you want the default nodeChange function to not process anything
        * @type Boolean
        */
        STOP_NODE_CHANGE: false,
        /**
        * @protected
        * @property CLASS_NOEDIT
        * @description CSS class applied to elements that are not editable.
        * @type String
        */
        CLASS_NOEDIT: 'yui-noedit',
        /**
        * @protected
        * @property CLASS_CONTAINER
        * @description Default CSS class to apply to the editors container element
        * @type String
        */
        CLASS_CONTAINER: 'yui-editor-container',
        /**
        * @protected
        * @property CLASS_EDITABLE
        * @description Default CSS class to apply to the editors iframe element
        * @type String
        */
        CLASS_EDITABLE: 'yui-editor-editable',
        /**
        * @protected
        * @property CLASS_EDITABLE_CONT
        * @description Default CSS class to apply to the editors iframe's parent element
        * @type String
        */
        CLASS_EDITABLE_CONT: 'yui-editor-editable-container',
        /**
        * @protected
        * @property CLASS_PREFIX
        * @description Default prefix for dynamically created class names
        * @type String
        */
        CLASS_PREFIX: 'yui-editor',
        /** 
        * @property browser
        * @description Standard browser detection
        * @type Object
        */
        browser: function() {
            var br = YAHOO.env.ua;
            //Check for webkit3
            if (br.webkit >= 420) {
                br.webkit3 = br.webkit;
            } else {
                br.webkit3 = 0;
            }
            return br;
        }(),
        /** 
        * @method init
        * @description The Editor class' initialization method
        */
        init: function(p_oElement, p_oAttributes) {

            if (!this._defaultToolbar) {
                this._defaultToolbar = {
                    collapse: true,
                    titlebar: 'Text Editing Tools',
                    draggable: false,
                    buttons: [
                        { group: 'fontstyle', label: 'Font Name and Size',
                            buttons: [
                                { type: 'select', label: 'Arial', value: 'fontname', disabled: true,
                                    menu: [
                                        { text: 'Arial', checked: true },
                                        { text: 'Arial Black' },
                                        { text: 'Comic Sans MS' },
                                        { text: 'Courier New' },
                                        { text: 'Lucida Console' },
                                        { text: 'Tahoma' },
                                        { text: 'Times New Roman' },
                                        { text: 'Trebuchet MS' },
                                        { text: 'Verdana' }
                                    ]
                                },
                                { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true }
                            ]
                        },
                        { type: 'separator' },
                        { group: 'textstyle', label: 'Font Style',
                            buttons: [
                                { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' },
                                { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' },
                                { type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' },
                                { type: 'separator' },
                                { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },
                                { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true }
                                
                            ]
                        },
                        { type: 'separator' },
                        { group: 'indentlist', label: 'Lists',
                            buttons: [
                                { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' },
                                { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' }
                            ]
                        },
                        { type: 'separator' },
                        { group: 'insertitem', label: 'Insert Item',
                            buttons: [
                                { type: 'push', label: 'HTML Link CTRL + SHIFT + L', value: 'createlink', disabled: true },
                                { type: 'push', label: 'Insert Image', value: 'insertimage' }
                            ]
                        }
                    ]
                };
            }

            YAHOO.widget.SimpleEditor.superclass.init.call(this, p_oElement, p_oAttributes);
            YAHOO.widget.EditorInfo._instances[this.get('id')] = this;


            this.currentElement = [];
            this.on('contentReady', function() {
                this.DOMReady = true;
                this.fireQueue();
            }, this, true);

        },
        /**
        * @method initAttributes
        * @description Initializes all of the configuration attributes used to create 
        * the editor.
        * @param {Object} attr Object literal specifying a set of 
        * configuration attributes used to create the editor.
        */
        initAttributes: function(attr) {
            YAHOO.widget.SimpleEditor.superclass.initAttributes.call(this, attr);
            var self = this;

            /**
            * @config container
            * @description Used when dynamically creating the Editor from Javascript with no default textarea.
            * We will create one and place it in this container. If no container is passed we will append to document.body.
            * @default false
            * @type HTMLElement
            */
            this.setAttributeConfig('container', {
                writeOnce: true,
                value: attr.container || false
            });
            /**
            * @config plainText
            * @description Process the inital textarea data as if it was plain text. Accounting for spaces, tabs and line feeds.
            * @default false
            * @type Boolean
            */
            this.setAttributeConfig('plainText', {
                writeOnce: true,
                value: attr.plainText || false
            });
            /**
            * @private
            * @config iframe
            * @description Internal config for holding the iframe element.
            * @default null
            * @type HTMLElement
            */
            this.setAttributeConfig('iframe', {
                value: null
            });
            /**
            * @private
            * @depreciated
            * @config textarea
            * @description Internal config for holding the textarea element (replaced with element).
            * @default null
            * @type HTMLElement
            */
            this.setAttributeConfig('textarea', {
                value: null,
                writeOnce: true
            });
            /**
            * @private
            * @config container
            * @description Internal config for holding a reference to the container to append a dynamic editor to.
            * @default null
            * @type HTMLElement
            */
            this.setAttributeConfig('container', {
                readOnly: true,
                value: null
            });
            /**
            * @config nodeChangeThreshold
            * @description The number of seconds that need to be in between nodeChange processing
            * @default 3
            * @type Number
            */            
            this.setAttributeConfig('nodeChangeThreshold', {
                value: attr.nodeChangeThreshold || 3,
                validator: YAHOO.lang.isNumber
            });
            /**
            * @config allowNoEdit
            * @description Should the editor check for non-edit fields. It should be noted that this technique is not perfect. If the user does the right things, they will still be able to make changes.
            * Such as highlighting an element below and above the content and hitting a toolbar button or a shortcut key.
            * @default false
            * @type Boolean
            */            
            this.setAttributeConfig('allowNoEdit', {
                value: attr.allowNoEdit || false,
                validator: YAHOO.lang.isBoolean
            });
            /**
            * @config limitCommands
            * @description Should the Editor limit the allowed execCommands to the ones available in the toolbar. If true, then execCommand and keyboard shortcuts will fail if they are not defined in the toolbar.
            * @default false
            * @type Boolean
            */            
            this.setAttributeConfig('limitCommands', {
                value: attr.limitCommands || false,
                validator: YAHOO.lang.isBoolean
            });
            /**
            * @config element_cont
            * @description Internal config for the editors container
            * @default false
            * @type HTMLElement
            */
            this.setAttributeConfig('element_cont', {
                value: attr.element_cont
            });
            /**
            * @private
            * @config editor_wrapper
            * @description The outter wrapper for the entire editor.
            * @default null
            * @type HTMLElement
            */
            this.setAttributeConfig('editor_wrapper', {
                value: attr.editor_wrapper || null,
                writeOnce: true
            });
            /**
            * @attribute height
            * @description The height of the editor iframe container, not including the toolbar..
            * @default Best guessed size of the textarea, for best results use CSS to style the height of the textarea or pass it in as an argument
            * @type String
            */
            this.setAttributeConfig('height', {
                value: attr.height || Dom.getStyle(self.get('element'), 'height'),
                method: function(height) {
                    if (this._rendered) {
                        //We have been rendered, change the height
                        if (this.get('animate')) {
                            var anim = new YAHOO.util.Anim(this.get('iframe').get('parentNode'), {
                                height: {
                                    to: parseInt(height, 10)
                                }
                            }, 0.5);
                            anim.animate();
                        } else {
                            Dom.setStyle(this.get('iframe').get('parentNode'), 'height', height);
                        }
                    }
                }
            });
            /**
            * @config autoHeight
            * @description Remove the scrollbars from the edit area and resize it to fit the content. It will not go any lower than the current config height.
            * @default false
            * @type Boolean || Number
            */
            this.setAttributeConfig('autoHeight', {
                value: attr.autoHeight || false,
                method: function(a) {
                    if (a) {
                        if (this.get('iframe')) {
                            this.get('iframe').get('element').setAttribute('scrolling', 'no');
                        }
                        this.on('afterNodeChange', this._handleAutoHeight, this, true);
                        this.on('editorKeyDown', this._handleAutoHeight, this, true);
                        this.on('editorKeyPress', this._handleAutoHeight, this, true);
                    } else {
                        if (this.get('iframe')) {
                            this.get('iframe').get('element').setAttribute('scrolling', 'auto');
                        }
                        this.unsubscribe('afterNodeChange', this._handleAutoHeight);
                        this.unsubscribe('editorKeyDown', this._handleAutoHeight);
                        this.unsubscribe('editorKeyPress', this._handleAutoHeight);
                    }
                }
            });
            /**
            * @attribute width
            * @description The width of the editor container.
            * @default Best guessed size of the textarea, for best results use CSS to style the width of the textarea or pass it in as an argument
            * @type String
            */            
            this.setAttributeConfig('width', {
                value: attr.width || Dom.getStyle(this.get('element'), 'width'),
                method: function(width) {
                    if (this._rendered) {
                        //We have been rendered, change the width
                        if (this.get('animate')) {
                            var anim = new YAHOO.util.Anim(this.get('element_cont').get('element'), {
                                width: {
                                    to: parseInt(width, 10)
                                }
                            }, 0.5);
                            anim.animate();
                        } else {
                            this.get('element_cont').setStyle('width', width);
                        }
                    }
                }
            });
                        
            /**
            * @attribute blankimage
            * @description The URL for the image placeholder to put in when inserting an image.
            * @default The yahooapis.com address for the current release + 'assets/blankimage.png'
            * @type String
            */            
            this.setAttributeConfig('blankimage', {
                value: attr.blankimage || this._getBlankImage()
            });
            /**
            * @attribute css
            * @description The Base CSS used to format the content of the editor
            * @default <code><pre>html {
                height: 95%;
            }
            body {
                height: 100%;
                padding: 7px; background-color: #fff; font:13px/1.22 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;
            }
            a {
                color: blue;
                text-decoration: underline;
                cursor: pointer;
            }
            .warning-localfile {
                border-bottom: 1px dashed red !important;
            }
            .yui-busy {
                cursor: wait !important;
            }
            img.selected { //Safari image selection
                border: 2px dotted #808080;
            }
            img {
                cursor: pointer !important;
                border: none;
            }
            </pre></code>
            * @type String
            */            
            this.setAttributeConfig('css', {
                value: attr.css || this._defaultCSS,
                writeOnce: true
            });
            /**
            * @attribute html
            * @description The default HTML to be written to the iframe document before the contents are loaded (Note that the DOCTYPE attr will be added at render item)
            * @default This HTML requires a few things if you are to override:
                <p><code>{TITLE}, {CSS}, {HIDDEN_CSS}, {EXTRA_CSS}</code> and <code>{CONTENT}</code> need to be there, they are passed to YAHOO.lang.substitute to be replace with other strings.<p>
                <p><code>onload="document.body._rteLoaded = true;"</code> : the onload statement must be there or the editor will not finish loading.</p>
                <code>
                <pre>
                &lt;html&gt;
                    &lt;head&gt;
                        &lt;title&gt;{TITLE}&lt;/title&gt;
                        &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
                        &lt;style&gt;
                        {CSS}
                        &lt;/style&gt;
                        &lt;style&gt;
                        {HIDDEN_CSS}
                        &lt;/style&gt;
                        &lt;style&gt;
                        {EXTRA_CSS}
                        &lt;/style&gt;
                    &lt;/head&gt;
                &lt;body onload="document.body._rteLoaded = true;"&gt;
                {CONTENT}
                &lt;/body&gt;
                &lt;/html&gt;
                </pre>
                </code>
            * @type String
            */            
            this.setAttributeConfig('html', {
                value: attr.html || '<html><head><title>{TITLE}</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><base href="' + this._baseHREF + '"><style>{CSS}</style><style>{HIDDEN_CSS}</style><style>{EXTRA_CSS}</style></head><body onload="document.body._rteLoaded = true;">{CONTENT}</body></html>',
                writeOnce: true
            });

            /**
            * @attribute extracss
            * @description Extra user defined css to load after the default SimpleEditor CSS
            * @default ''
            * @type String
            */            
            this.setAttributeConfig('extracss', {
                value: attr.extracss || '',
                writeOnce: true
            });

            /**
            * @attribute handleSubmit
            * @description Config handles if the editor will attach itself to the textareas parent form's submit handler.
            If it is set to true, the editor will attempt to attach a submit listener to the textareas parent form.
            Then it will trigger the editors save handler and place the new content back into the text area before the form is submitted.
            * @default false
            * @type Boolean
            */            
            this.setAttributeConfig('handleSubmit', {
                value: attr.handleSubmit || false,
                method: function(exec) {
                    if (this.get('element').form) {
                        if (!this._formButtons) {
                            this._formButtons = [];
                        }
                        if (exec) {
                            Event.on(this.get('element').form, 'submit', this._handleFormSubmit, this, true);
                            var i = this.get('element').form.getElementsByTagName('input');
                            for (var s = 0; s < i.length; s++) {
                                var type = i[s].getAttribute('type');
                                if (type && (type.toLowerCase() == 'submit')) {
                                    Event.on(i[s], 'click', this._handleFormButtonClick, this, true);
                                    this._formButtons[this._formButtons.length] = i[s];
                                }
                            }
                        } else {
                            Event.removeListener(this.get('element').form, 'submit', this._handleFormSubmit);
                            if (this._formButtons) {
                                Event.removeListener(this._formButtons, 'click', this._handleFormButtonClick);
                            }
                        }
                    }
                }
            });
            /**
            * @attribute disabled
            * @description This will toggle the editor's disabled state. When the editor is disabled, designMode is turned off and a mask is placed over the iframe so no interaction can take place.
            All Toolbar buttons are also disabled so they cannot be used.
            * @default false
            * @type Boolean
            */

            this.setAttributeConfig('disabled', {
                value: false,
                method: function(disabled) {
                    if (this._rendered) {
                        this._disableEditor(disabled);
                    }
                }
            });
            /**
            * @config toolbar_cont
            * @description Internal config for the toolbars container
            * @default false
            * @type Boolean
            */
            this.setAttributeConfig('toolbar_cont', {
                value: null,
                writeOnce: true
            });
            /**
            * @attribute toolbar
            * @description The default toolbar config.
            * @type Object
            */            
            this.setAttributeConfig('toolbar', {
                value: attr.toolbar || this._defaultToolbar,
                writeOnce: true,
                method: function(toolbar) {
                    if (!toolbar.buttonType) {
                        toolbar.buttonType = this._defaultToolbar.buttonType;
                    }
                    this._defaultToolbar = toolbar;
                }
            });
            /**
            * @attribute animate
            * @description Should the editor animate window movements
            * @default false unless Animation is found, then true
            * @type Boolean
            */            
            this.setAttributeConfig('animate', {
                value: ((attr.animate) ? ((YAHOO.util.Anim) ? true : false) : false),
                validator: function(value) {
                    var ret = true;
                    if (!YAHOO.util.Anim) {
                        ret = false;
                    }
                    return ret;
                }
            });
            /**
            * @config panel
            * @description A reference to the panel we are using for windows.
            * @default false
            * @type Boolean
            */            
            this.setAttributeConfig('panel', {
                value: null,
                writeOnce: true,
                validator: function(value) {
                    var ret = true;
                    if (!YAHOO.widget.Overlay) {
                        ret = false;
                    }
                    return ret;
                }               
            });
            /**
            * @attribute focusAtStart
            * @description Should we focus the window when the content is ready?
            * @default false
            * @type Boolean
            */            
            this.setAttributeConfig('focusAtStart', {
                value: attr.focusAtStart || false,
                writeOnce: true,
                method: function() {
                    this.on('editorContentLoaded', function() {
                        var self = this;
                        setTimeout(function() {
                            self._focusWindow.call(self, true);
                            self.editorDirty = false;
                        }, 400);
                    }, this, true);
                }
            });
            /**
            * @attribute dompath
            * @description Toggle the display of the current Dom path below the editor
            * @default false
            * @type Boolean
            */            
            this.setAttributeConfig('dompath', {
                value: attr.dompath || false,
                method: function(dompath) {
                    if (dompath && !this.dompath) {
                        this.dompath = document.createElement('DIV');
                        this.dompath.id = this.get('id') + '_dompath';
                        Dom.addClass(this.dompath, 'dompath');
                        this.get('element_cont').get('firstChild').appendChild(this.dompath);
                        if (this.get('iframe')) {
                            this._writeDomPath();
                        }
                    } else if (!dompath && this.dompath) {
                        this.dompath.parentNode.removeChild(this.dompath);
                        this.dompath = null;
                    }
                }
            });
            /**
            * @attribute markup
            * @description Should we try to adjust the markup for the following types: semantic, css, default or xhtml
            * @default "semantic"
            * @type String
            */            
            this.setAttributeConfig('markup', {
                value: attr.markup || 'semantic',
                validator: function(markup) {
                    switch (markup.toLowerCase()) {
                        case 'semantic':
                        case 'css':
                        case 'default':
                        case 'xhtml':
                        return true;
                    }
                    return false;
                }
            });
            /**
            * @attribute removeLineBreaks
            * @description Should we remove linebreaks and extra spaces on cleanup
            * @default false
            * @type Boolean
            */            
            this.setAttributeConfig('removeLineBreaks', {
                value: attr.removeLineBreaks || false,
                validator: YAHOO.lang.isBoolean
            });
            

            this.on('afterRender', function() {
                this._renderPanel();
            });
        },
        /**
        * @private
        * @method _getBlankImage
        * @description Retrieves the full url of the image to use as the blank image.
        * @return {String} The URL to the blank image
        */
        _getBlankImage: function() {
            if (!this.DOMReady) {
                this._queue[this._queue.length] = ['_getBlankImage', arguments];
                return '';
            }
            var img = '';
            if (!this._blankImageLoaded) {
                if (YAHOO.widget.EditorInfo.blankImage) {
                    this.set('blankimage', YAHOO.widget.EditorInfo.blankImage);
                    this._blankImageLoaded = true;
                } else {
                    var div = document.createElement('div');
                    div.style.position = 'absolute';
                    div.style.top = '-9999px';
                    div.style.left = '-9999px';
                    div.className = this.CLASS_PREFIX + '-blankimage';
                    document.body.appendChild(div);
                    img = YAHOO.util.Dom.getStyle(div, 'background-image');
                    img = img.replace('url(', '').replace(')', '').replace(/"/g, '');
                    //Adobe AIR Code
                    img = img.replace('app:/', '');                    
                    this.set('blankimage', img);
                    this._blankImageLoaded = true;
                    YAHOO.widget.EditorInfo.blankImage = img;
                }
            } else {
                img = this.get('blankimage');
            }
            return img;
        },
        /**
        * @private
        * @method _handleAutoHeight
        * @description Handles resizing the editor's height based on the content
        */
        _handleAutoHeight: function() {
            var doc = this._getDoc(),
                body = doc.body,
                docEl = doc.documentElement;

            var height = parseInt(Dom.getStyle(this.get('editor_wrapper'), 'height'), 10);
            var newHeight = body.scrollHeight;
            if (this.browser.webkit) {
                newHeight = docEl.scrollHeight;
            }
            if (newHeight < parseInt(this.get('height'), 10)) {
                newHeight = parseInt(this.get('height'), 10);
            }
            if ((height != newHeight) && (newHeight >= parseInt(this.get('height'), 10))) {   
                Dom.setStyle(this.get('editor_wrapper'), 'height', newHeight + 'px');
                if (this.browser.ie) {
                    //Internet Explorer needs this
                    this.get('iframe').setStyle('height', '99%');
                    this.get('iframe').setStyle('zoom', '1');
                    var self = this;
                    window.setTimeout(function() {
                        self.get('iframe').setStyle('height', '100%');
                    }, 1);
                }
            }
        },
        _formButtons: null,
        _formButtonClicked: null,
        _handleFormButtonClick: function(ev) {
            var tar = Event.getTarget(ev);
            this._formButtonClicked = tar;
        },
        /**
        * @private
        * @method _handleFormSubmit
        * @description Handles the form submission.
        * @param {Object} ev The Form Submit Event
        */
        _handleFormSubmit: function(ev) {
            Event.stopEvent(ev);
            
            this.saveHTML();
            var form = this.get('element').form;
            var tar = this._formButtonClicked || false;
            var self = this;

            window.setTimeout(function() {
                YAHOO.util.Event.removeListener(form, 'submit', self._handleFormSubmit);
                if (YAHOO.env.ua.ie) {
                    form.fireEvent("onsubmit");
                    if (tar && !tar.disabled) {
                        tar.click();
                    }
                } else {  // Gecko, Opera, and Safari
                    if (tar && !tar.disabled) {
                        tar.click();
                    } else {
                        var oEvent = document.createEvent("HTMLEvents");
                        oEvent.initEvent("submit", true, true);
                        form.dispatchEvent(oEvent);
                        if (YAHOO.env.ua.webkit) {
                            if (YAHOO.lang.isFunction(form.submit)) {
                                form.submit();
                            }
                        }
                    }
                }
            }, 200);
            
        },
        /**
        * @private
        * @method _handleFontSize
        * @description Handles the font size button in the toolbar.
        * @param {Object} o Object returned from Toolbar's buttonClick Event
        */
        _handleFontSize: function(o) {
            var button = this.toolbar.getButtonById(o.button.id);
            var value = button.get('label') + 'px';
            this.execCommand('fontsize', value);
            this.STOP_EXEC_COMMAND = true;
        },
        /**
        * @private
        * @description Handles the colorpicker buttons in the toolbar.
        * @param {Object} o Object returned from Toolbar's buttonClick Event
        */
        _handleColorPicker: function(o) {
            var cmd = o.button;
            var value = '#' + o.color;
            if ((cmd == 'forecolor') || (cmd == 'backcolor')) {
                this.execCommand(cmd, value);
            }
        },
        /**
        * @private
        * @method _handleAlign
        * @description Handles the alignment buttons in the toolbar.
        * @param {Object} o Object returned from Toolbar's buttonClick Event
        */
        _handleAlign: function(o) {
            var cmd = null;
            for (var i = 0; i < o.button.menu.length; i++) {
                if (o.button.menu[i].value == o.button.value) {
                    cmd = o.button.menu[i].value;
                }
            }
            var value = this._getSelection();

            this.execCommand(cmd, value);
            this.STOP_EXEC_COMMAND = true;
        },
        /**
        * @private
        * @method _handleAfterNodeChange
        * @description Fires after a nodeChange happens to setup the things that where reset on the node change (button state).
        */
        _handleAfterNodeChange: function() {
            var path = this._getDomPath(),
                elm = null,
                family = null,
                fontsize = null,
                validFont = false;
            var fn_button = this.toolbar.getButtonByValue('fontname');
            var fs_button = this.toolbar.getButtonByValue('fontsize');
            var hd_button = this.toolbar.getButtonByValue('heading');

            for (var i = 0; i < path.length; i++) {
                elm = path[i];

                var tag = elm.tagName.toLowerCase();


                if (elm.getAttribute('tag')) {
                    tag = elm.getAttribute('tag');
                }

                family = elm.getAttribute('face');
                if (Dom.getStyle(elm, 'font-family')) {
                    family = Dom.getStyle(elm, 'font-family');
                    //Adobe AIR Code
                    family = family.replace(/'/g, '');                    
                }

                if (tag.substring(0, 1) == 'h') {
                    if (hd_button) {
                        for (var h = 0; h < hd_button._configs.menu.value.length; h++) {
                            if (hd_button._configs.menu.value[h].value.toLowerCase() == tag) {
                                hd_button.set('label', hd_button._configs.menu.value[h].text);
                            }
                        }
                        this._updateMenuChecked('heading', tag);
                    }
                }
            }

            if (fn_button) {
                for (var b = 0; b < fn_button._configs.menu.value.length; b++) {
                    if (family && fn_button._configs.menu.value[b].text.toLowerCase() == family.toLowerCase()) {
                        validFont = true;
                        family = fn_button._configs.menu.value[b].text; //Put the proper menu name in the button
                    }
                }
                if (!validFont) {
                    family = fn_button._configs.label._initialConfig.value;
                }
                var familyLabel = '<span class="yui-toolbar-fontname-' + _cleanClassName(family) + '">' + family + '</span>';
                if (fn_button.get('label') != familyLabel) {
                    fn_button.set('label', familyLabel);
                    this._updateMenuChecked('fontname', family);
                }
            }

            if (fs_button) {
                fontsize = parseInt(Dom.getStyle(elm, 'fontSize'), 10);
                if ((fontsize === null) || isNaN(fontsize)) {
                    fontsize = fs_button._configs.label._initialConfig.value;
                }
                fs_button.set('label', ''+fontsize);
            }
            
            if (!this._isElement(elm, 'body') && !this._isElement(elm, 'img')) {
                this.toolbar.enableButton(fn_button);
                this.toolbar.enableButton(fs_button);
                this.toolbar.enableButton('forecolor');
                this.toolbar.enableButton('backcolor');
            }
            if (this._isElement(elm, 'img')) {
                if (YAHOO.widget.Overlay) {
                    this.toolbar.enableButton('createlink');
                }
            }
            if (this._isElement(elm, 'blockquote')) {
                this.toolbar.selectButton('indent');
                this.toolbar.disableButton('indent');
                this.toolbar.enableButton('outdent');
            }
            if (this._hasParent(elm, 'ol') || this._hasParent(elm, 'ul')) {
                this.toolbar.disableButton('indent');
            }
            this._lastButton = null;
            
        },
        _setBusy: function(off) {
            /*
            if (off) {
                Dom.removeClass(document.body, 'yui-busy');
                Dom.removeClass(this._getDoc().body, 'yui-busy');
            } else {
                Dom.addClass(document.body, 'yui-busy');
                Dom.addClass(this._getDoc().body, 'yui-busy');
            }
            */
        },
        /**
        * @private
        * @method _handleInsertImageClick
        * @description Opens the Image Properties Window when the insert Image button is clicked or an Image is Double Clicked.
        */
        _handleInsertImageClick: function() {
            if (this.get('limitCommands')) {
                if (!this.toolbar.getButtonByValue('insertimage')) {
                    return false;
                }
            }
        
            this.toolbar.set('disabled', true); //Disable the toolbar when the prompt is showing
            this.on('afterExecCommand', function() {
                var el = this.currentElement[0],
                    src = 'http://';
                if (!el) {
                    el = this._getSelectedElement();
                }
                if (el) {
                    if (el.getAttribute('src')) {
                        src = el.getAttribute('src', 2);
                        if (src.indexOf(this.get('blankimage')) != -1) {
                            src = this.STR_IMAGE_HERE;
                        }
                    }
                }
                var str = prompt(this.STR_LINK_URL + ': ', src);
                if ((str !== '') && (str !== null)) {
                    el.setAttribute('src', str);
                } else if (str === null) {
                    el.parentNode.removeChild(el);
                    this.currentElement = [];
                    this.nodeChange();
                }
                this.closeWindow();
                this.toolbar.set('disabled', false);
            }, this, true);
        },
        /**
        * @private
        * @method _handleInsertImageWindowClose
        * @description Handles the closing of the Image Properties Window.
        */
        _handleInsertImageWindowClose: function() {
            this.nodeChange();
        },
        /**
        * @private
        * @method _isLocalFile
        * @param {String} url THe url/string to check
        * @description Checks to see if a string (href or img src) is possibly a local file reference..
        */
        _isLocalFile: function(url) {
            if ((url !== '') && ((url.indexOf('file:/') != -1) || (url.indexOf(':\\') != -1))) {
                return true;
            }
            return false;
        },
        /**
        * @private
        * @method _handleCreateLinkClick
        * @description Handles the opening of the Link Properties Window when the Create Link button is clicked or an href is doubleclicked.
        */
        _handleCreateLinkClick: function() {
            if (this.get('limitCommands')) {
                if (!this.toolbar.getButtonByValue('createlink')) {
                    return false;
                }
            }
        
            this.toolbar.set('disabled', true); //Disable the toolbar when the prompt is showing
            this.on('afterExecCommand', function() {
                var el = this.currentElement[0],
                    url = '';

                if (el) {
                    if (el.getAttribute('href', 2) !== null) {
                        url = el.getAttribute('href', 2);
                    }
                }
                var str = prompt(this.STR_LINK_URL + ': ', url);
                if ((str !== '') && (str !== null)) {
                    var urlValue = str;
                    if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
                        if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
                            //Found an @ sign, prefix with mailto:
                            urlValue = 'mailto:' + urlValue;
                        } else {
                            /* :// not found adding */
                            if (urlValue.substring(0, 1) != '#') {
                                urlValue = 'http:/'+'/' + urlValue;
                            }
                        }
                    }
                    el.setAttribute('href', urlValue);
                } else if (str !== null) {
                    var _span = this._getDoc().createElement('span');
                    _span.innerHTML = el.innerHTML;
                    Dom.addClass(_span, 'yui-non');
                    el.parentNode.replaceChild(_span, el);
                }
                this.closeWindow();
                this.toolbar.set('disabled', false);
            });
        },
        /**
        * @private
        * @method _handleCreateLinkWindowClose
        * @description Handles the closing of the Link Properties Window.
        */
        _handleCreateLinkWindowClose: function() {
            this.nodeChange();
            this.currentElement = [];
        },
        /**
        * @method render
        * @description Calls the private method _render in a setTimeout to allow for other things on the page to continue to load.
        */
        render: function() {
            if (this._rendered) {
                return false;
            }
            if (!this.DOMReady) {
                this._queue[this._queue.length] = ['render', arguments];
                return false;
            }
            this._rendered = true;
            var self = this;
            window.setTimeout(function() {
                self._render.call(self);
            }, 4);
        },
        /**
        * @private
        * @method _render
        * @description Causes the toolbar and the editor to render and replace the textarea.
        */
        _render: function() {
            this._setBusy();
            var self = this;
            this.set('textarea', this.get('element'));

            this.get('element_cont').setStyle('display', 'none');
            this.get('element_cont').addClass(this.CLASS_CONTAINER);

            this.set('iframe', this._createIframe());
            window.setTimeout(function() {
                self._setInitialContent.call(self);
            }, 10);

            this.get('editor_wrapper').appendChild(this.get('iframe').get('element'));

            if (this.get('disabled')) {
                this._disableEditor(true);
            }

            var tbarConf = this.get('toolbar');
            //Create Toolbar instance
            if (tbarConf instanceof Toolbar) {
                this.toolbar = tbarConf;
                //Set the toolbar to disabled until content is loaded
                this.toolbar.set('disabled', true);
            } else {
                //Set the toolbar to disabled until content is loaded
                tbarConf.disabled = true;
                this.toolbar = new Toolbar(this.get('toolbar_cont'), tbarConf);
            }

            this.fireEvent('toolbarLoaded', { type: 'toolbarLoaded', target: this.toolbar });

            
            this.toolbar.on('toolbarCollapsed', function() {
                if (this.currentWindow) {
                    this.moveWindow();
                }
            }, this, true);
            this.toolbar.on('toolbarExpanded', function() {
                if (this.currentWindow) {
                    this.moveWindow();
                }
            }, this, true);
            this.toolbar.on('fontsizeClick', function(o) {
                this._handleFontSize(o);
            }, this, true);
            
            this.toolbar.on('colorPickerClicked', function(o) {
                this._handleColorPicker(o);
                return false; //Stop the buttonClick event
            }, this, true);

            this.toolbar.on('alignClick', function(o) {
                this._handleAlign(o);
            }, this, true);
            this.on('afterNodeChange', function() {
                this._handleAfterNodeChange();
            }, this, true);
            this.toolbar.on('insertimageClick', function() {
                this._handleInsertImageClick();
            }, this, true);
            this.on('windowinsertimageClose', function() {
                this._handleInsertImageWindowClose();
            }, this, true);
            this.toolbar.on('createlinkClick', function() {
                this._handleCreateLinkClick();
            }, this, true);
            this.on('windowcreatelinkClose', function() {
                this._handleCreateLinkWindowClose();
            }, this, true);
            

            //Replace Textarea with editable area
            this.get('parentNode').replaceChild(this.get('element_cont').get('element'), this.get('element'));

            
            this.setStyle('visibility', 'hidden');
            this.setStyle('position', 'absolute');
            this.setStyle('top', '-9999px');
            this.setStyle('left', '-9999px');
            this.get('element_cont').appendChild(this.get('element'));
            this.get('element_cont').setStyle('display', 'block');


            Dom.addClass(this.get('iframe').get('parentNode'), this.CLASS_EDITABLE_CONT);
            this.get('iframe').addClass(this.CLASS_EDITABLE);

            //Set height and width of editor container
            this.get('element_cont').setStyle('width', this.get('width'));
            Dom.setStyle(this.get('iframe').get('parentNode'), 'height', this.get('height'));

            this.get('iframe').setStyle('width', '100%'); //WIDTH
            this.get('iframe').setStyle('height', '100%');

            window.setTimeout(function() {
                self._setupAfterElement.call(self);
            }, 0);
            this.fireEvent('afterRender', { type: 'afterRender', target: this });
        },
        /**
        * @method execCommand
        * @param {String} action The "execCommand" action to try to execute (Example: bold, insertimage, inserthtml)
        * @param {String} value (optional) The value for a given action such as action: fontname value: 'Verdana'
        * @description This method attempts to try and level the differences in the various browsers and their support for execCommand actions
        */
        execCommand: function(action, value) {
            var beforeExec = this.fireEvent('beforeExecCommand', { type: 'beforeExecCommand', target: this, args: arguments });
            if ((beforeExec === false) || (this.STOP_EXEC_COMMAND)) {
                this.STOP_EXEC_COMMAND = false;
                return false;
            }
            this._setMarkupType(action);
            if (this.browser.ie) {
                this._getWindow().focus();
            }
            var exec = true;
            
            if (this.get('limitCommands')) {
                if (!this.toolbar.getButtonByValue(action)) {
                    exec = false;
                }
            }

            this.editorDirty = true;
            
            if ((typeof this['cmd_' + action.toLowerCase()] == 'function') && exec) {
                var retValue = this['cmd_' + action.toLowerCase()](value);
                exec = retValue[0];
                if (retValue[1]) {
                    action = retValue[1];
                }
                if (retValue[2]) {
                    value = retValue[2];
                }
            }
            if (exec) {
                try {
                    this._getDoc().execCommand(action, false, value);
                } catch(e) {
                }
            } else {
            }
            this.on('afterExecCommand', function() {
                this.unsubscribeAll('afterExecCommand');
                this.nodeChange();
            });
            this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
            
        },
    /* {{{  Command Overrides */

        /**
        * @method cmd_backcolor
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('backcolor') is used.
        */
        cmd_backcolor: function(value) {
            var exec = true,
                el = this._getSelectedElement(),
                action = 'backcolor';

            if (this.browser.gecko || this.browser.opera) {
                this._setEditorStyle(true);
                action = 'hilitecolor';
            }
            /**
            * @browser opera
            * @knownissue - Opera fails to assign a background color on an element that already has one.
            *
            if (this.browser.opera) {
                if (!this._isElement(el, 'body') && Dom.getStyle(el, 'background-color')) {
                    Dom.setStyle(el, 'background-color', value);
                } else {
                    this._createCurrentElement('span', { backgroundColor: value });
                }
                exec = false;
            //} else if (!this._hasSelection()) {
            } else if (el !== this._getDoc().body) {
                Dom.setStyle(el, 'background-color', value);
                this._selectNode(el);
                exec = false;
            } else {
                this._createCurrentElement('span', { backgroundColor: value });
                this._selectNode(this.currentElement[0]);
                exec = false;
            }*/

            if (!this._isElement(el, 'body') && !this._hasSelection()) {            
                Dom.setStyle(el, 'background-color', value);
                this._selectNode(el);
                exec = false;
            } else {
                this._createCurrentElement('span', { backgroundColor: value });
                this._selectNode(this.currentElement[0]);
                exec = false;
            }

            return [exec, action];
        },
        /**
        * @method cmd_forecolor
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('forecolor') is used.
        */
        cmd_forecolor: function(value) {
            var exec = true,
                el = this._getSelectedElement();

                if (!this._isElement(el, 'body') && !this._hasSelection()) {            
                    Dom.setStyle(el, 'color', value);
                    this._selectNode(el);
                    exec = false;
                } else {
                    this._createCurrentElement('span', { color: value });
                    this._selectNode(this.currentElement[0]);
                    exec = false;
                }
                return [exec];
        },
        /**
        * @method cmd_unlink
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('unlink') is used.
        */
        cmd_unlink: function(value) {
            this._swapEl(this.currentElement[0], 'span', function(el) {
                el.className = 'yui-non';
            });
            return [false];
        },
        /**
        * @method cmd_createlink
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('createlink') is used.
        */
        cmd_createlink: function(value) {
            var el = this._getSelectedElement(), _a = null;
            if (this._hasParent(el, 'a')) {
                this.currentElement[0] = this._hasParent(el, 'a');
            } else if (!this._isElement(el, 'a')) {
                this._createCurrentElement('a');
                _a = this._swapEl(this.currentElement[0], 'a');
                this.currentElement[0] = _a;
            } else {
                this.currentElement[0] = el;
            }
            return [false];
        },
        /**
        * @method cmd_insertimage
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertimage') is used.
        */
        cmd_insertimage: function(value) {
            var exec = true, _img = null, action = 'insertimage',
                el = this._getSelectedElement();

            if (value === '') {
                value = this.get('blankimage');
            }

            /**
            * @knownissue
            * @browser Safari 2.x
            * @description The issue here is that we have no way of knowing where the cursor position is
            * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
            */
            
            if (this._isElement(el, 'img')) {
                this.currentElement[0] = el;
                exec = false;
            } else {
                if (this._getDoc().queryCommandEnabled(action)) {
                    this._getDoc().execCommand('insertimage', false, value);
                    var imgs = this._getDoc().getElementsByTagName('img');
                    for (var i = 0; i < imgs.length; i++) {
                        if (!YAHOO.util.Dom.hasClass(imgs[i], 'yui-img')) {
                            YAHOO.util.Dom.addClass(imgs[i], 'yui-img');
                            this.currentElement[0] = imgs[i];
                        }
                    }
                    exec = false;
                } else {
                    if (el == this._getDoc().body) {
                        _img = this._getDoc().createElement('img');
                        _img.setAttribute('src', value);
                        YAHOO.util.Dom.addClass(_img, 'yui-img');
                        this._getDoc().body.appendChild(_img);
                    } else {
                        this._createCurrentElement('img');
                        _img = this._getDoc().createElement('img');
                        _img.setAttribute('src', value);
                        YAHOO.util.Dom.addClass(_img, 'yui-img');
                        this.currentElement[0].parentNode.replaceChild(_img, this.currentElement[0]);
                    }
                    this.currentElement[0] = _img;
                    exec = false;
                }
            }
            return [exec];
        },
        /**
        * @method cmd_inserthtml
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('inserthtml') is used.
        */
        cmd_inserthtml: function(value) {
            var exec = true, action = 'inserthtml', _span = null, _range = null;
            /**
            * @knownissue
            * @browser Safari 2.x
            * @description The issue here is that we have no way of knowing where the cursor position is
            * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
            */
            if (this.browser.webkit && !this._getDoc().queryCommandEnabled(action)) {
                this._createCurrentElement('img');
                _span = this._getDoc().createElement('span');
                _span.innerHTML = value;
                this.currentElement[0].parentNode.replaceChild(_span, this.currentElement[0]);
                exec = false;
            } else if (this.browser.ie) {
                _range = this._getRange();
                if (_range.item) {
                    _range.item(0).outerHTML = value;
                } else {
                    _range.pasteHTML(value);
                }
                exec = false;                    
            }
            return [exec];
        },
        /**
        * @method cmd_list
        * @param tag The tag of the list you want to create (eg, ul or ol)
        * @description This is a combined execCommand override method. It is called from the cmd_insertorderedlist and cmd_insertunorderedlist methods.
        */
        cmd_list: function(tag) {
            var exec = true, list = null, li = 0, el = null, str = '',
                selEl = this._getSelectedElement(), action = 'insertorderedlist';
                if (tag == 'ul') {
                    action = 'insertunorderedlist';
                }
            /**
            * @knownissue Safari 2.+ doesn't support ordered and unordered lists
            * @browser Safari 2.x
            * The issue with this workaround is that when applied to a set of text
            * that has BR's in it, Safari may or may not pick up the individual items as
            * list items. This is fixed in WebKit (Safari 3)
            */
            if ((this.browser.webkit && !this._getDoc().queryCommandEnabled(action))) {
                if (this._isElement(selEl, 'li') && this._isElement(selEl.parentNode, tag)) {
                    el = selEl.parentNode;
                    list = this._getDoc().createElement('span');
                    YAHOO.util.Dom.addClass(list, 'yui-non');
                    str = '';
                    var lis = el.getElementsByTagName('li');
                    for (li = 0; li < lis.length; li++) {
                        str += '<div>' + lis[li].innerHTML + '</div>';
                    }
                    list.innerHTML = str;
                    this.currentElement[0] = el;
                    this.currentElement[0].parentNode.replaceChild(list, this.currentElement[0]);
                } else {
                    this._createCurrentElement(tag.toLowerCase());
                    list = this._getDoc().createElement(tag);
                    for (li = 0; li < this.currentElement.length; li++) {
                        var newli = this._getDoc().createElement('li');
                        newli.innerHTML = this.currentElement[li].innerHTML + '<span class="yui-non">&nbsp;</span>&nbsp;';
                        list.appendChild(newli);
                        if (li > 0) {
                            this.currentElement[li].parentNode.removeChild(this.currentElement[li]);
                        }
                    }
                    this.currentElement[0].parentNode.replaceChild(list, this.currentElement[0]);
                    this.currentElement[0] = list;
                    var _h = this.currentElement[0].firstChild;
                    _h = Dom.getElementsByClassName('yui-non', 'span', _h)[0];
                    this._getSelection().setBaseAndExtent(_h, 1, _h, _h.innerText.length);
                }
                exec = false;
            } else {
                el = this._getSelectedElement();
                if (this._isElement(el, 'li') && this._isElement(el.parentNode, tag) || (this.browser.ie && this._isElement(this._getRange().parentElement, 'li')) || (this.browser.ie && this._isElement(el, 'ul')) || (this.browser.ie && this._isElement(el, 'ol'))) { //we are in a list..
                    if (this.browser.ie) {
                        if ((this.browser.ie && this._isElement(el, 'ul')) || (this.browser.ie && this._isElement(el, 'ol'))) {
                            el = el.getElementsByTagName('li')[0];
                        }
                        str = '';
                        var lis2 = el.parentNode.getElementsByTagName('li');
                        for (var j = 0; j < lis2.length; j++) {
                            str += lis2[j].innerHTML + '<br>';
                        }
                        var newEl = this._getDoc().createElement('span');
                        newEl.innerHTML = str;
                        el.parentNode.parentNode.replaceChild(newEl, el.parentNode);
                    } else {
                        this.nodeChange();
                        this._getDoc().execCommand(action, '', el.parentNode);
                        this.nodeChange();
                    }
                    exec = false;
                }
                if (this.browser.opera) {
                    var self = this;
                    window.setTimeout(function() {
                        var liso = self._getDoc().getElementsByTagName('li');
                        for (var i = 0; i < liso.length; i++) {
                            if (liso[i].innerHTML.toLowerCase() == '<br>') {
                                liso[i].parentNode.parentNode.removeChild(liso[i].parentNode);
                            }
                        }
                    },30);
                }
                if (this.browser.ie && exec) {
                    var html = '';
                    if (this._getRange().html) {
                        html = '<li>' + this._getRange().html+ '</li>';
                    } else {
                        var t = this._getRange().text.split('\n');
                        if (t.length > 1) {
                            html = '';
                            for (var ie = 0; ie < t.length; ie++) {
                                html += '<li>' + t[ie] + '</li>';
                            }
                        } else {
                            html = '<li>' + this._getRange().text + '</li>';
                        }
                    }

                    this._getRange().pasteHTML('<' + tag + '>' + html + '</' + tag + '>');
                    exec = false;
                }
            }
            return exec;
        },
        /**
        * @method cmd_insertorderedlist
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertorderedlist ') is used.
        */
        cmd_insertorderedlist: function(value) {
            return [this.cmd_list('ol')];
        },
        /**
        * @method cmd_insertunorderedlist 
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('insertunorderedlist') is used.
        */
        cmd_insertunorderedlist: function(value) {
            return [this.cmd_list('ul')];
        },
        /**
        * @method cmd_fontname
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('fontname') is used.
        */
        cmd_fontname: function(value) {
            var exec = true,
                selEl = this._getSelectedElement();

            this.currentFont = value;
            if (selEl && selEl.tagName && !this._hasSelection()) {
                YAHOO.util.Dom.setStyle(selEl, 'font-family', value);
                exec = false;
            }
            return [exec];
        },
        /**
        * @method cmd_fontsize
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('fontsize') is used.
        */
        cmd_fontsize: function(value) {
            if (this.currentElement && (this.currentElement.length > 0) && (!this._hasSelection())) {
                YAHOO.util.Dom.setStyle(this.currentElement, 'fontSize', value);
            } else if (!this._isElement(this._getSelectedElement(), 'body')) {
                var el = this._getSelectedElement();
                YAHOO.util.Dom.setStyle(el, 'fontSize', value);
                this._selectNode(el);
            } else {
                this._createCurrentElement('span', {'fontSize': value });
                this._selectNode(this.currentElement[0]);
            }
            return [false];
        },
    /* }}} */
        /**
        * @private
        * @method _swapEl
        * @param {HTMLElement} el The element to swap with
        * @param {String} tagName The tagname of the element that you wish to create
        * @param {Function} callback (optional) A function to run on the element after it is created, but before it is replaced. An element reference is passed to this function.
        * @description This function will create a new element in the DOM and populate it with the contents of another element. Then it will assume it's place.
        */
        _swapEl: function(el, tagName, callback) {
            var _el = this._getDoc().createElement(tagName);
            _el.innerHTML = el.innerHTML;
            if (typeof callback == 'function') {
                callback.call(this, _el);
            }
            el.parentNode.replaceChild(_el, el);
            return _el;
        },
        /**
        * @private
        * @method _createCurrentElement
        * @param {String} tagName (optional defaults to a) The tagname of the element that you wish to create
        * @param {Object} tagStyle (optional) Object literal containing styles to apply to the new element.
        * @description This is a work around for the various browser issues with execCommand. This method will run <code>execCommand('fontname', false, 'yui-tmp')</code> on the given selection.
        * It will then search the document for an element with the font-family set to <strong>yui-tmp</strong> and replace that with another span that has other information in it, then assign the new span to the 
        * <code>this.currentElement</code> array, so we now have element references to the elements that were just modified. At this point we can use standard DOM manipulation to change them as we see fit.
        */
        _createCurrentElement: function(tagName, tagStyle) {
            tagName = ((tagName) ? tagName : 'a');
            var tar = null,
                el = [],
                _doc = this._getDoc();
            
            if (this.currentFont) {
                if (!tagStyle) {
                    tagStyle = {};
                }
                tagStyle.fontFamily = this.currentFont;
                this.currentFont = null;
            }
            this.currentElement = [];

            var _elCreate = function() {
                var el = null;
                switch (tagName) {
                    case 'h1':
                    case 'h2':
                    case 'h3':
                    case 'h4':
                    case 'h5':
                    case 'h6':
                        el = _doc.createElement(tagName);
                        break;
                    default:
                        el = _doc.createElement('span');
                        YAHOO.util.Dom.addClass(el, 'yui-tag-' + tagName);
                        YAHOO.util.Dom.addClass(el, 'yui-tag');
                        el.setAttribute('tag', tagName);

                        for (var k in tagStyle) {
                            if (YAHOO.lang.hasOwnProperty(tagStyle, k)) {
                                el.style[k] = tagStyle[k];
                            }
                        }
                        break;
                }
                return el;
            };

            if (!this._hasSelection()) {
                if (this._getDoc().queryCommandEnabled('insertimage')) {
                    this._getDoc().execCommand('insertimage', false, 'yui-tmp-img');
                    var imgs = this._getDoc().getElementsByTagName('img');
                    for (var j = 0; j < imgs.length; j++) {
                        if (imgs[j].getAttribute('src', 2) == 'yui-tmp-img') {
                            el = _elCreate();
                            imgs[j].parentNode.replaceChild(el, imgs[j]);
                            this.currentElement[this.currentElement.length] = el;
                        }
                    }
                } else {
                    if (this.currentEvent) {
                        tar = YAHOO.util.Event.getTarget(this.currentEvent);
                    } else {
                        //For Safari..
                        tar = this._getDoc().body;                        
                    }
                }
                if (tar) {
                    /**
                    * @knownissue
                    * @browser Safari 2.x
                    * @description The issue here is that we have no way of knowing where the cursor position is
                    * inside of the iframe, so we have to place the newly inserted data in the best place that we can.
                    */
                    el = _elCreate();
                    if (this._isElement(tar, 'body') || this._isElement(tar, 'html')) {
                        if (this._isElement(tar, 'html')) {
                            tar = this._getDoc().body;
                        }
                        tar.appendChild(el);
                    } else if (tar.nextSibling) {
                        tar.parentNode.insertBefore(el, tar.nextSibling);
                    } else {
                        tar.parentNode.appendChild(el);
                    }
                    //this.currentElement = el;
                    this.currentElement[this.currentElement.length] = el;
                    this.currentEvent = null;
                    if (this.browser.webkit) {
                        //Force Safari to focus the new element
                        this._getSelection().setBaseAndExtent(el, 0, el, 0);
                        if (this.browser.webkit3) {
                            this._getSelection().collapseToStart();
                        } else {
                            this._getSelection().collapse(true);
                        }
                    }
                }
            } else {
                //Force CSS Styling for this action...
                this._setEditorStyle(true);
                this._getDoc().execCommand('fontname', false, 'yui-tmp');
                var _tmp = [];
                /* TODO: This needs to be cleaned up.. */
                var _tmp1 = this._getDoc().getElementsByTagName('font');
                var _tmp2 = this._getDoc().getElementsByTagName(this._getSelectedElement().tagName);
                var _tmp3 = this._getDoc().getElementsByTagName('span');
                var _tmp4 = this._getDoc().getElementsByTagName('i');
                var _tmp5 = this._getDoc().getElementsByTagName('b');
                var _tmp6 = this._getDoc().getElementsByTagName(this._getSelectedElement().parentNode.tagName);
                for (var e1 = 0; e1 < _tmp1.length; e1++) {
                    _tmp[_tmp.length] = _tmp1[e1];
                }
                for (var e6 = 0; e6 < _tmp6.length; e6++) {
                    _tmp[_tmp.length] = _tmp6[e6];
                }
                for (var e2 = 0; e2 < _tmp2.length; e2++) {
                    _tmp[_tmp.length] = _tmp2[e2];
                }
                for (var e3 = 0; e3 < _tmp3.length; e3++) {
                    _tmp[_tmp.length] = _tmp3[e3];
                }
                for (var e4 = 0; e4 < _tmp4.length; e4++) {
                    _tmp[_tmp.length] = _tmp4[e4];
                }
                for (var e5 = 0; e5 < _tmp5.length; e5++) {
                    _tmp[_tmp.length] = _tmp5[e5];
                }
                for (var i = 0; i < _tmp.length; i++) {
                    if ((YAHOO.util.Dom.getStyle(_tmp[i], 'font-family') == 'yui-tmp') || (_tmp[i].face && (_tmp[i].face == 'yui-tmp'))) {
                        el = _elCreate();
                        el.innerHTML = _tmp[i].innerHTML;
                        if (this._isElement(_tmp[i], 'ol') || (this._isElement(_tmp[i], 'ul'))) {
                            var fc = _tmp[i].getElementsByTagName('li')[0];
                            _tmp[i].style.fontFamily = 'inherit';
                            fc.style.fontFamily = 'inherit';
                            el.innerHTML = fc.innerHTML;
                            fc.innerHTML = '';
                            fc.appendChild(el);
                            this.currentElement[this.currentElement.length] = el;
                        } else if (this._isElement(_tmp[i], 'li')) {
                            _tmp[i].innerHTML = '';
                            _tmp[i].appendChild(el);
                            _tmp[i].style.fontFamily = 'inherit';
                            this.currentElement[this.currentElement.length] = el;
                        } else {
                            if (_tmp[i].parentNode) {
                                _tmp[i].parentNode.replaceChild(el, _tmp[i]);
                                this.currentElement[this.currentElement.length] = el;
                                this.currentEvent = null;
                                if (this.browser.webkit) {
                                    //Force Safari to focus the new element
                                    this._getSelection().setBaseAndExtent(el, 0, el, 0);
                                    if (this.browser.webkit3) {
                                        this._getSelection().collapseToStart();
                                    } else {
                                        this._getSelection().collapse(true);
                                    }
                                }
                                if (this.browser.ie && tagStyle && tagStyle.fontSize) {
                                    this._getSelection().empty();
                                }
                                if (this.browser.gecko) {
                                    this._getSelection().collapseToStart();
                                }
                            }
                        }
                    }
                }
                var len = this.currentElement.length;
                for (var e = 0; e < len; e++) {
                    if ((e + 1) != len) { //Skip the last one in the list
                        if (this.currentElement[e] && this.currentElement[e].nextSibling) {
                            if (this._isElement(this.currentElement[e], 'br')) {
                                this.currentElement[this.currentElement.length] = this.currentElement[e].nextSibling;
                            }
                        }
                    }
                }
            }
        },
        /**
        * @method saveHTML
        * @description Cleans the HTML with the cleanHTML method then places that string back into the textarea.
        * @return String
        */
        saveHTML: function() {
            var html = this.cleanHTML();
            this.get('element').value = html;
            return html;
        },
        /**
        * @method setEditorHTML
        * @param {String} html The html content to load into the editor
        * @description Loads HTML into the editors body
        */
        setEditorHTML: function(html) {
            html = this._cleanIncomingHTML(html);
            this._getDoc().body.innerHTML = html;
            this.nodeChange();
        },
        /**
        * @method getEditorHTML
        * @description Gets the unprocessed/unfiltered HTML from the editor
        */
        getEditorHTML: function() {
            var b = this._getDoc().body;
            if (b === null) {
                return null;
            }
            return this._getDoc().body.innerHTML;
        },
        /**
        * @method show
        * @description This method needs to be called if the Editor was hidden (like in a TabView or Panel). It is used to reset the editor after being in a container that was set to display none.
        */
        show: function() {
            if (this.browser.gecko) {
                this._setDesignMode('on');
                this._focusWindow();
            }
            if (this.browser.webkit) {
                var self = this;
                window.setTimeout(function() {
                    self._setInitialContent.call(self);
                }, 10);
            }
            //Adding this will close all other Editor window's when showing this one.
            if (YAHOO.widget.EditorInfo.window.win && YAHOO.widget.EditorInfo.window.scope) {
                YAHOO.widget.EditorInfo.window.scope.closeWindow.call(YAHOO.widget.EditorInfo.window.scope);
            }
            //Put the iframe back in place
            this.get('iframe').setStyle('position', 'static');
            this.get('iframe').setStyle('left', '');
        },
        /**
        * @method hide
        * @description This method needs to be called if the Editor is to be hidden (like in a TabView or Panel). It should be called to clear timeouts and close open editor windows.
        */
        hide: function() {
            //Adding this will close all other Editor window's.
            if (YAHOO.widget.EditorInfo.window.win && YAHOO.widget.EditorInfo.window.scope) {
                YAHOO.widget.EditorInfo.window.scope.closeWindow.call(YAHOO.widget.EditorInfo.window.scope);
            }
            if (this._fixNodesTimer) {
                clearTimeout(this._fixNodesTimer);
                this._fixNodesTimer = null;
            }
            if (this._nodeChangeTimer) {
                clearTimeout(this._nodeChangeTimer);
                this._nodeChangeTimer = null;
            }
            this._lastNodeChange = 0;
            //Move the iframe off of the screen, so that in containers with visiblity hidden, IE will not cover other elements.
            this.get('iframe').setStyle('position', 'absolute');
            this.get('iframe').setStyle('left', '-9999px');
        },
        /**
        * @method _cleanIncomingHTML
        * @param {String} html The unfiltered HTML
        * @description Process the HTML with a few regexes to clean it up and stabilize the input
        * @return {String} The filtered HTML
        */
        _cleanIncomingHTML: function(html) {
            html = html.replace(/<strong([^>]*)>/gi, '<b$1>');
            html = html.replace(/<\/strong>/gi, '</b>');   

            //replace embed before em check
            html = html.replace(/<embed([^>]*)>/gi, '<YUI_EMBED$1>');
            html = html.replace(/<\/embed>/gi, '</YUI_EMBED>');

            html = html.replace(/<em([^>]*)>/gi, '<i$1>');
            html = html.replace(/<\/em>/gi, '</i>');
            
            //Put embed tags back in..
            html = html.replace(/<YUI_EMBED([^>]*)>/gi, '<embed$1>');
            html = html.replace(/<\/YUI_EMBED>/gi, '</embed>');
            if (this.get('plainText')) {
                html = html.replace(/\n/g, '<br>').replace(/\r/g, '<br>');
                html = html.replace(/  /gi, '&nbsp;&nbsp;'); //Replace all double spaces
                html = html.replace(/\t/gi, '&nbsp;&nbsp;&nbsp;&nbsp;'); //Replace all tabs
            }
            //Removing Script Tags from the Editor
            html = html.replace(/<script([^>]*)>/gi, '<bad>');
            html = html.replace(/<\/script([^>]*)>/gi, '</bad>');
            html = html.replace(/&lt;script([^>]*)&gt;/gi, '<bad>');
            html = html.replace(/&lt;\/script([^>]*)&gt;/gi, '</bad>');
            //Replace the line feeds
            html = html.replace(/\n/g, '<YUI_LF>').replace(/\r/g, '<YUI_LF>');
            //Remove Bad HTML elements (used to be script nodes)
            html = html.replace(new RegExp('<bad([^>]*)>(.*?)<\/bad>', 'gi'), '');
            //Replace the lines feeds
            html = html.replace(/<YUI_LF>/g, '\n');
            return html;
        },
        /**
        * @method cleanHTML
        * @param {String} html The unfiltered HTML
        * @description Process the HTML with a few regexes to clean it up and stabilize the output
        * @return {String} The filtered HTML
        */
        cleanHTML: function(html) {
            //Start Filtering Output
            //Begin RegExs..
            if (!html) { 
                html = this.getEditorHTML();
            }
            var markup = this.get('markup');
            //Make some backups...
            html = this.pre_filter_linebreaks(html, markup);

		    html = html.replace(/<img([^>]*)\/>/gi, '<YUI_IMG$1>');
		    html = html.replace(/<img([^>]*)>/gi, '<YUI_IMG$1>');

		    html = html.replace(/<input([^>]*)\/>/gi, '<YUI_INPUT$1>');
		    html = html.replace(/<input([^>]*)>/gi, '<YUI_INPUT$1>');

		    html = html.replace(/<ul([^>]*)>/gi, '<YUI_UL$1>');
		    html = html.replace(/<\/ul>/gi, '<\/YUI_UL>');
		    html = html.replace(/<blockquote([^>]*)>/gi, '<YUI_BQ$1>');
		    html = html.replace(/<\/blockquote>/gi, '<\/YUI_BQ>');

		    html = html.replace(/<embed([^>]*)>/gi, '<YUI_EMBED$1>');
		    html = html.replace(/<\/embed>/gi, '<\/YUI_EMBED>');

            //Convert b and i tags to strong and em tags
            if ((markup == 'semantic') || (markup == 'xhtml')) {
                html = html.replace(/<i(\s+[^>]*)?>/gi, '<em$1>');
                html = html.replace(/<\/i>/gi, '</em>');
                html = html.replace(/<b([^>]*)>/gi, '<strong$1>');
                html = html.replace(/<\/b>/gi, '</strong>');
            }
            
            //Case Changing
		    html = html.replace(/<font/gi, '<font');
		    html = html.replace(/<\/font>/gi, '</font>');
		    html = html.replace(/<span/gi, '<span');
		    html = html.replace(/<\/span>/gi, '</span>');
            if ((markup == 'semantic') || (markup == 'xhtml') || (markup == 'css')) {
                html = html.replace(new RegExp('<font([^>]*)face="([^>]*)">(.*?)<\/font>', 'gi'), '<span $1 style="font-family: $2;">$3</span>');
                html = html.replace(/<u/gi, '<span style="text-decoration: underline;"');
                if (this.browser.webkit) {
                    html = html.replace(new RegExp('<span class="Apple-style-span" style="font-weight: bold;">([^>]*)<\/span>', 'gi'), '<strong>$1</strong>');
                    html = html.replace(new RegExp('<span class="Apple-style-span" style="font-style: italic;">([^>]*)<\/span>', 'gi'), '<em>$1</em>');
                }
                html = html.replace(/\/u>/gi, '/span>');
                if (markup == 'css') {
                    html = html.replace(/<em([^>]*)>/gi, '<i$1>');
                    html = html.replace(/<\/em>/gi, '</i>');
                    html = html.replace(/<strong([^>]*)>/gi, '<b$1>');
                    html = html.replace(/<\/strong>/gi, '</b>');
                    html = html.replace(/<b/gi, '<span style="font-weight: bold;"');
                    html = html.replace(/\/b>/gi, '/span>');
                    html = html.replace(/<i/gi, '<span style="font-style: italic;"');
                    html = html.replace(/\/i>/gi, '/span>');
                }
                html = html.replace(/  /gi, ' '); //Replace all double spaces and replace with a single
            } else {
		        html = html.replace(/<u/gi, '<u');
		        html = html.replace(/\/u>/gi, '/u>');
            }
		    html = html.replace(/<ol([^>]*)>/gi, '<ol$1>');
		    html = html.replace(/\/ol>/gi, '/ol>');
		    html = html.replace(/<li/gi, '<li');
		    html = html.replace(/\/li>/gi, '/li>');
            html = this.filter_safari(html);

            html = this.filter_internals(html);

            html = this.filter_all_rgb(html);

            //Replace our backups with the real thing
            html = this.post_filter_linebreaks(html, markup);

            if (markup == 'xhtml') {
		        html = html.replace(/<YUI_IMG([^>]*)>/g, '<img $1 />');
		        html = html.replace(/<YUI_INPUT([^>]*)>/g, '<input $1 />');
            } else {
		        html = html.replace(/<YUI_IMG([^>]*)>/g, '<img $1>');
		        html = html.replace(/<YUI_INPUT([^>]*)>/g, '<input $1>');
            }
		    html = html.replace(/<YUI_UL([^>]*)>/g, '<ul$1>');
		    html = html.replace(/<\/YUI_UL>/g, '<\/ul>');

            html = this.filter_invalid_lists(html);

		    html = html.replace(/<YUI_BQ([^>]*)>/g, '<blockquote$1>');
		    html = html.replace(/<\/YUI_BQ>/g, '<\/blockquote>');

		    html = html.replace(/<YUI_EMBED([^>]*)>/g, '<embed$1>');
		    html = html.replace(/<\/YUI_EMBED>/g, '<\/embed>');

            //Trim the output, removing whitespace from the beginning and end
            html = YAHOO.lang.trim(html);

            if (this.get('removeLineBreaks')) {
                html = html.replace(/\n/g, '').replace(/\r/g, '');
                html = html.replace(/  /gi, ' '); //Replace all double spaces and replace with a single
            }
            
            //First empty span
            if (html.substring(0, 6).toLowerCase() == '<span>')  {
                html = html.substring(6);
                //Last empty span
                if (html.substring(html.length - 7, html.length).toLowerCase() == '</span>')  {
                    html = html.substring(0, html.length - 7);
                }
            }

            for (var v in this.invalidHTML) {
                if (YAHOO.lang.hasOwnProperty(this.invalidHTML, v)) {
                    if (Lang.isObject(v) && v.keepContents) {
                        html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '$1');
                    } else {
                        html = html.replace(new RegExp('<' + v + '([^>]*)>(.*?)<\/' + v + '>', 'gi'), '');
                    }
                }
            }

            this.fireEvent('cleanHTML', { type: 'cleanHTML', target: this, html: html });

            return html;
        },
        /**
        * @method filter_invalid_lists
        * @param String html The HTML string to filter
        * @description Filters invalid ol and ul list markup, converts this: <li></li><ol>..</ol> to this: <li></li><li><ol>..</ol></li>
        */
        filter_invalid_lists: function(html) {
            html = html.replace(/<\/li>\n/gi, '</li>');

            html = html.replace(/<\/li><ol>/gi, '</li><li><ol>');
            html = html.replace(/<\/ol>/gi, '</ol></li>');
            html = html.replace(/<\/ol><\/li>\n/gi, "</ol>\n");

            html = html.replace(/<\/li><ul>/gi, '</li><li><ul>');
            html = html.replace(/<\/ul>/gi, '</ul></li>');
            html = html.replace(/<\/ul><\/li>\n/gi, "</ul>\n");

            html = html.replace(/<\/li>/gi, "</li>\n");
            html = html.replace(/<\/ol>/gi, "</ol>\n");
            html = html.replace(/<ol>/gi, "<ol>\n");
            html = html.replace(/<ul>/gi, "<ul>\n");
            return html;
        },
        /**
        * @method filter_safari
        * @param String html The HTML string to filter
        * @description Filters strings specific to Safari
        * @return String
        */
        filter_safari: function(html) {
            if (this.browser.webkit) {
                //<span class="Apple-tab-span" style="white-space:pre">	</span>
                html = html.replace(/<span class="Apple-tab-span" style="white-space:pre">([^>])<\/span>/gi, '&nbsp;&nbsp;&nbsp;&nbsp;');
                html = html.replace(/Apple-style-span/gi, '');
                html = html.replace(/style="line-height: normal;"/gi, '');
                //Remove bogus LI's
                html = html.replace(/<li><\/li>/gi, '');
                html = html.replace(/<li> <\/li>/gi, '');
                html = html.replace(/<li>  <\/li>/gi, '');
                //Remove bogus DIV's
                html = html.replace(/<div><\/div>/gi, '');
                html = html.replace(/<div> <\/div>/gi, '');
            }
            return html;
        },
        /**
        * @method filter_internals
        * @param String html The HTML string to filter
        * @description Filters internal RTE strings and bogus attrs we don't want
        * @return String
        */
        filter_internals: function(html) {
		    html = html.replace(/\r/g, '');
            //Fix stuff we don't want
	        html = html.replace(/<\/?(body|head|html)[^>]*>/gi, '');
            //Fix last BR in LI
		    html = html.replace(/<YUI_BR><\/li>/gi, '</li>');

		    html = html.replace(/yui-tag-span/gi, '');
		    html = html.replace(/yui-tag/gi, '');
		    html = html.replace(/yui-non/gi, '');
		    html = html.replace(/yui-img/gi, '');
		    html = html.replace(/ tag="span"/gi, '');
		    html = html.replace(/ class=""/gi, '');
		    html = html.replace(/ style=""/gi, '');
		    html = html.replace(/ class=" "/gi, '');
		    html = html.replace(/ class="  "/gi, '');
		    html = html.replace(/ target=""/gi, '');
		    html = html.replace(/ title=""/gi, '');

            if (this.browser.ie) {
		        html = html.replace(/ class= /gi, '');
		        html = html.replace(/ class= >/gi, '');
		        html = html.replace(/_height="([^>])"/gi, '');
		        html = html.replace(/_width="([^>])"/gi, '');
            }
            
            return html;
        },
        /**
        * @method filter_all_rgb
        * @param String str The HTML string to filter
        * @description Converts all RGB color strings found in passed string to a hex color, example: style="color: rgb(0, 255, 0)" converts to style="color: #00ff00"
        * @return String
        */
        filter_all_rgb: function(str) {
            var exp = new RegExp("rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)", "gi");
            var arr = str.match(exp);
            if (Lang.isArray(arr)) {
                for (var i = 0; i < arr.length; i++) {
                    var color = this.filter_rgb(arr[i]);
                    str = str.replace(arr[i].toString(), color);
                }
            }
            
            return str;
        },
        /**
        * @method filter_rgb
        * @param String css The CSS string containing rgb(#,#,#);
        * @description Converts an RGB color string to a hex color, example: rgb(0, 255, 0) converts to #00ff00
        * @return String
        */
        filter_rgb: function(css) {
            if (css.toLowerCase().indexOf('rgb') != -1) {
                var exp = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi");
                var rgb = css.replace(exp, "$1,$2,$3,$4,$5").split(',');
            
                if (rgb.length == 5) {
                    var r = parseInt(rgb[1], 10).toString(16);
                    var g = parseInt(rgb[2], 10).toString(16);
                    var b = parseInt(rgb[3], 10).toString(16);

                    r = r.length == 1 ? '0' + r : r;
                    g = g.length == 1 ? '0' + g : g;
                    b = b.length == 1 ? '0' + b : b;

                    css = "#" + r + g + b;
                }
            }
            return css;
        },
        /**
        * @method pre_filter_linebreaks
        * @param String html The HTML to filter
        * @param String markup The markup type to filter to
        * @description HTML Pre Filter
        * @return String
        */
        pre_filter_linebreaks: function(html, markup) {
            if (this.browser.webkit) {
		        html = html.replace(/<br class="khtml-block-placeholder">/gi, '<YUI_BR>');
		        html = html.replace(/<br class="webkit-block-placeholder">/gi, '<YUI_BR>');
            }
		    html = html.replace(/<br>/gi, '<YUI_BR>');
		    html = html.replace(/<br (.*?)>/gi, '<YUI_BR>');
		    html = html.replace(/<br\/>/gi, '<YUI_BR>');
		    html = html.replace(/<br \/>/gi, '<YUI_BR>');
		    html = html.replace(/<div><YUI_BR><\/div>/gi, '<YUI_BR>');
		    html = html.replace(/<p>(&nbsp;|&#160;)<\/p>/g, '<YUI_BR>');            
		    html = html.replace(/<p><br>&nbsp;<\/p>/gi, '<YUI_BR>');
		    html = html.replace(/<p>&nbsp;<\/p>/gi, '<YUI_BR>');
            //Fix last BR
	        html = html.replace(/<YUI_BR>$/, '');
            //Fix last BR in P
	        html = html.replace(/<YUI_BR><\/p>/g, '</p>');
            return html;
        },
        /**
        * @method post_filter_linebreaks
        * @param String html The HTML to filter
        * @param String markup The markup type to filter to
        * @description HTML Pre Filter
        * @return String
        */
        post_filter_linebreaks: function(html, markup) {
            if (markup == 'xhtml') {
		        html = html.replace(/<YUI_BR>/g, '<br />');
            } else {
		        html = html.replace(/<YUI_BR>/g, '<br>');
            }
            return html;
        },
        /**
        * @method clearEditorDoc
        * @description Clear the doc of the Editor
        */
        clearEditorDoc: function() {
            this._getDoc().body.innerHTML = '&nbsp;';
        },
        /**
        * @private
        * @method _renderPanel
        * @description Override Method for Advanced Editor
        */
        _renderPanel: function() {
        },
        /**
        * @method openWindow
        * @description Override Method for Advanced Editor
        */
        openWindow: function(win) {
        },
        /**
        * @method moveWindow
        * @description Override Method for Advanced Editor
        */
        moveWindow: function() {
        },
        /**
        * @private
        * @method _closeWindow
        * @description Override Method for Advanced Editor
        */
        _closeWindow: function() {
        },
        /**
        * @method closeWindow
        * @description Override Method for Advanced Editor
        */
        closeWindow: function() {
            this.unsubscribeAll('afterExecCommand');
            this.toolbar.resetAllButtons();
            this._focusWindow();        
        },
        /**
        * @method destroy
        * @description Destroys the editor, all of it's elements and objects.
        * @return {Boolean}
        */
        destroy: function() {
            this.saveHTML();
            this.toolbar.destroy();
            this.setStyle('visibility', 'hidden');
            this.setStyle('position', 'absolute');
            this.setStyle('top', '-9999px');
            this.setStyle('left', '-9999px');
            var textArea = this.get('element');
            this.get('element_cont').get('parentNode').replaceChild(textArea, this.get('element_cont').get('element'));
            this.get('element_cont').get('element').innerHTML = '';
            this.set('handleSubmit', false); //Remove the submit handler
            //Brutal Object Destroy
            for (var i in this) {
                if (Lang.hasOwnProperty(this, i)) {
                    this[i] = null;
                }
            }
            return true;
        },        
        /**
        * @method toString
        * @description Returns a string representing the editor.
        * @return {String}
        */
        toString: function() {
            var str = 'SimpleEditor';
            if (this.get && this.get('element_cont')) {
                str = 'SimpleEditor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : ''));
            }
            return str;
        }
    });

/**
* @event toolbarLoaded
* @description Event is fired during the render process directly after the Toolbar is loaded. Allowing you to attach events to the toolbar. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event cleanHTML
* @description Event is fired after the cleanHTML method is called.
* @type YAHOO.util.CustomEvent
*/
/**
* @event afterRender
* @description Event is fired after the render process finishes. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event editorContentLoaded
* @description Event is fired after the editor iframe's document fully loads and fires it's onload event. From here you can start injecting your own things into the document. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event editorMouseUp
* @param {Event} ev The DOM Event that occured
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event editorMouseDown
* @param {Event} ev The DOM Event that occured
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event editorDoubleClick
* @param {Event} ev The DOM Event that occured
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event editorKeyUp
* @param {Event} ev The DOM Event that occured
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event editorKeyPress
* @param {Event} ev The DOM Event that occured
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event editorKeyDown
* @param {Event} ev The DOM Event that occured
* @description Passed through HTML Event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event beforeNodeChange
* @description Event fires at the beginning of the nodeChange process. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event afterNodeChange
* @description Event fires at the end of the nodeChange process. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event beforeExecCommand
* @description Event fires at the beginning of the execCommand process. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event afterExecCommand
* @description Event fires at the end of the execCommand process. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/

/**
     * @description Singleton object used to track the open window objects and panels across the various open editors
     * @class EditorInfo
     * @static
    */
    YAHOO.widget.EditorInfo = {
        /**
        * @private
        * @property _instances
        * @description A reference to all editors on the page.
        * @type Object
        */
        _instances: {},
        /**
        * @private
        * @property blankImage
        * @description A reference to the blankImage url
        * @type String 
        */
        blankImage: '',
        /**
        * @private
        * @property window
        * @description A reference to the currently open window object in any editor on the page.
        * @type Object <a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a>
        */
        window: {},
        /**
        * @private
        * @property panel
        * @description A reference to the currently open panel in any editor on the page.
        * @type Object <a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>
        */
        panel: null,
        /**
        * @method getEditorById
        * @description Returns a reference to the Editor object associated with the given textarea
        * @param {String/HTMLElement} id The id or reference of the textarea to return the Editor instance of
        * @return Object <a href="YAHOO.widget.Editor.html">YAHOO.widget.Editor</a>
        */
        getEditorById: function(id) {
            if (!YAHOO.lang.isString(id)) {
                //Not a string, assume a node Reference
                id = id.id;
            }
            if (this._instances[id]) {
                return this._instances[id];
            }
            return false;
        },
        /**
        * @method toString
        * @description Returns a string representing the EditorInfo.
        * @return {String}
        */
        toString: function() {
            var len = 0;
            for (var i in this._instances) {
                len++;
            }
            return 'Editor Info (' + len + ' registered intance' + ((len > 1) ? 's' : '') + ')';
        }
    };



    
})();
/**
 * @module editor
 * @description <p>The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.</p>
 * @namespace YAHOO.widget
 * @requires yahoo, dom, element, event, container_core, simpleeditor
 * @optional dragdrop, animation, menu, button
 * @beta
 */

(function() {
var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event,
    Lang = YAHOO.lang,
    Toolbar = YAHOO.widget.Toolbar;

    /**
     * The Rich Text Editor is a UI control that replaces a standard HTML textarea; it allows for the rich formatting of text content, including common structural treatments like lists, formatting treatments like bold and italic text, and drag-and-drop inclusion and sizing of images. The Rich Text Editor's toolbar is extensible via a plugin architecture so that advanced implementations can achieve a high degree of customization.
     * @constructor
     * @class Editor
     * @extends YAHOO.widget.SimpleEditor
     * @param {String/HTMLElement} el The textarea element to turn into an editor.
     * @param {Object} attrs Object liternal containing configuration parameters.
    */
    
    YAHOO.widget.Editor = function(el, attrs) {
        YAHOO.widget.Editor.superclass.constructor.call(this, el, attrs);
    };

    /**
    * @private
    * @method _cleanClassName
    * @description Makes a useable classname from dynamic data, by dropping it to lowercase and replacing spaces with -'s.
    * @param {String} str The classname to clean up
    * @return {String}
    */
    function _cleanClassName(str) {
        return str.replace(/ /g, '-').toLowerCase();
    }


    YAHOO.extend(YAHOO.widget.Editor, YAHOO.widget.SimpleEditor, {
        /**
        * @property STR_BEFORE_EDITOR
        * @description The accessibility string for the element before the iFrame
        * @type String
        */
        STR_BEFORE_EDITOR: 'This text field can contain stylized text and graphics. To cycle through all formatting options, use the keyboard shortcut Control + Shift + T to place focus on the toolbar and navigate between option heading names. <h4>Common formatting keyboard shortcuts:</h4><ul><li>Control Shift B sets text to bold</li> <li>Control Shift I sets text to italic</li> <li>Control Shift U underlines text</li> <li>Control Shift [ aligns text left</li> <li>Control Shift | centers text</li> <li>Control Shift ] aligns text right</li> <li>Control Shift L adds an HTML link</li> <li>To exit this text editor use the keyboard shortcut Control + Shift + ESC.</li></ul>',    
        /**
        * @property STR_CLOSE_WINDOW
        * @description The Title of the close button in the Editor Window
        * @type String
        */
        STR_CLOSE_WINDOW: 'Close Window',
        /**
        * @property STR_CLOSE_WINDOW_NOTE
        * @description A note appearing in the Editor Window to tell the user that the Escape key will close the window
        * @type String
        */
        STR_CLOSE_WINDOW_NOTE: 'To close this window use the Control + Shift + W key',
        /**
        * @property STR_IMAGE_PROP_TITLE
        * @description The title for the Image Property Editor Window
        * @type String
        */
        STR_IMAGE_PROP_TITLE: 'Image Options',
        /**
        * @property STR_IMAGE_URL
        * @description The label string for Image URL
        * @type String
        */
        STR_IMAGE_URL: 'Image URL',
        /**
        * @property STR_IMAGE_TITLE
        * @description The label string for Image Description
        * @type String
        */
        STR_IMAGE_TITLE: 'Description',
        /**
        * @property STR_IMAGE_SIZE
        * @description The label string for Image Size
        * @type String
        */
        STR_IMAGE_SIZE: 'Size',
        /**
        * @property STR_IMAGE_ORIG_SIZE
        * @description The label string for Original Image Size
        * @type String
        */
        STR_IMAGE_ORIG_SIZE: 'Original Size',
        /**
        * @property STR_IMAGE_COPY
        * @description The label string for the image copy and paste message for Opera and Safari
        * @type String
        */
        STR_IMAGE_COPY: '<span class="tip"><span class="icon icon-info"></span><strong>Note:</strong>To move this image just highlight it, cut, and paste where ever you\'d like.</span>',
        /**
        * @property STR_IMAGE_PADDING
        * @description The label string for the image padding.
        * @type String
        */
        STR_IMAGE_PADDING: 'Padding',
        /**
        * @property STR_IMAGE_BORDER
        * @description The label string for the image border.
        * @type String
        */
        STR_IMAGE_BORDER: 'Border',
        /**
        * @property STR_IMAGE_TEXTFLOW
        * @description The label string for the image text flow.
        * @type String
        */
        STR_IMAGE_TEXTFLOW: 'Text Flow',
        /**
        * @property STR_LOCAL_FILE_WARNING
        * @description The label string for the local file warning.
        * @type String
        */
        STR_LOCAL_FILE_WARNING: '<span class="tip"><span class="icon icon-warn"></span><strong>Note:</strong>This image/link points to a file on your computer and will not be accessible to others on the internet.</span>',
        /**
        * @property STR_LINK_PROP_TITLE
        * @description The label string for the Link Property Editor Window.
        * @type String
        */
        STR_LINK_PROP_TITLE: 'Link Options',
        /**
        * @property STR_LINK_PROP_REMOVE
        * @description The label string for the Remove link from text link inside the property editor.
        * @type String
        */
        STR_LINK_PROP_REMOVE: 'Remove link from text',
        /**
        * @property STR_LINK_NEW_WINDOW
        * @description The string for the open in a new window label.
        * @type String
        */
        STR_LINK_NEW_WINDOW: 'Open in a new window.',
        /**
        * @property STR_LINK_TITLE
        * @description The string for the link description.
        * @type String
        */
        STR_LINK_TITLE: 'Description',
        /**
        * @protected
        * @property CLASS_LOCAL_FILE
        * @description CSS class applied to an element when it's found to have a local url.
        * @type String
        */
        CLASS_LOCAL_FILE: 'warning-localfile',
        /**
        * @protected
        * @property CLASS_HIDDEN
        * @description CSS class applied to the body when the hiddenelements button is pressed.
        * @type String
        */
        CLASS_HIDDEN: 'yui-hidden',
        /** 
        * @method init
        * @description The Editor class' initialization method
        */
        init: function(p_oElement, p_oAttributes) {

            this._defaultToolbar = {
                collapse: true,
                titlebar: 'Text Editing Tools',
                draggable: false,
                buttonType: 'advanced',
                buttons: [
                    { group: 'fontstyle', label: 'Font Name and Size',
                        buttons: [
                            { type: 'select', label: 'Arial', value: 'fontname', disabled: true,
                                menu: [
                                    { text: 'Arial', checked: true },
                                    { text: 'Arial Black' },
                                    { text: 'Comic Sans MS' },
                                    { text: 'Courier New' },
                                    { text: 'Lucida Console' },
                                    { text: 'Tahoma' },
                                    { text: 'Times New Roman' },
                                    { text: 'Trebuchet MS' },
                                    { text: 'Verdana' }
                                ]
                            },
                            { type: 'spin', label: '13', value: 'fontsize', range: [ 9, 75 ], disabled: true }
                        ]
                    },
                    { type: 'separator' },
                    { group: 'textstyle', label: 'Font Style',
                        buttons: [
                            { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' },
                            { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' },
                            { type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' },
                            { type: 'separator' },
                            { type: 'push', label: 'Subscript', value: 'subscript', disabled: true },
                            { type: 'push', label: 'Superscript', value: 'superscript', disabled: true },
                            { type: 'separator' },
                            { type: 'color', label: 'Font Color', value: 'forecolor', disabled: true },
                            { type: 'color', label: 'Background Color', value: 'backcolor', disabled: true },
                            { type: 'separator' },
                            { type: 'push', label: 'Remove Formatting', value: 'removeformat', disabled: true },
                            { type: 'push', label: 'Show/Hide Hidden Elements', value: 'hiddenelements' }
                        ]
                    },
                    { type: 'separator' },
                    { group: 'alignment', label: 'Alignment',
                        buttons: [
                            { type: 'push', label: 'Align Left CTRL + SHIFT + [', value: 'justifyleft' },
                            { type: 'push', label: 'Align Center CTRL + SHIFT + |', value: 'justifycenter' },
                            { type: 'push', label: 'Align Right CTRL + SHIFT + ]', value: 'justifyright' },
                            { type: 'push', label: 'Justify', value: 'justifyfull' }
                        ]
                    },
                    { type: 'separator' },
                    { group: 'parastyle', label: 'Paragraph Style',
                        buttons: [
                        { type: 'select', label: 'Normal', value: 'heading', disabled: true,
                            menu: [
                                { text: 'Normal', value: 'none', checked: true },
                                { text: 'Header 1', value: 'h1' },
                                { text: 'Header 2', value: 'h2' },
                                { text: 'Header 3', value: 'h3' },
                                { text: 'Header 4', value: 'h4' },
                                { text: 'Header 5', value: 'h5' },
                                { text: 'Header 6', value: 'h6' }
                            ]
                        }
                        ]
                    },
                    { type: 'separator' },
                    { group: 'indentlist', label: 'Indenting and Lists',
                        buttons: [
                            { type: 'push', label: 'Indent', value: 'indent', disabled: true },
                            { type: 'push', label: 'Outdent', value: 'outdent', disabled: true },
                            { type: 'push', label: 'Create an Unordered List', value: 'insertunorderedlist' },
                            { type: 'push', label: 'Create an Ordered List', value: 'insertorderedlist' }
                        ]
                    },
                    { type: 'separator' },
                    { group: 'insertitem', label: 'Insert Item',
                        buttons: [
                            { type: 'push', label: 'HTML Link CTRL + SHIFT + L', value: 'createlink', disabled: true },
                            { type: 'push', label: 'Insert Image', value: 'insertimage' }
                        ]
                    }
                ]
            };

            YAHOO.widget.Editor.superclass.init.call(this, p_oElement, p_oAttributes);

        },
        /**
        * @method initAttributes
        * @description Initializes all of the configuration attributes used to create 
        * the editor.
        * @param {Object} attr Object literal specifying a set of 
        * configuration attributes used to create the editor.
        */
        initAttributes: function(attr) {
            YAHOO.widget.Editor.superclass.initAttributes.call(this, attr);

            /**
            * @attribute localFileWarning
            * @description Should we throw the warning if we detect a file that is local to their machine?
            * @default true
            * @type Boolean
            */            
            this.setAttributeConfig('localFileWarning', {
                value: attr.locaFileWarning || true
            });

            /**
            * @attribute hiddencss
            * @description The CSS used to show/hide hidden elements on the page, these rules must be prefixed with the class provided in <code>this.CLASS_HIDDEN</code>
            * @default <code><pre>
            .yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u, .yui-hidden div, .yui-hidden p, .yui-hidden span, .yui-hidden img, .yui-hidden ul, .yui-hidden ol, .yui-hidden li, .yui-hidden table {
                border: 1px dotted #ccc;
            }
            .yui-hidden .yui-non {
                border: none;
            }
            .yui-hidden img {
                padding: 2px;
            }</pre></code>
            * @type String
            */            
            this.setAttributeConfig('hiddencss', {
                value: attr.hiddencss || '.yui-hidden font, .yui-hidden strong, .yui-hidden b, .yui-hidden em, .yui-hidden i, .yui-hidden u, .yui-hidden div,.yui-hidden p,.yui-hidden span,.yui-hidden img, .yui-hidden ul, .yui-hidden ol, .yui-hidden li, .yui-hidden table { border: 1px dotted #ccc; } .yui-hidden .yui-non { border: none; } .yui-hidden img { padding: 2px; }',
                writeOnce: true
            });
           
        },
        /**
        * @private
        * @method _fixNodes
        * @description Fix href and imgs as well as remove invalid HTML.
        */
        _fixNodes: function() {
            YAHOO.widget.Editor.superclass._fixNodes.call(this);
            var url = '';

            var imgs = this._getDoc().getElementsByTagName('img');
            for (var im = 0; im < imgs.length; im++) {
                if (imgs[im].getAttribute('href', 2)) {
                    url = imgs[im].getAttribute('src', 2);
                    if (this._isLocalFile(url)) {
                        Dom.addClass(imgs[im], this.CLASS_LOCAL_FILE);
                    } else {
                        Dom.removeClass(imgs[im], this.CLASS_LOCAL_FILE);
                    }
                }
            }
            var fakeAs = this._getDoc().body.getElementsByTagName('a');
            for (var a = 0; a < fakeAs.length; a++) {
                if (fakeAs[a].getAttribute('href', 2)) {
                    url = fakeAs[a].getAttribute('href', 2);
                    if (this._isLocalFile(url)) {
                        Dom.addClass(fakeAs[a], this.CLASS_LOCAL_FILE);
                    } else {
                        Dom.removeClass(fakeAs[a], this.CLASS_LOCAL_FILE);
                    }
                }
            }
        },
        /**
        * @private
        * @property _disabled
        * @description The Toolbar items that should be disabled if there is no selection present in the editor.
        * @type Array
        */
        _disabled: [ 'createlink', 'forecolor', 'backcolor', 'fontname', 'fontsize', 'superscript', 'subscript', 'removeformat', 'heading', 'indent' ],
        /**
        * @private
        * @property _alwaysDisabled
        * @description The Toolbar items that should ALWAYS be disabled event if there is a selection present in the editor.
        * @type Object
        */
        _alwaysDisabled: { 'outdent': true },
        /**
        * @private
        * @property _alwaysEnabled
        * @description The Toolbar items that should ALWAYS be enabled event if there isn't a selection present in the editor.
        * @type Object
        */
        _alwaysEnabled: { hiddenelements: true },
        /**
        * @private
        * @method _handleKeyDown
        * @param {Event} ev The event we are working on.
        * @description Override method that handles some new keydown events inside the iFrame document.
        */
        _handleKeyDown: function(ev) {
            YAHOO.widget.Editor.superclass._handleKeyDown.call(this, ev);
            var doExec = false,
                action = null,
                exec = false;

            if (ev.shiftKey && ev.ctrlKey) {
                doExec = true;
            }
            switch (ev.keyCode) {
                case 219: //Left
                    action = 'justifyleft';
                    break;
                case 220: //Center
                    action = 'justifycenter';
                    break;
                case 221: //Right
                    action = 'justifyright';
                    break;
            }
            if (doExec && action) {
                this.execCommand(action, null);
                Event.stopEvent(ev);
                this.nodeChange();
            }
        },        
        _handleCreateLinkClick: function() {
            var el = this._getSelectedElement();
            if (this._isElement(el, 'img')) {
                this.STOP_EXEC_COMMAND = true;
                this.currentElement[0] = el;
                this.toolbar.fireEvent('insertimageClick', { type: 'insertimageClick', target: this.toolbar });
                this.fireEvent('afterExecCommand', { type: 'afterExecCommand', target: this });
                return false;
            }
            if (this.get('limitCommands')) {
                if (!this.toolbar.getButtonByValue('createlink')) {
                    return false;
                }
            }
            
            this.on('afterExecCommand', function() {

                var win = new YAHOO.widget.EditorWindow('createlink', {
                    width: '350px'
                });
                
                var el = this.currentElement[0],
                    url = '',
                    title = '',
                    target = '',
                    localFile = false;
                if (el) {
                    if (el.getAttribute('href', 2) !== null) {
                        url = el.getAttribute('href', 2);
                        if (this._isLocalFile(url)) {
                            //Local File throw Warning
                            win.setFooter(this.STR_LOCAL_FILE_WARNING);
                            localFile = true;
                        } else {
                            win.setFooter(' ');
                        }
                    }
                    if (el.getAttribute('title') !== null) {
                        title = el.getAttribute('title');
                    }
                    if (el.getAttribute('target') !== null) {
                        target = el.getAttribute('target');
                    }
                }
                var str = '<label for="createlink_url"><strong>' + this.STR_LINK_URL + ':</strong> <input type="text" name="createlink_url" class="createlink_url" id="createlink_url" value="' + url + '"' + ((localFile) ? ' class="warning"' : '') + '></label>';
                str += '<label for="createlink_target"><strong>&nbsp;</strong><input type="checkbox" name="createlink_target" id="createlink_target" class="createlink_target" value="_blank"' + ((target) ? ' checked' : '') + '> ' + this.STR_LINK_NEW_WINDOW + '</label>';
                str += '<label for="createlink_title"><strong>' + this.STR_LINK_TITLE + ':</strong> <input type="text" name="createlink_title" class="createlink_title" id="createlink_title" value="' + title + '"></label>';
                
                var body = document.createElement('div');
                body.innerHTML = str;

                var unlinkCont = document.createElement('div');
                unlinkCont.className = 'removeLink';
                var unlink = document.createElement('a');
                unlink.href = '#';
                unlink.innerHTML = this.STR_LINK_PROP_REMOVE;
                unlink.title = this.STR_LINK_PROP_REMOVE;
                Event.on(unlink, 'click', function(ev) {
                    Event.stopEvent(ev);
                    this.execCommand('unlink');
                    this.closeWindow();
                }, this, true);
                unlinkCont.appendChild(unlink);
                body.appendChild(unlinkCont);

                win.setHeader(this.STR_LINK_PROP_TITLE);
                win.setBody(body);

                Event.onAvailable('createlink_url', function() {
                    window.setTimeout(function() {
                        try {
                            YAHOO.util.Dom.get('createlink_url').focus();
                        } catch (e) {}
                    }, 50);
                    Event.on('createlink_url', 'blur', function() {
                        var url = Dom.get('createlink_url');
                        if (this._isLocalFile(url.value)) {
                            //Local File throw Warning
                            Dom.addClass(url, 'warning');
                            this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
                        } else {
                            Dom.removeClass(url, 'warning');
                            this.get('panel').setFooter(' ');
                        }
                    }, this, true);
                }, this, true);

                this.openWindow(win);
            });
        },
        /**
        * @private
        * @method _handleCreateLinkWindowClose
        * @description Handles the closing of the Link Properties Window.
        */
        _handleCreateLinkWindowClose: function() {
            var url = Dom.get('createlink_url'),
                target = Dom.get('createlink_target'),
                title = Dom.get('createlink_title'),
                el = this.currentElement[0],
                a = el;
            if (url && url.value) {
                var urlValue = url.value;
                if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
                    if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
                        //Found an @ sign, prefix with mailto:
                        urlValue = 'mailto:' + urlValue;
                    } else {
                        /* :// not found adding */
                        if (urlValue.substring(0, 1) != '#') {
                            urlValue = 'http:/'+'/' + urlValue;
                        }
                        
                    }
                }
                el.setAttribute('href', urlValue);
                if (target.checked) {
                    el.setAttribute('target', target.value);
                } else {
                    el.setAttribute('target', '');
                }
                el.setAttribute('title', ((title.value) ? title.value : ''));

            } else {
                var _span = this._getDoc().createElement('span');
                _span.innerHTML = el.innerHTML;
                Dom.addClass(_span, 'yui-non');
                el.parentNode.replaceChild(_span, el);
            }
            this.nodeChange();
            this.currentElement = [];
        },
        /**
        * @private
        * @method _handleInsertImageClick
        * @description Opens the Image Properties Window when the insert Image button is clicked or an Image is Double Clicked.
        */
        _handleInsertImageClick: function() {
            if (this.get('limitCommands')) {
                if (!this.toolbar.getButtonByValue('insertimage')) {
                    return false;
                }
            }
            this._setBusy();
            this.on('afterExecCommand', function() {
                var el = this.currentElement[0],
                    body = null,
                    link = '',
                    target = '',
                    title = '',
                    src = '',
                    align = '',
                    height = 75,
                    width = 75,
                    padding = 0,
                    oheight = 0,
                    owidth = 0,
                    blankimage = false,
                    win = new YAHOO.widget.EditorWindow('insertimage', {
                        width: '415px'
                    });

                if (!el) {
                    el = this._getSelectedElement();
                }
                if (el) {
                    if (el.getAttribute('src')) {
                        src = el.getAttribute('src', 2);
                        if (src.indexOf(this.get('blankimage')) != -1) {
                            src = this.STR_IMAGE_HERE;
                            blankimage = true;
                        }
                    }
                    if (el.getAttribute('alt', 2)) {
                        title = el.getAttribute('alt', 2);
                    }
                    if (el.getAttribute('title', 2)) {
                        title = el.getAttribute('title', 2);
                    }

                    if (el.parentNode && this._isElement(el.parentNode, 'a')) {
                        link = el.parentNode.getAttribute('href', 2);
                        if (el.parentNode.getAttribute('target') !== null) {
                            target = el.parentNode.getAttribute('target');
                        }
                    }
                    height = parseInt(el.height, 10);
                    width = parseInt(el.width, 10);
                    if (el.style.height) {
                        height = parseInt(el.style.height, 10);
                    }
                    if (el.style.width) {
                        width = parseInt(el.style.width, 10);
                    }
                    if (el.style.margin) {
                        padding = parseInt(el.style.margin, 10);
                    }
                    if (!el._height) {
                        el._height = height;
                    }
                    if (!el._width) {
                        el._width = width;
                    }
                    oheight = el._height;
                    owidth = el._width;
                }
                var str = '<label for="insertimage_url"><strong>' + this.STR_IMAGE_URL + ':</strong> <input type="text" id="insertimage_url" class="insertimage_url" value="' + src + '" size="40"></label>';
                body = document.createElement('div');
                body.innerHTML = str;

                var tbarCont = document.createElement('div');
                tbarCont.id = 'img_toolbar';
                body.appendChild(tbarCont);

                var str2 = '<label for="insertimage_title"><strong>' + this.STR_IMAGE_TITLE + ':</strong> <input type="text" id="insertimage_title" class="insertimage_title" value="' + title + '" size="40"></label>';
                str2 += '<label for="insertimage_link"><strong>' + this.STR_LINK_URL + ':</strong> <input type="text" name="insertimage_link" id="insertimage_link" class="insertimage_link" value="' + link + '"></label>';
                str2 += '<label for="insertimage_target"><strong>&nbsp;</strong><input type="checkbox" name="insertimage_target_" id="insertimage_target" class="insertimage_target" value="_blank"' + ((target) ? ' checked' : '') + '> ' + this.STR_LINK_NEW_WINDOW + '</label>';
                var div = document.createElement('div');
                div.innerHTML = str2;
                body.appendChild(div);
                win.cache = body;

                var tbar = new YAHOO.widget.Toolbar(tbarCont, {
                    /* {{{ */ 
                    buttonType: this._defaultToolbar.buttonType,
                    buttons: [
                        { group: 'textflow', label: this.STR_IMAGE_TEXTFLOW + ':',
                            buttons: [
                                { type: 'push', label: 'Left', value: 'left' },
                                { type: 'push', label: 'Inline', value: 'inline' },
                                { type: 'push', label: 'Block', value: 'block' },
                                { type: 'push', label: 'Right', value: 'right' }
                            ]
                        },
                        { type: 'separator' },
                        { group: 'padding', label: this.STR_IMAGE_PADDING + ':',
                            buttons: [
                                { type: 'spin', label: ''+padding, value: 'padding', range: [0, 50] }
                            ]
                        },
                        { type: 'separator' },
                        { group: 'border', label: this.STR_IMAGE_BORDER + ':',
                            buttons: [
                                { type: 'select', label: 'Border Size', value: 'bordersize',
                                    menu: [
                                        { text: 'none', value: '0', checked: true },
                                        { text: '1px', value: '1' },
                                        { text: '2px', value: '2' },
                                        { text: '3px', value: '3' },
                                        { text: '4px', value: '4' },
                                        { text: '5px', value: '5' }
                                    ]
                                },
                                { type: 'select', label: 'Border Type', value: 'bordertype', disabled: true,
                                    menu: [
                                        { text: 'Solid', value: 'solid', checked: true },
                                        { text: 'Dashed', value: 'dashed' },
                                        { text: 'Dotted', value: 'dotted' }
                                    ]
                                },
                                { type: 'color', label: 'Border Color', value: 'bordercolor', disabled: true }
                            ]
                        }
                    ]
                    /* }}} */
                });
                
                var bsize = '0';
                var btype = 'solid';
                if (el.style.borderLeftWidth) {
                    bsize = parseInt(el.style.borderLeftWidth, 10);
                }
                if (el.style.borderLeftStyle) {
                    btype = el.style.borderLeftStyle;
                }
                var bs_button = tbar.getButtonByValue('bordersize');
                var bSizeStr = ((parseInt(bsize, 10) > 0) ? '' : 'none');
                bs_button.set('label', '<span class="yui-toolbar-bordersize-' + bsize + '">'+bSizeStr+'</span>');
                this._updateMenuChecked('bordersize', bsize, tbar);

                var bt_button = tbar.getButtonByValue('bordertype');
                bt_button.set('label', '<span class="yui-toolbar-bordertype-' + btype + '"></span>');
                this._updateMenuChecked('bordertype', btype, tbar);
                if (parseInt(bsize, 10) > 0) {
                    tbar.enableButton(bt_button);
                    tbar.enableButton(bs_button);
                }

                var cont = tbar.get('cont');
                var hw = document.createElement('div');
                hw.className = 'yui-toolbar-group yui-toolbar-group-height-width height-width';
                hw.innerHTML = '<h3>' + this.STR_IMAGE_SIZE + ':</h3>';
                var orgSize = '';
                if ((height != oheight) || (width != owidth)) {
                    orgSize = '<span class="info">' + this.STR_IMAGE_ORIG_SIZE + '<br>'+ owidth +' x ' + oheight + '</span>';
                }
                hw.innerHTML += '<span tabIndex="-1"><input type="text" size="3" value="'+width+'" id="insertimage_width"> x <input type="text" size="3" value="'+height+'" id="insertimage_height"></span>' + orgSize;
                cont.insertBefore(hw, cont.firstChild);

                Event.onAvailable('insertimage_width', function() {
                    Event.on('insertimage_width', 'blur', function() {
                        var value = parseInt(Dom.get('insertimage_width').value, 10);
                        if (value > 5) {
                            el.style.width = value + 'px';
                            //Removed moveWindow call so the window doesn't jump
                            //this.moveWindow();
                        }
                    }, this, true);
                }, this, true);
                Event.onAvailable('insertimage_height', function() {
                    Event.on('insertimage_height', 'blur', function() {
                        var value = parseInt(Dom.get('insertimage_height').value, 10);
                        if (value > 5) {
                            el.style.height = value + 'px';
                            //Removed moveWindow call so the window doesn't jump
                            //this.moveWindow();
                        }
                    }, this, true);
                }, this, true);

                if ((el.align == 'right') || (el.align == 'left')) {
                    tbar.selectButton(el.align);
                } else if (el.style.display == 'block') {
                    tbar.selectButton('block');
                } else {
                    tbar.selectButton('inline');
                }
                if (parseInt(el.style.marginLeft, 10) > 0) {
                     tbar.getButtonByValue('padding').set('label', ''+parseInt(el.style.marginLeft, 10));
                }
                if (el.style.borderSize) {
                    tbar.selectButton('bordersize');
                    tbar.selectButton(parseInt(el.style.borderSize, 10));
                }

                tbar.on('colorPickerClicked', function(o) {
                    var size = '1', type = 'solid', color = 'black';

                    if (el.style.borderLeftWidth) {
                        size = parseInt(el.style.borderLeftWidth, 10);
                    }
                    if (el.style.borderLeftStyle) {
                        type = el.style.borderLeftStyle;
                    }
                    if (el.style.borderLeftColor) {
                        color = el.style.borderLeftColor;
                    }
                    var borderString = size + 'px ' + type + ' #' + o.color;
                    el.style.border = borderString;
                }, this.toolbar, true);

                tbar.on('buttonClick', function(o) {
                    var value = o.button.value,
                        borderString = '';
                    if (o.button.menucmd) {
                        value = o.button.menucmd;
                    }
                    var size = '1', type = 'solid', color = 'black';

                    /* All border calcs are done on the left border
                        since our default interface only supports
                        one border size/type and color */
                    if (el.style.borderLeftWidth) {
                        size = parseInt(el.style.borderLeftWidth, 10);
                    }
                    if (el.style.borderLeftStyle) {
                        type = el.style.borderLeftStyle;
                    }
                    if (el.style.borderLeftColor) {
                        color = el.style.borderLeftColor;
                    }
                    switch(value) {
                        case 'bordersize':
                            if (this.browser.webkit && this._lastImage) {
                                Dom.removeClass(this._lastImage, 'selected');
                                this._lastImage = null;
                            }

                            borderString = parseInt(o.button.value, 10) + 'px ' + type + ' ' + color;
                            el.style.border = borderString;
                            if (parseInt(o.button.value, 10) > 0) {
                                tbar.enableButton('bordertype');
                                tbar.enableButton('bordercolor');
                            } else {
                                tbar.disableButton('bordertype');
                                tbar.disableButton('bordercolor');
                            }
                            break;
                        case 'bordertype':
                            if (this.browser.webkit && this._lastImage) {
                                Dom.removeClass(this._lastImage, 'selected');
                                this._lastImage = null;
                            }
                            borderString = size + 'px ' + o.button.value + ' ' + color;
                            el.style.border = borderString;
                            break;
                        case 'right':
                        case 'left':
                            tbar.deselectAllButtons();
                            el.style.display = '';
                            el.align = o.button.value;
                            break;
                        case 'inline':
                            tbar.deselectAllButtons();
                            el.style.display = '';
                            el.align = '';
                            break;
                        case 'block':
                            tbar.deselectAllButtons();
                            el.style.display = 'block';
                            el.align = 'center';
                            break;
                        case 'padding':
                            var _button = tbar.getButtonById(o.button.id);
                            el.style.margin = _button.get('label') + 'px';
                            break;
                    }
                    tbar.selectButton(o.button.value);
                    this.moveWindow();
                }, this, true);

                win.setHeader(this.STR_IMAGE_PROP_TITLE);
                win.setBody(body);
                //Adobe AIR Code
                if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {                
                    win.setFooter(this.STR_IMAGE_COPY);
                }
                this.openWindow(win);

                //Set event after openWindow..
                Event.onAvailable('insertimage_url', function() {

                    this.toolbar.selectButton('insertimage');

                    window.setTimeout(function() {
                        YAHOO.util.Dom.get('insertimage_url').focus();
                        if (blankimage) {
                            YAHOO.util.Dom.get('insertimage_url').select();
                        }
                    }, 50);
                    
                    if (this.get('localFileWarning')) {
                        Event.on('insertimage_link', 'blur', function() {
                            var url = Dom.get('insertimage_link');
                            if (this._isLocalFile(url.value)) {
                                //Local File throw Warning
                                Dom.addClass(url, 'warning');
                                this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
                            } else {
                                Dom.removeClass(url, 'warning');
                                this.get('panel').setFooter(' ');
                                //Adobe AIR Code
                                if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {                
                                    this.get('panel').setFooter(this.STR_IMAGE_COPY);
                                }
                            }
                        }, this, true);

                        Event.on('insertimage_url', 'blur', function() {
                            var url = Dom.get('insertimage_url');
                            if (url.value && el) {
                                if (url.value == el.getAttribute('src', 2)) {
                                    return false;
                                }
                            }
                            if (this._isLocalFile(url.value)) {
                                //Local File throw Warning
                                Dom.addClass(url, 'warning');
                                this.get('panel').setFooter(this.STR_LOCAL_FILE_WARNING);
                            } else if (this.currentElement[0]) {
                                Dom.removeClass(url, 'warning');
                                this.get('panel').setFooter(' ');
                                //Adobe AIR Code
                                if ((this.browser.webkit && !this.browser.webkit3 || this.browser.air) || this.browser.opera) {                
                                    this.get('panel').setFooter(this.STR_IMAGE_COPY);
                                }
                                
                                if (url && url.value && (url.value != this.STR_IMAGE_HERE)) {
                                    this.currentElement[0].setAttribute('src', url.value);
                                    var self = this,
                                        img = new Image();

                                    img.onerror = function() {
                                        url.value = self.STR_IMAGE_HERE;
                                        img.setAttribute('src', self.get('blankimage'));
                                        self.currentElement[0].setAttribute('src', self.get('blankimage'));
                                        YAHOO.util.Dom.get('insertimage_height').value = img.height;
                                        YAHOO.util.Dom.get('insertimage_width').value = img.width;
                                    };
                                    window.setTimeout(function() {
                                        YAHOO.util.Dom.get('insertimage_height').value = img.height;
                                        YAHOO.util.Dom.get('insertimage_width').value = img.width;
                                        if (self.currentElement && self.currentElement[0]) {
                                            if (!self.currentElement[0]._height) {
                                                self.currentElement[0]._height = img.height;
                                            }
                                            if (!self.currentElement[0]._width) {
                                                self.currentElement[0]._width = img.width;
                                            }
                                        }
                                        //Removed moveWindow call so the window doesn't jump
                                        //self.moveWindow();
                                    }, 800); //Bumped the timeout up to account for larger images..

                                    if (url.value != this.STR_IMAGE_HERE) {
                                        img.src = url.value;
                                    }
                                }
                            }
                        }, this, true);
                    }
                }, this, true);
            });
        },
        /**
        * @private
        * @method _handleInsertImageWindowClose
        * @description Handles the closing of the Image Properties Window.
        */
        _handleInsertImageWindowClose: function() {
            var url = Dom.get('insertimage_url');
            var title = Dom.get('insertimage_title');
            var link = Dom.get('insertimage_link');
            var target = Dom.get('insertimage_target');
            var el = this.currentElement[0];
            if (url && url.value && (url.value != this.STR_IMAGE_HERE)) {
                el.setAttribute('src', url.value);
                el.setAttribute('title', title.value);
                el.setAttribute('alt', title.value);
                var par = el.parentNode;
                if (link.value) {
                    var urlValue = link.value;
                    if ((urlValue.indexOf(':/'+'/') == -1) && (urlValue.substring(0,1) != '/') && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
                        if ((urlValue.indexOf('@') != -1) && (urlValue.substring(0, 6).toLowerCase() != 'mailto')) {
                            //Found an @ sign, prefix with mailto:
                            urlValue = 'mailto:' + urlValue;
                        } else {
                            /* :// not found adding */
                            urlValue = 'http:/'+'/' + urlValue;
                        }
                    }
                    if (par && this._isElement(par, 'a')) {
                        par.setAttribute('href', urlValue);
                        if (target.checked) {
                            par.setAttribute('target', target.value);
                        } else {
                            par.setAttribute('target', '');
                        }
                    } else {
                        var _a = this._getDoc().createElement('a');
                        _a.setAttribute('href', urlValue);
                        if (target.checked) {
                            _a.setAttribute('target', target.value);
                        } else {
                            _a.setAttribute('target', '');
                        }
                        el.parentNode.replaceChild(_a, el);
                        _a.appendChild(el);
                    }
                } else {
                    if (par && this._isElement(par, 'a')) {
                        par.parentNode.replaceChild(el, par);
                    }
                }
            } else {
                //No url/src given, remove the node from the document
                el.parentNode.removeChild(el);
            }
            this.currentElement = [];
            this.nodeChange();
        },
        /**
        * @private
        * @method _renderPanel
        * @description Renders the panel used for Editor Windows to the document so we can start using it..
        * @return {<a href="YAHOO.widget.Overlay.html">YAHOO.widget.Overlay</a>}
        */
        _renderPanel: function() {
            var panel = null;
            if (!YAHOO.widget.EditorInfo.panel) {
                panel = new YAHOO.widget.Overlay(this.EDITOR_PANEL_ID, {
                    width: '300px',
                    iframe: true,
                    visible: false,
                    underlay: 'none',
                    draggable: false,
                    close: false
                });
                YAHOO.widget.EditorInfo.panel = panel;
            } else {
                panel = YAHOO.widget.EditorInfo.panel;
            }
            this.set('panel', panel);

            this.get('panel').setBody('---');
            this.get('panel').setHeader(' ');
            this.get('panel').setFooter(' ');
            if (this.DOMReady) {
                this.get('panel').render(document.body);
                Dom.addClass(this.get('panel').element, 'yui-editor-panel');
            } else {
                Event.onDOMReady(function() {
                    this.get('panel').render(document.body);
                    Dom.addClass(this.get('panel').element, 'yui-editor-panel');
                }, this, true);
            }
            this.get('panel').showEvent.subscribe(function() {
                YAHOO.util.Dom.setStyle(this.element, 'display', 'block');
            });
            return this.get('panel');
        },
        /**
        * @method openWindow
        * @param {<a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a>} win A <a href="YAHOO.widget.EditorWindow.html">YAHOO.widget.EditorWindow</a> instance
        * @description Opens a new "window/panel"
        */
        openWindow: function(win) {
            this.toolbar.set('disabled', true); //Disable the toolbar when an editor window is open..
            Event.on(document, 'keypress', this._closeWindow, this, true);
            if (YAHOO.widget.EditorInfo.window.win && YAHOO.widget.EditorInfo.window.scope) {
                YAHOO.widget.EditorInfo.window.scope.closeWindow.call(YAHOO.widget.EditorInfo.window.scope);
            }
            YAHOO.widget.EditorInfo.window.win = win;
            YAHOO.widget.EditorInfo.window.scope = this;

            var self = this,
                xy = Dom.getXY(this.currentElement[0]),
                elXY = Dom.getXY(this.get('iframe').get('element')),
                panel = this.get('panel'),
                newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)],
                wWidth = (parseInt(win.attrs.width, 10) / 2),
                align = 'center',
                body = null;

            this.fireEvent('beforeOpenWindow', { type: 'beforeOpenWindow', win: win, panel: panel });

            body = document.createElement('div');
            body.className = this.CLASS_PREFIX + '-body-cont';
            for (var b in this.browser) {
                if (this.browser[b]) {
                    Dom.addClass(body, b);
                    break;
                }
            }
            Dom.addClass(body, ((YAHOO.widget.Button && (this._defaultToolbar.buttonType == 'advanced')) ? 'good-button' : 'no-button'));

            var _note = document.createElement('h3');
            _note.className = 'yui-editor-skipheader';
            _note.innerHTML = this.STR_CLOSE_WINDOW_NOTE;
            body.appendChild(_note);
            form = document.createElement('form');
            form.setAttribute('method', 'GET');
            var windowName = win.name;
            Event.on(form, 'submit', function(ev) {
                var evName = 'window' + windowName + 'Submit';
                self.fireEvent(evName, { type: evName, target: this });
                Event.stopEvent(ev);
            }, this, true);
            body.appendChild(form);

            if (Lang.isObject(win.body)) { //Assume it's a reference
                form.appendChild(win.body);
            } else { //Assume it's a string
                var _tmp = document.createElement('div');
                _tmp.innerHTML = win.body;
                form.appendChild(_tmp);
            }
            var _close = document.createElement('span');
            _close.innerHTML = 'X';
            _close.title = this.STR_CLOSE_WINDOW;
            _close.className = 'close';
            Event.on(_close, 'click', function() {
                this.closeWindow();
            }, this, true);
            var _knob = document.createElement('span');
            _knob.innerHTML = '^';
            _knob.className = 'knob';
            win._knob = _knob;

            var _header = document.createElement('h3');
            _header.innerHTML = win.header;

            panel.cfg.setProperty('width', win.attrs.width);
            panel.setHeader(' '); //Clear the current header
            panel.appendToHeader(_header);
            _header.appendChild(_close);
            _header.appendChild(_knob);
            panel.setBody(' '); //Clear the current body
            panel.setFooter(' '); //Clear the current footer
            if (win.footer !== null) {
                panel.setFooter(win.footer);
                Dom.addClass(panel.footer, 'open');
            } else {
                Dom.removeClass(panel.footer, 'open');
            }
            panel.appendToBody(body); //Append the new DOM node to it
            var fireShowEvent = function() {
                panel.bringToTop();
                Event.on(panel.element, 'click', function(ev) {
                    Event.stopPropagation(ev);
                });
                this._setBusy(true);
                panel.showEvent.unsubscribe(fireShowEvent);
            };
            panel.showEvent.subscribe(fireShowEvent, this, true);
            var fireCloseEvent = function() {
                this.currentWindow = null;
                var evName = 'window' + windowName + 'Close';
                this.fireEvent(evName, { type: evName, target: this });
                panel.hideEvent.unsubscribe(fireCloseEvent);
            };
            panel.hideEvent.subscribe(fireCloseEvent, this, true);
            this.currentWindow = win;
            this.moveWindow(true);
            panel.show();
            this.fireEvent('afterOpenWindow', { type: 'afterOpenWindow', win: win, panel: panel });
        },
        /**
        * @method moveWindow
        * @param {Boolean} force Boolean to tell it to move but not use any animation (Usually done the first time the window is loaded.)
        * @description Realign the window with the currentElement and reposition the knob above the panel.
        */
        moveWindow: function(force) {
            if (!this.currentWindow) {
                return false;
            }
            var win = this.currentWindow,
                xy = Dom.getXY(this.currentElement[0]),
                elXY = Dom.getXY(this.get('iframe').get('element')),
                panel = this.get('panel'),
                //newXY = [(xy[0] + elXY[0] - 20), (xy[1] + elXY[1] + 10)],
                newXY = [(xy[0] + elXY[0]), (xy[1] + elXY[1])],
                wWidth = (parseInt(win.attrs.width, 10) / 2),
                align = 'center',
                orgXY = panel.cfg.getProperty('xy') || [0,0],
                _knob = win._knob,
                xDiff = 0,
                yDiff = 0,
                anim = false;


            newXY[0] = ((newXY[0] - wWidth) + 20);
            //Account for the Scroll bars in a scrolled editor window.
            newXY[0] = newXY[0] - Dom.getDocumentScrollLeft(this._getDoc());
            newXY[1] = newXY[1] - Dom.getDocumentScrollTop(this._getDoc());
            
            if (this._isElement(this.currentElement[0], 'img')) {
                if (this.currentElement[0].src.indexOf(this.get('blankimage')) != -1) {
                    newXY[0] = (newXY[0] + (75 / 2)); //Placeholder size
                    newXY[1] = (newXY[1] + 75); //Placeholder sizea
                } else {
                    var w = parseInt(this.currentElement[0].width, 10);
                    var h = parseInt(this.currentElement[0].height, 10);
                    newXY[0] = (newXY[0] + (w / 2));
                    newXY[1] = (newXY[1] + h);
                }
                newXY[1] = newXY[1] + 15;
            } else {
                var fs = Dom.getStyle(this.currentElement[0], 'fontSize');
                if (fs && fs.indexOf && fs.indexOf('px') != -1) {
                    newXY[1] = newXY[1] + parseInt(Dom.getStyle(this.currentElement[0], 'fontSize'), 10) + 5;
                } else {
                    newXY[1] = newXY[1] + 20;
                }
            }
            if (newXY[0] < elXY[0]) {
                newXY[0] = elXY[0] + 5;
                align = 'left';
            }

            if ((newXY[0] + (wWidth * 2)) > (elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10))) {
                newXY[0] = ((elXY[0] + parseInt(this.get('iframe').get('element').clientWidth, 10)) - (wWidth * 2) - 5);
                align = 'right';
            }
            
            try {
                xDiff = (newXY[0] - orgXY[0]);
                yDiff = (newXY[1] - orgXY[1]);
            } catch (e) {}


            var iTop = elXY[1] + parseInt(this.get('height'), 10);
            var iLeft = elXY[0] + parseInt(this.get('width'), 10);
            if (newXY[1] > iTop) {
                newXY[1] = iTop;
            }
            if (newXY[0] > iLeft) {
                newXY[0] = (iLeft / 2);
            }
            
            //Convert negative numbers to positive so we can get the difference in distance
            xDiff = ((xDiff < 0) ? (xDiff * -1) : xDiff);
            yDiff = ((yDiff < 0) ? (yDiff * -1) : yDiff);

            if (((xDiff > 10) || (yDiff > 10)) || force) { //Only move the window if it's supposed to move more than 10px or force was passed (new window)
                var _knobLeft = 0,
                    elW = 0;

                if (this.currentElement[0].width) {
                    elW = (parseInt(this.currentElement[0].width, 10) / 2);
                }

                var leftOffset = xy[0] + elXY[0] + elW;
                _knobLeft = leftOffset - newXY[0];
                //Check to see if the knob will go off either side & reposition it
                if (_knobLeft > (parseInt(win.attrs.width, 10) - 1)) {
                    _knobLeft = ((parseInt(win.attrs.width, 10) - 30) - 1);
                } else if (_knobLeft < 40) {
                    _knobLeft = 1;
                }
                if (isNaN(_knobLeft)) {
                    _knobLeft = 1;
                }
                if (force) {
                    if (_knob) {
                        _knob.style.left = _knobLeft + 'px';
                    }
                    if (this.get('animate')) {
                        Dom.setStyle(panel.element, 'opacity', '0');
                        anim = new YAHOO.util.Anim(panel.element, {
                            opacity: {
                                from: 0,
                                to: 1
                            }
                        }, 0.1, YAHOO.util.Easing.easeOut);
                        panel.cfg.setProperty('xy', newXY);
                        anim.onComplete.subscribe(function() {
                            if (this.browser.ie) {
                                panel.element.style.filter = 'none';
                            }
                        }, this, true);
                        anim.animate();
                    } else {
                        panel.cfg.setProperty('xy', newXY);
                    }
                } else {
                    if (this.get('animate')) {
                        anim = new YAHOO.util.Anim(panel.element, {}, 0.5, YAHOO.util.Easing.easeOut);
                        anim.attributes = {
                            top: {
                                to: newXY[1]
                            },
                            left: {
                                to: newXY[0]
                            }
                        };
                        anim.onComplete.subscribe(function() {
                            panel.cfg.setProperty('xy', newXY);
                        });
                        //We have to animate the iframe shim at the same time as the panel or we get scrollbar bleed ..
                        var iframeAnim = new YAHOO.util.Anim(panel.iframe, anim.attributes, 0.5, YAHOO.util.Easing.easeOut);

                        var _knobAnim = new YAHOO.util.Anim(_knob, {
                            left: {
                                to: _knobLeft
                            }
                        }, 0.6, YAHOO.util.Easing.easeOut);
                        anim.animate();
                        iframeAnim.animate();
                        _knobAnim.animate();
                    } else {
                        _knob.style.left = _knobLeft + 'px';
                        panel.cfg.setProperty('xy', newXY);
                    }
                }
            }
        },
        /**
        * @private
        * @method _closeWindow
        * @description Close the currently open EditorWindow with the Escape key.
        * @param {Event} ev The keypress Event that we are trapping
        */
        _closeWindow: function(ev) {
            if ((ev.charCode == 87) && ev.shiftKey && ev.ctrlKey) {
                if (this.currentWindow) {
                    this.closeWindow();
                }
            }
        },
        /**
        * @method closeWindow
        * @description Close the currently open EditorWindow.
        */
        closeWindow: function() {
            YAHOO.widget.EditorInfo.window = {};
            this.fireEvent('closeWindow', { type: 'closeWindow', win: this.currentWindow });
            this.currentWindow = null;
            this.get('panel').hide();
            this.get('panel').cfg.setProperty('xy', [-900,-900]);
            this.get('panel').syncIframe(); //Needed to move the iframe with the hidden panel
            this.unsubscribeAll('afterExecCommand');
            this.toolbar.set('disabled', false); //enable the toolbar now that the window is closed
            this.toolbar.resetAllButtons();
            this._focusWindow();
            Event.removeListener(document, 'keypress', this._closeWindow);
        },
        /* {{{  Command Overrides - These commands are only over written when we are using the advanced version */
        /**
        * @method cmd_heading
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('heading') is used.
        */
        cmd_heading: function(value) {
            var exec = true,
                el = null,
                action = 'heading',
                _sel = this._getSelection(),
                _selEl = this._getSelectedElement();

            if (_selEl) {
                _sel = _selEl;
            }
            
            if (this.browser.ie) {
                action = 'formatblock';
            }
            if (value == 'none') {
                if ((_sel && _sel.tagName && (_sel.tagName.toLowerCase().substring(0,1) == 'h')) || (_sel && _sel.parentNode && _sel.parentNode.tagName && (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h'))) {
                    if (_sel.parentNode.tagName.toLowerCase().substring(0,1) == 'h') {
                        _sel = _sel.parentNode;
                    }
                    if (this._isElement(_sel, 'html')) {
                        return [false];
                    }
                    el = this._swapEl(_selEl, 'span', function(el) {
                        el.className = 'yui-non';
                    });
                    this._selectNode(el);
                    this.currentElement[0] = el;
                }
                exec = false;
            } else {
                if (this._isElement(_selEl, 'h1') || this._isElement(_selEl, 'h2') || this._isElement(_selEl, 'h3') || this._isElement(_selEl, 'h4') || this._isElement(_selEl, 'h5') || this._isElement(_selEl, 'h6')) {
                    el = this._swapEl(_selEl, value);
                    this._selectNode(el);
                    this.currentElement[0] = el;
                } else {
                    this._createCurrentElement(value);
                    this._selectNode(this.currentElement[0]);
                }
                exec = false;
            }
            return [exec, action];
        },
        /**
        * @method cmd_hiddenelements
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('hiddenelements') is used.
        */
        cmd_hiddenelements: function(value) {
            if (this._showingHiddenElements) {
                //Don't auto highlight the hidden button
                this._lastButton = null;
                this._showingHiddenElements = false;
                this.toolbar.deselectButton('hiddenelements');
                Dom.removeClass(this._getDoc().body, this.CLASS_HIDDEN);
            } else {
                this._showingHiddenElements = true;
                Dom.addClass(this._getDoc().body, this.CLASS_HIDDEN);
                this.toolbar.selectButton('hiddenelements');
            }
            return [false];
        },
        /**
        * @method cmd_removeformat
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('removeformat') is used.
        */
        cmd_removeformat: function(value) {
            var exec = true;
            /**
            * @knownissue Remove Format issue
            * @browser Safari 2.x
            * @description There is an issue here with Safari, that it may not always remove the format of the item that is selected.
            * Due to the way that Safari 2.x handles ranges, it is very difficult to determine what the selection holds.
            * So here we are making the best possible guess and acting on it.
            */
            if (this.browser.webkit && !this._getDoc().queryCommandEnabled('removeformat')) {
                var _txt = this._getSelection()+'';
                this._createCurrentElement('span');
                this.currentElement[0].className = 'yui-non';
                this.currentElement[0].innerHTML = _txt;
                for (var i = 1; i < this.currentElement.length; i++) {
                    this.currentElement[i].parentNode.removeChild(this.currentElement[i]);
                }
                /*
                this._createCurrentElement('span');
                YAHOO.util.Dom.addClass(this.currentElement[0], 'yui-non');
                var re= /<\S[^><]*>/g;
                var str = this.currentElement[0].innerHTML.replace(re, '');
                var _txt = this._getDoc().createTextNode(str);
                this.currentElement[0].parentNode.parentNode.replaceChild(_txt, this.currentElement[0].parentNode);
                */
                
                exec = false;
            }
            return [exec];
        },
        /**
        * @method cmd_script
        * @param action action passed from the execCommand method
        * @param value Value passed from the execCommand method
        * @description This is a combined execCommand override method. It is called from the cmd_superscript and cmd_subscript methods.
        */
        cmd_script: function(action, value) {
            var exec = true, tag = action.toLowerCase().substring(0, 3),
                _span = null, _selEl = this._getSelectedElement();

            if (this.browser.webkit) {
                if (this._isElement(_selEl, tag)) {
                    _span = this._swapEl(this.currentElement[0], 'span', function(el) {
                        el.className = 'yui-non';
                    });
                    this._selectNode(_span);
                } else {
                    this._createCurrentElement(tag);
                    var _sub = this._swapEl(this.currentElement[0], tag);
                    this._selectNode(_sub);
                    this.currentElement[0] = _sub;
                }
                exec = false;
            }
            return exec;
        },
        /**
        * @method cmd_superscript
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('superscript') is used.
        */
        cmd_superscript: function(value) {
            return [this.cmd_script('superscript', value)];
        },
        /**
        * @method cmd_subscript
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('subscript') is used.
        */
        cmd_subscript: function(value) {
            return [this.cmd_script('subscript', value)];
        },
        /**
        * @method cmd_indent
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('indent') is used.
        */
        cmd_indent: function(value) {
            var exec = true, selEl = this._getSelectedElement(), _bq = null;

            if (this.browser.webkit || this.browser.ie || this.browser.gecko) {
                if (this._isElement(selEl, 'blockquote')) {
                    _bq = this._getDoc().createElement('blockquote');
                    _bq.innerHTML = selEl.innerHTML;
                    selEl.innerHTML = '';
                    selEl.appendChild(_bq);
                    this._selectNode(_bq);
                } else {
                    this._createCurrentElement('blockquote');
                    for (var i = 0; i < this.currentElement.length; i++) {
                        _bq = this._getDoc().createElement('blockquote');
                        _bq.innerHTML = this.currentElement[i].innerHTML;
                        this.currentElement[i].parentNode.replaceChild(_bq, this.currentElement[i]);
                        this.currentElement[i] = _bq;
                    }
                    this._selectNode(this.currentElement[0]);
                }
                exec = false;
            } else {
                value = 'blockquote';
            }
            return [exec, 'indent', value];
        },
        /**
        * @method cmd_outdent
        * @param value Value passed from the execCommand method
        * @description This is an execCommand override method. It is called from execCommand when the execCommand('outdent') is used.
        */
        cmd_outdent: function(value) {
            var exec = true, selEl = this._getSelectedElement(), _bq = null, _span = null;
            if (this.browser.webkit || this.browser.ie || this.browser.gecko) {
                selEl = this._getSelectedElement();
                if (this._isElement(selEl, 'blockquote')) {
                    var par = selEl.parentNode;
                    if (this._isElement(selEl.parentNode, 'blockquote')) {
                        par.innerHTML = selEl.innerHTML;
                        this._selectNode(par);
                    } else {
                        _span = this._getDoc().createElement('span');
                        _span.innerHTML = selEl.innerHTML;
                        YAHOO.util.Dom.addClass(_span, 'yui-non');
                        par.replaceChild(_span, selEl);
                        this._selectNode(_span);
                    }
                } else {
                }
                exec = false;
            } else {
                value = 'blockquote';
            }
            return [exec, 'indent', value];
        },
        /* }}}*/        
        /**
        * @method toString
        * @description Returns a string representing the editor.
        * @return {String}
        */
        toString: function() {
            var str = 'Editor';
            if (this.get && this.get('element_cont')) {
                str = 'Editor (#' + this.get('element_cont').get('id') + ')' + ((this.get('disabled') ? ' Disabled' : ''));
            }
            return str;
        }
    });
    /**
     * @description Class to hold Window information between uses. We use the same panel to show the windows, so using this will allow you to configure a window before it is shown.
     * This is what you pass to Editor.openWindow();. These parameters will not take effect until the openWindow() is called in the editor.
     * @class EditorWindow
     * @param {String} name The name of the window.
     * @param {Object} attrs Attributes for the window. Current attributes used are : height and width
    */
    YAHOO.widget.EditorWindow = function(name, attrs) {
        /**
        * @private
        * @property name
        * @description A unique name for the window
        */
        this.name = name.replace(' ', '_');
        /**
        * @private
        * @property attrs
        * @description The window attributes
        */
        this.attrs = attrs;
    };

    YAHOO.widget.EditorWindow.prototype = {
        /**
        * @private
        * @property _cache
        * @description Holds a cache of the DOM for the window so we only have to build it once..
        */
        _cache: null,
        /**
        * @private
        * @property header
        * @description Holder for the header of the window, used in Editor.openWindow
        */
        header: null,
        /**
        * @private
        * @property body
        * @description Holder for the body of the window, used in Editor.openWindow
        */
        body: null,
        /**
        * @private
        * @property footer
        * @description Holder for the footer of the window, used in Editor.openWindow
        */
        footer: null,
        /**
        * @method setHeader
        * @description Sets the header for the window.
        * @param {String/HTMLElement} str The string or DOM reference to be used as the windows header.
        */
        setHeader: function(str) {
            this.header = str;
        },
        /**
        * @method setBody
        * @description Sets the body for the window.
        * @param {String/HTMLElement} str The string or DOM reference to be used as the windows body.
        */
        setBody: function(str) {
            this.body = str;
        },
        /**
        * @method setFooter
        * @description Sets the footer for the window.
        * @param {String/HTMLElement} str The string or DOM reference to be used as the windows footer.
        */
        setFooter: function(str) {
            this.footer = str;
        },
        /**
        * @method toString
        * @description Returns a string representing the EditorWindow.
        * @return {String}
        */
        toString: function() {
            return 'Editor Window (' + this.name + ')';
        }
    };
/**
* @event beforeOpenWindow
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
* @param {Overlay} panel The Overlay object that is used to create the window.
* @description Event fires before an Editor Window is opened. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event afterOpenWindow
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
* @param {Overlay} panel The Overlay object that is used to create the window.
* @description Event fires after an Editor Window is opened. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event closeWindow
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
* @description Event fires after an Editor Window is closed. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event windowCMDOpen
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
* @param {Overlay} panel The Overlay object that is used to create the window.
* @description Dynamic event fired when an <a href="YAHOO.widget.EditorWindow.html">EditorWindow</a> is opened.. The dynamic event is based on the name of the window. Example Window: createlink, opening this window would fire the windowcreatelinkOpen event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/
/**
* @event windowCMDClose
* @param {<a href="YAHOO.widget.EditorWindow.html">EditorWindow</a>} win The EditorWindow object
* @param {Overlay} panel The Overlay object that is used to create the window.
* @description Dynamic event fired when an <a href="YAHOO.widget.EditorWindow.html">EditorWindow</a> is closed.. The dynamic event is based on the name of the window. Example Window: createlink, opening this window would fire the windowcreatelinkClose event. See <a href="YAHOO.util.Element.html#addListener">Element.addListener</a> for more information on listening for this event.
* @type YAHOO.util.CustomEvent
*/

})();
YAHOO.register("editor", YAHOO.widget.Editor, {version: "2.5.2", build: "1076"});
var articleEditElement = null;
var articleEditTextId = -1;
var articleEditor = null;

function initUIArticle() {
    YAHOO.widget.Toolbar.prototype.STR_COLLAPSE = 'Click to close the editor.';
    var myConfig = {
        height: '200px',
	width: '650px',
	animate: true,
	autoHeight: true,
	setSize: false,
        markup: 'xhtml',
        removeLineBreaks: true
    };



    articleEditor = new YAHOO.widget.Editor('editor', myConfig);
    articleEditor._defaultToolbar.buttonType = 'basic';     
    articleEditor.render();

    articleEditor.on('toolbarLoaded', function() {  
        var config = { 
            group: 'File upload', 
            label: 'File upload', 
            buttons: [ 
                    { type: 'push', label: 'Upload a file', value: 'fileupload' } 
            ] 
        };
        this.toolbar.addSeparator(); 
        this.toolbar.addButtonGroup(config); 
  
            
        this.toolbar.on('toolbarCollapsed', function() {
            Dom.setXY(this.get('element_cont').get('element'), [-99999, -99999]);
            Dom.removeClass(this.toolbar.get('cont').parentNode, 'yui-toolbar-container-collapsed');
            articleEditor.saveHTML();
         
            var content = articleEditor.get('element').value;       
            articleEditElement.innerHTML = content;
            articleEditElement.style.height = 'auto';          
            document.getElementById('content_' + articleEditTextId).value = content;  
            document.getElementById('txtEdit_' + articleEditTextId).innerHTML = 'Cliquez ici pour modifier ce paragraphe';
          
            articleEditElement = null;
            articleEditTextId = -1;
        }, articleEditor, true);
        
        
        this.toolbar.on('insertimageClick', function() {
                var _sel = this._getSelectedElement();
                if (_sel && _sel.tagName && (_sel.tagName.toLowerCase() == 'img')) {
                } 
                else
                {
                    win = window.open(getHost() + '/weblogik/sites/shared/browser.html?type=1&siteName=' + getSiteName(), 'IMAGE_BROWSER', 'left=20,top=20,width=300,height=300,toolbar=0,resizable=0,status=0');

                    if (!win) {
                        alert('Please disable your popup blocker.');              
                    }
                    
                    return false;
                }
        }, articleEditor, true);  
        

        this.toolbar.on('fileuploadClick', function() {
            var ta = this.get('element');

            win = window.open(getHost() + '/weblogik/sites/shared/fu.html?siteName=' + getSiteName() + '&editor=editor', 'IMAGE_BROWSER', 'left=20,top=20,width=300,height=300,toolbar=0,resizable=1,status=0');

            if (!win) {
                    alert('Please disable your popup blocker.');
            }

            return false;
        }, articleEditor, true);
        
        
        
        
    }, articleEditor, true);

    articleEditor.render();
}

function editArticleUI(textId) {
    var target = document.getElementById('text_' + textId);
    if(target == null) {
        return;
    }
    
    
    if(articleEditElement !== null) {
        articleEditor.saveHTML();
        articleEditor.toolbar.fireEvent('toolbarCollapsed', false);
        //articleEditElement.innerHTML = articleEditor.get('element').value;                
        //articleEditElement.style.height = 'auto';
    }
    
    if(textId == articleEditTextId) {
        articleEditor.toolbar.fireEvent('toolbarCollapsed', false);
        articleEditElement = null;
        articleEditTextId = -1;
        return;
    }
            
    target.style.height = '400px';
            

    var xy = Dom.getXY(target);
    articleEditor.setEditorHTML(target.innerHTML);
    Dom.setXY(articleEditor.get('element_cont').get('element'), xy);
    
    articleEditElement = target;
    articleEditTextId = textId;
    
    document.getElementById('txtEdit_' + textId).innerHTML = 'Cliquez ici pour fermer l\'éditeur';
}

function saveArticleContentUI(textId) {
    if(articleEditTextId == textId && articleEditElement !== null) {
        articleEditor.toolbar.fireEvent('toolbarCollapsed', false);
    }    
    else { // sassurer que l'article soit saver
        if(articleEditElement !== null) {
            articleEditor.toolbar.fireEvent('toolbarCollapsed', false);
        }
        
        var target = document.getElementById('text_' + textId);
        articleEditor.setEditorHTML(target.innerHTML);
        articleEditor.saveHTML();

        var content = articleEditor.get('element').value;       
        document.getElementById('content_' + textId).value = content;  
    }


    return true;
}

function updateArticle(articleId, f /*form*/){
    
    var onLoad = function(){
        alert('L\'article a \u00E9t\u00E9 modifi\u00E9 avec succ\u00E8s\!');  
    };
    
    doc = new XML();
    doc._method = "POST";
    doc.setAttribute("articleId", articleId);
    doc.setAttribute("name", f.name.value);
    doc.setAttribute("subTitle", f.subTitle.value);
    doc.setAttribute("author", f.author.value);
    doc.setAttribute("nocache", Math.round(Math.random()*10000));
    doc.addListener(onLoad);
    doc.sendAndLoad("actions-pressUpdateArticle.do");
}
var openedDiv = -1;
var MAX_ONGLETS = 5;
var loaded = {};

var editingElement = null;
var editingTabId = -1;
var myEditor = null;
var Dom = YAHOO.util.Dom;
var Event = YAHOO.util.Event;
var lockedGalleryMedia = -1;

var isEditable = true;
var galSelectedItem = '';
var galOrganizationId = '';

function CloseOpenedDiv() {
    if(openedDiv > -1) {
        var spanTexte = document.getElementById('Name411_' +openedDiv);
        if(spanTexte != null) {
            spanTexte.innerHTML = 'D&eacute;tails';
        }
        
        HideDiv('Infos411_' + openedDiv);
        openedDiv = -1;
    }
}

function LoadCard(organizationId) {
    if(openedDiv == organizationId) {
        CloseOpenedDiv();
        return;
    }
    
    CloseOpenedDiv();
    
    if(loaded[organizationId]) {
        ShowDiv('Infos411_' + organizationId);
        openedDiv = organizationId;
    }
    else {    
        LoadOrgIntoDiv('page-carte411.do', 'Infos411_' + organizationId, organizationId);
    }
}

function LoadDetails(organizationId) {
    if(openedDiv == organizationId) {
        CloseOpenedDiv();
        return;
    }
    
    CloseOpenedDiv();
    
    if(loaded[organizationId]) {
        ShowDiv('Infos411_' + organizationId);
        openedDiv = organizationId;
        
        var spanTexte = document.getElementById('Name411_' +openedDiv);
        spanTexte.innerHTML = 'Fermer';
    }
    else {   
        LoadOrgIntoDiv('page-infos411.do', 'Infos411_' + organizationId, organizationId);
    }
}

function LoadOrgIntoDiv(pageName, divName, organizationId) {
    var div = document.getElementById(divName);
    
    
    var onDataLoaded = function(response){
        var txt = response.responseText;
        loaded[organizationId] = true;

        div.innerHTML = txt;   
        openedDiv = organizationId;
        ShowDiv('Infos411_' + organizationId);
        
        var spanTexte = document.getElementById('Name411_' +openedDiv);
        if(spanTexte != null) {
            spanTexte.innerHTML = 'Fermer';
        }
    }
    
    
    var doc = new XML(); 
    doc.addListener(onDataLoaded);    
    doc.setAttribute("orgId", organizationId);            
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.sendAndLoad(pageName);
    
    
}

function ShowDiv(divName) {
    document.getElementById(divName).style.display = 'block';
}

function HideDiv(divName) {
    document.getElementById(divName).style.display = 'none';
}



/* FICHE ENTREPRISE */

FicheEntreprise = function() {				
    this.reset();
}

FicheEntreprise.prototype.reset = function() {
    this.menuDivName = '';
    this.tabTitles = [];
    this.tabDivNames = [];
    this.tabEnabled = [];
    this.tabIds = [];
    this.tabTypes = [];
    
    this.selectedTab = -1;
    this.organizationId = -1
    this.selectedTabName = '';
    
    this.MAX_ONG = 5;
    this.isEditable = false;
    this.isBoutique = false;
}


FicheEntreprise.prototype.getTabId = function(index) {    
    return this.tabIds[index];
}

FicheEntreprise.prototype.setOrganizationId = function(orgId) {
    this.organizationId = orgId;
}

FicheEntreprise.prototype.setBoutique = function(isBoutique) {
    this.isBoutique = isBoutique;
}

FicheEntreprise.prototype.isBoutique = function() {
    return this.isBoutique;
}

FicheEntreprise.prototype.setSelectedTab = function(selectedTabName) {
    this.selectedTabName = selectedTabName.toLowerCase();
}


FicheEntreprise.prototype.getOrganizationId = function() {
    return this.organizationId;
}

FicheEntreprise.prototype.setMenuDiv = function(menuDiv) {
    this.menuDivName = menuDiv;
}

FicheEntreprise.prototype.setEditable = function(editable) {
    this.isEditable = editable;
}

FicheEntreprise.prototype.addTab = function(title, divname, tabid) {
    this.tabTitles.push(title);
    this.tabDivNames.push(divname);
    this.tabEnabled.push(true);
    this.tabIds.push(tabid);
    this.tabTypes.push('');
}

FicheEntreprise.prototype.addTabWithType = function(title, divname, tabid, type) {
    this.tabTitles.push(title);
    this.tabDivNames.push(divname);
    this.tabEnabled.push(true);
    this.tabIds.push(tabid);
    this.tabTypes.push(type);
}

FicheEntreprise.prototype.addTabDisabled = function(title, divname, tabid) {
    this.tabTitles.push(title);
    this.tabDivNames.push(divname);
    this.tabEnabled.push(false);
    this.tabIds.push(tabid);
    this.tabTypes.push('');
}

FicheEntreprise.prototype.disableTab = function(index) {
    if(index == this.selectedTab) {
        if(index > 0) {
            this.mouseOver(index - 1);
            this.clickedTab(index - 1);
        }
        else {
            this.mouseOver(index + 1);
            this.clickedTab(index + 1);
        }
    }
    
    this.tabEnabled[index] = false;
}

FicheEntreprise.prototype.enableTab = function(index) {
    this.tabEnabled[index] = true;
}

FicheEntreprise.prototype.renameTab = function(index, newname) {
    this.tabTitles[index] = newname;
}

FicheEntreprise.prototype.addContentTab = function(title, tabid, index) {
    var data = document.getElementById('contentContainer').innerHTML;    
    var divName = 'contentOnglet' + index;  
    
    
    
    data += '<div id="' + divName + '" style="display: none; margin-top: 10px;">';
    
    data += '<div><a href="javascript:showEditor('+tabid+')">Cliquez ici pour modifier le contenu de cet onglet</a></div>';
    data += '<div style="height: 10px; clear: both;"></div>';
    data += '<div class="containers" id="tab_'+tabid+'" style="min-height: 83px; overflow-y: auto; font-family: Arial,Verdana,Tahoma; font-size: 13px">';
    data += '<div> </div>';
    data += '</div>';
                        
    data += '<div style="clear: both; height: 10px;"></div>';
    
    data += '<form method="POST" action="actions-updateTab.do" onsubmit="return saveEditorContent();">';
        data += '<div style="display: none;"><textarea name="content" id="content_'+tabid+'"></textarea></div>';    
        data += '<input type="hidden" name="organizationId" value="' + this.getOrganizationId() + '" />';
        data += '<input type="hidden" name="tab_id" value="' + tabid + '" />';     
        data += '<div><input type="submit" value="Sauvegarder l\'onglet courant" /></div>';
    data += '</form>';    
    
    data += '</div>';
    
    
    
    document.getElementById('contentContainer').innerHTML = data;
    
    this.addTab(title, divName, tabid);
}

FicheEntreprise.prototype.showTabs = function() {
    var menuDiv = document.getElementById(this.menuDivName);
    var html = '';  
    for(var i = 0; i < this.tabTitles.length; i++) {
        if(this.tabEnabled[i] == false)
                continue;
        
        if(i > 0) {
            html += '<div style="float: left; height: 22px; width: 10px;"></div>';
        }
        
        var onClickAction = 'FicheTabClicked(' + i + ')';
        var onOverAction = 'FicheTabOver(' + i + ')';
        var onOutAction = 'FicheTabOut(' + i + ')';
        
        
        
        html += '<div style="float: left; cursor: pointer;" onclick="' + onClickAction + '" onmouseover="' + onOverAction + '" onmouseout="' + onOutAction + '">';     
        
        
        html += '<div style="float: left; height: 22px; width: 8px; background: url(\'img/onglets/Fiche/left_out.jpg\');" id="LeftTab_' + i + '">';
        html += '</div>';       
        
        html += '<div style="float: left; height: 22px; text-align: center; background: url(\'img/onglets/Fiche/bg_out.jpg\') repeat-x;" id="MidTab_' + i + '">';
        html += '<div class="FicheOngletsTitle">';
        html += this.tabTitles[i];
        html += '</div>';
        html += '</div>';
        
        html += '<div style="float: left; height: 22px; width: 4px; background: url(\'img/onglets/Fiche/right_out.jpg\');" id="RightTab_' + i + '">';
        html += '</div>';
        
        
        html += '</div>';
    }   

    menuDiv.innerHTML = html;    
    menuDiv.style.display = 'block';
    
    if(this.selectedTabName != '') {
        for(var i = 0; i < this.tabTitles.length; i++) {
          
            if(this.selectedTabName == this.tabTitles[i].toLowerCase()) {
                this.selectedTab = i;
                break;
            }
        }
        
        this.selectedTabName = '';
    }

    if(this.selectedTab == -1 || this.selectedTab >= this.tabTitles.length) {
        this.selectedTab = -1;
        
        var leftDiv = document.getElementById('LeftTab_0');
        var midDiv = document.getElementById('MidTab_0');
        var rightDiv = document.getElementById('RightTab_0');
        leftDiv.style.backgroundImage = leftDiv.style.backgroundImage.replace(/_out.jpg/, '_on.jpg');    
        midDiv.style.backgroundImage = midDiv.style.backgroundImage.replace(/_out.jpg/, '_on.jpg');    
        rightDiv.style.backgroundImage = rightDiv.style.backgroundImage.replace(/_out.jpg/, '_on.jpg');   

        this.mouseOver(0);
        this.clickedTab(0);
    }
    else {
        var index = this.selectedTab;
        this.selectedTab = -1;
        
        this.mouseOver(index);
        this.clickedTab(index);
    }
}

FicheEntreprise.prototype.mouseOver = function(index) {
    if(index == this.selectedTab) {
        return;
    }
    
    var leftDiv = document.getElementById('LeftTab_' + index);
    var midDiv = document.getElementById('MidTab_' + index);
    var rightDiv = document.getElementById('RightTab_' + index);

    leftDiv.style.backgroundImage = leftDiv.style.backgroundImage.replace(/_out.jpg/, '_on.jpg');    
    midDiv.style.backgroundImage = midDiv.style.backgroundImage.replace(/_out.jpg/, '_on.jpg');    
    rightDiv.style.backgroundImage = rightDiv.style.backgroundImage.replace(/_out.jpg/, '_on.jpg');    
}

FicheEntreprise.prototype.mouseOut = function(index) {
    if(index == this.selectedTab) {
        return;
    }
    
    var leftDiv = document.getElementById('LeftTab_' + index);
    var midDiv = document.getElementById('MidTab_' + index);
    var rightDiv = document.getElementById('RightTab_' + index);

    leftDiv.style.backgroundImage = leftDiv.style.backgroundImage.replace(/_on.jpg/, '_out.jpg');    
    midDiv.style.backgroundImage = midDiv.style.backgroundImage.replace(/_on.jpg/, '_out.jpg');    
    rightDiv.style.backgroundImage = rightDiv.style.backgroundImage.replace(/_on.jpg/, '_out.jpg');       
}

FicheEntreprise.prototype.clickedTab = function(index) {    
    if(index == this.selectedTab) {
        return;
    }
    
    if(this.selectedTab != -1) {        
        var leftDiv = document.getElementById('LeftTab_' + this.selectedTab);
        var midDiv = document.getElementById('MidTab_' + this.selectedTab);
        var rightDiv = document.getElementById('RightTab_' + this.selectedTab);

        leftDiv.style.backgroundImage = leftDiv.style.backgroundImage.replace(/_on.jpg/, '_out.jpg');    
        midDiv.style.backgroundImage = midDiv.style.backgroundImage.replace(/_on.jpg/, '_out.jpg');    
        rightDiv.style.backgroundImage = rightDiv.style.backgroundImage.replace(/_on.jpg/, '_out.jpg');    
    
        var div = document.getElementById(this.tabDivNames[this.selectedTab]);
        if(div != null)
            div.style.display = 'none';
        if(this.isEditable == true && this.selectedTab >= 3 && index < 3) {
            document.getElementById('contentContainer').style.display = 'none';
        }
    }
    
    if(this.isEditable == true && index >= 3) {
        document.getElementById('contentContainer').style.display = 'block';
    }
    
        
        
    var div = document.getElementById(this.tabDivNames[index]);
    if(div != null)
            div.style.display = 'block';
    
    this.selectedTab = index;
    
    if(editingElement !== null) {
        myEditor.toolbar.fireEvent('toolbarCollapsed', false);
    }
}

FicheEntreprise.prototype.getNumTabs = function() {
    return this.tabDivNames.length;
}


function FicheTabClicked(i) {
    _ficheEntreprise.clickedTab(i);
}

function FicheTabOver(i) {
    _ficheEntreprise.mouseOver(i);
}

function FicheTabOut(i) {
    _ficheEntreprise.mouseOut(i);
}


// AJOUTER, ENABLED/DISABLER, RENOMMER, MOVER UN ONGLET
function addOngletRow(hasBoutique) {
    
    
    var divName = 'newOnglet0';
    var index = 0;    
    
    // wow code laid
    if(document.getElementById(divName).innerHTML != '') {
        divName = 'newOnglet1';
        index = 1;
        
        if(document.getElementById(divName).innerHTML != '') {
            divName = 'newOnglet2';
            index = 2;
            
            
            if(document.getElementById(divName).innerHTML != '') {
              divName = 'newOnglet3';
              index = 3;
              
              if(document.getElementById(divName).innerHTML != '') {
                  return;
              }
           }
        }
    }
    
    var max = 2;
    if(hasBoutique)
        max = 3;
  
    var div = document.getElementById(divName);
    /*/
    var content = '<div style="clear: both;">';    
    content += '<div style="float: left; width: 30px;">';
    content += '<input type="checkbox" onclick="enableOnglet(' + (max + index) + ', this.checked)" checked="true" />';
    content += '</div>';
    content += '<div style="float: left; width: 250px;"><input type="text" id="onglet_'+index+'" style="width: 120px;" /></div>';
    content += '<div style="float: left;"><input type="button" onclick="renameOnglet(' + (max + index) + ', \'onglet_'+index+'\')" value="Modifier le nom" /></div>';
    content += '</div>';    
    div.innerHTML = content;
*/
    // AJAX POUR AJOUTER
    /*
    var tabId = 0;
    
    var onDataLoaded = function(response) {
        //var doc = response.responseXML.documentElement;
        //var tabs = getItems(doc, "Tab").items();
        //tabId = parseInt(tabs[0].getAttribute("id"));
        
        document.location.reload(true);
    }
    
    var doc = new XML(); 
    doc._method = 'POST';
    doc.addListener(onDataLoaded);     
    doc.setAttribute("organizationId", _ficheEntreprise.getOrganizationId());   
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.setAsyn(true);
    doc.sendAndLoad('actions-ajaxAddTab.do');
    */
   
   
    window.location = 'actions-ajaxAddTab.do?uniqId=' + Math.round(Math.random()*10000) + '&organizationId=' + _ficheEntreprise.getOrganizationId();
    
     /*/
    
    if(index == 2) {
        document.getElementById('ongletsAdd').style.display = 'none';
    }
    
    _ficheEntreprise.addContentTab('', tabId, index);
    _ficheEntreprise.showTabs();  
    */
    
}

function moveOnglet(up, typeOrId, infopageId) {
    var type = null;
    var tabId = 0;
    if(typeof typeOrId == 'string') {
        type = typeOrId;
    }
    else {
        tabId = parseInt(typeOrId);
    }
    
    var allo = function(response) {
        window.location = window.location;
    }

    var doc = new XML(); 
    doc._method = 'POST';
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    if(type != null)
      doc.setAttribute("type", type);   
    else
      doc.setAttribute("tabId", tabId);   
    doc.setAttribute("order", (up == true ? "up" : "down"));  
    doc.setAttribute("infopageId", infopageId);  
    doc.addListener(allo);
    doc.setAsyn(false);
    doc.sendAndLoad('actions-guideSetInfopageTabOrder.do');    
}

function enableOnglet(index, checked) {
    var doc = new XML(); 
    doc._method = 'POST'; 
    doc.setAttribute("id", _ficheEntreprise.getTabId(index));   
    doc.setAttribute("isActive", (checked ? 'true' : 'false'));           
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.setAsyn(false);
    doc.sendAndLoad('actions-checkActiveTabStatus.do');
  
    
    if(checked)
        _ficheEntreprise.enableTab(index);
    else
        _ficheEntreprise.disableTab(index);
    
    _ficheEntreprise.showTabs();
}

function renameOnglet(index, inputid) {
    // AJAX POUR RENOMER
     var newname = document.getElementById(inputid).value;

    
    if(inputid == 'ong_name_gallery') {    
        var doc = new XML(); 
        doc._method = 'POST';
        doc.addListener();    
        doc.setAttribute("galleryName", newname);        
        doc.setAttribute("organizationId", _ficheEntreprise.getOrganizationId());   
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.setAsyn(false);
        doc.sendAndLoad('actions-ajaxUpdateGalleryName.do');
    }
    else {
        var doc = new XML(); 
        doc._method = 'POST';
        doc.addListener();    
        doc.setAttribute("name", newname);        
        doc.setAttribute("id", _ficheEntreprise.getTabId(index));   
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.setAsyn(false);
        doc.sendAndLoad('actions-ajaxUpdateTabName.do');
    }
    
    _ficheEntreprise.renameTab(index, newname);
    _ficheEntreprise.showTabs();
}


function initUI() {
    YAHOO.widget.Toolbar.prototype.STR_COLLAPSE = 'Click to close the editor.';
    var myConfig = {
        height: '200px',
	width: '650px',
	animate: true,
	autoHeight: true,
	setSize: false,
        markup: 'xhtml',
        removeLineBreaks: true
    };



    myEditor = new YAHOO.widget.Editor('editor', myConfig);
    myEditor._defaultToolbar.buttonType = 'basic';     
    myEditor.render()
        
    myEditor.on('toolbarLoaded', function() {
        this.toolbar.on('toolbarCollapsed', function() {
            Dom.setXY(this.get('element_cont').get('element'), [-99999, -99999]);
            Dom.removeClass(this.toolbar.get('cont').parentNode, 'yui-toolbar-container-collapsed');            
            myEditor.saveHTML();
            myEditor.cleanHTML();
            
            var content = myEditor.get('element').value;            
            editingElement.innerHTML = myEditor.get('element').value;
            editingElement.style.height = 'auto';            
            document.getElementById('content_' + editingTabId).value = content;     
            document.getElementById('txtEdit_' + editingTabId).innerHTML = 'Cliquez ici pour modifier le contenu de cet onglet';
            
            editingElement = null;
            editingTabId = -1;
        }, myEditor, true);
        
        this.toolbar.on('insertimageClick', function() {
                // Get the selected element
                var _sel = this._getSelectedElement();

                
                // If the selected element is an image, do the normal thing so they can manipulate the image
                if (_sel && _sel.tagName && (_sel.tagName.toLowerCase() == 'img')) {
                    // Do the normal thing here...
                } 
                else
                {
                    //They don't have a selected image, open the image browser window
                    win = window.open(getHost() + '/weblogik/sites/shared/browser.html?siteName=' + getSiteName(), 'IMAGE_BROWSER', 'left=20,top=20,width=300,height=300,toolbar=0,resizable=0,status=0');

                    if (!win) { //Catch the popup blocker
                        alert('Please disable your popup blocker.');              
                    }
                    
                    return false;
            }
        }, myEditor, true);  
        
    }, myEditor, true);

    myEditor.render();
}

function showEditor(tab_id) {
    var target = document.getElementById('tab_' + tab_id);
    if(target == null) {
        return;
    }
    
    
    if(editingElement !== null) {
        myEditor.saveHTML();
        editingElement.innerHTML = myEditor.get('element').value;                
        editingElement.style.height = 'auto';
    }
    
    if(tab_id == editingTabId) {
        myEditor.toolbar.fireEvent('toolbarCollapsed', false);
        editingElement = null;
        editingTabId = -1;
        return;
    }
            
    target.style.height = '400px';
            

    var xy = Dom.getXY(target);
    myEditor.setEditorHTML(target.innerHTML);
    Dom.setXY(myEditor.get('element_cont').get('element'), xy);
    
    editingElement = target;
    editingTabId = tab_id;
    
    document.getElementById('txtEdit_' + editingTabId).innerHTML = 'Cliquez ici pour fermer l\'éditeur';
}

function saveEditorContent(tabId) {
    if(editingTabId == tabId && editingElement !== null) {
        myEditor.toolbar.fireEvent('toolbarCollapsed', false);
    }    
    else { // sassurer que l'article soit saver
        if(editingElement !== null) {
            myEditor.toolbar.fireEvent('toolbarCollapsed', false);
        }
        
        var target = document.getElementById('tab_' + tabId);
        myEditor.setEditorHTML(target.innerHTML);
        myEditor.saveHTML();

        var content = myEditor.get('element').value;       
        document.getElementById('content_' + tabId).value = content;  
     }
    
    return true;
}






/* EDITION FICHE ENTREPRISE */

function getOfficeInfo(officeId) {
    if (officeId == 0) {
        document.getElementById('addOrModifyButton').value = 'Ajouter';
        document.getElementById('deleteOfficeBtn').style.visibility = 'hidden';
        //document.getElementById('officeId').value = officeId;
        document.getElementById('addModifyOfficeForm').action = 'actions-guideAddOffice.do';
        
        document.getElementById('name_text').value = '';
        document.getElementById('address_text').value = '';
        document.getElementById('city_text').value = '';
        document.getElementById('postal_text').value = '';
        document.getElementById('fax_text').value = '';
        document.getElementById('phone_text').value = '';
        document.getElementById('cell_text').value = '';
        document.getElementById('tollfree_text').value = '';

        var orgC = new CountriesProvincesSelect('selectCountries', 'selectProvinces', 'province_lbl');    
        orgC.setDefault(1, 1);
        orgC.loadCountries();
        
        return;
    }
    else {
        document.getElementById('addOrModifyButton').value = 'Modifier';
        document.getElementById('deleteOfficeBtn').style.visibility = 'visible';
        //document.getElementById('officeId').value = officeId;
        document.getElementById('addModifyOfficeForm').action = 'actions-guideUpdateOffice.do';
    }
    
    doc = new XML(); 
    doc.addListener(onOfficeInfoReturned);  
    doc.setAttribute('officeId', officeId);
    doc.setAttribute('uniqId', Math.round(Math.random()*10000));
    doc.sendAndLoad('actions-guideGetOfficeDetails.do');
}

function onOfficeInfoReturned(response){
    var xmldoc = response.responseXML.documentElement;    
    
    document.getElementById('name_text').value = xmldoc.getAttribute('name');
    document.getElementById('address_text').value = xmldoc.getAttribute('address');
    document.getElementById('city_text').value = xmldoc.getAttribute('city');
    document.getElementById('postal_text').value = xmldoc.getAttribute('postalCode');
    document.getElementById('fax_text').value = xmldoc.getAttribute('fax');
    document.getElementById('phone_text').value = xmldoc.getAttribute('phone');
    document.getElementById('cell_text').value = xmldoc.getAttribute('cell');
    document.getElementById('tollfree_text').value = xmldoc.getAttribute('tollFree');

    document.getElementById('officeIdInput').value = xmldoc.getAttribute('id');
    
    var orgC = new CountriesProvincesSelect('selectCountries', 'selectProvinces', 'province_lbl');    
    orgC.setDefault(xmldoc.getAttribute('countryId'), xmldoc.getAttribute('provinceId'));
    orgC.loadCountries();
}

function setContactVisible(checkbox) {
    if(checkbox == null) {
        return;
    }
    
    var visible = '0';
    if(checkbox.checked) {
        visible = '1';
    }
    var personId = parseInt(checkbox.value);
    
    var retfunc = function(response) { 
        var msg = 'Le contact est maintenant non visible pour les utilisateurs.';
        if(checkbox.checked) {
            msg = 'Le contact est maintenant visible.';
        }
        alert(msg);
    };
    
    var doc = new XML();    
    doc.method = 'POST';    
    doc.setAsyn(false);   
    doc.addListener(retfunc);                   
    doc.setAttribute('uniqId', Math.round(Math.random()*10000));
    doc.setAttribute('visible', visible);
    doc.setAttribute('personId', personId);
    doc.sendAndLoad('actions-setVisibleContact.do');
}

function getMainContactVisibility(contactId) {
    
    var onVisibilityReturned = function(response) { 
        var xmldoc = response.responseXML.documentElement;
        if (xmldoc.firstChild.nodeValue == "yes") {
            document.getElementById('mainContactVisibility').checked = "checked";
        }
        else {
            document.getElementById('mainContactVisibility').checked = false;
        }
    };
    
    doc2 = new XML(); 
    doc2.addListener(onVisibilityReturned);  
    doc2.setAttribute("personId", contactId);
    doc2.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc2.sendAndLoad("actions-guideGetContactVisibility.do");    
}

function getContactInfo(contactId) {
    document.getElementById('contactIdInput').value = contactId;
    
    document.getElementById('firstname_text').value =  "";
    document.getElementById('lastname_text').value =  "";
    document.getElementById('function_text').value =  "";
    document.getElementById('email_text').value =  "";
    document.getElementById('contact_phone_text').value =  "";
    document.getElementById('contact_cell_text').value =  "";
    document.getElementById('contact_tollfree_text').value = "";
    if (contactId == 0) {
        document.getElementById('addOrModifyContactButton').value = "Ajouter";
        document.getElementById('contDeleteButton').style.visibility = "hidden";
        document.getElementById('chkContactVisible').style.visibility = "hidden";
        document.getElementById('visibleQuestion').style.visibility = "hidden";        
        document.getElementById('addModifyContactForm').action = "actions-guideAddContact.do";
    }
    else {
        document.getElementById('addOrModifyContactButton').value = "Modifier";
        document.getElementById('contDeleteButton').style.visibility = "visible";
        document.getElementById('chkContactVisible').style.visibility = "visible";
        document.getElementById('visibleQuestion').style.visibility = "visible";
        document.getElementById('addModifyContactForm').action = "actions-guideUpdateContact.do";
        
        doc = new XML(); 
        doc.addListener(onPersonInfoReturned);  
        doc.setAttribute("personId", contactId);
        doc.setAttribute("uniqId", Math.round(Math.random()*10000));
        doc.sendAndLoad("actions-guideGetPerson.do");
        getContactVisibility(contactId);
    }        
}

function getContactVisibility(contactId) {
    
    var onVisibilityReturned = function(response) { 
        var xmldoc = response.responseXML.documentElement;
        if (xmldoc.firstChild.nodeValue == "yes") {
            document.getElementById('chkContactVisible').checked = "checked";
            document.getElementById('chkContactVisible').value = xmldoc.getAttribute('id');
        }
        else {
            document.getElementById('chkContactVisible').checked = false;
            document.getElementById('chkContactVisible').value = xmldoc.getAttribute('id');
        }
    };
    
    doc2 = new XML(); 
    doc2.addListener(onVisibilityReturned);  
    doc2.setAttribute("personId", contactId);
    doc2.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc2.sendAndLoad("actions-guideGetContactVisibility.do");    
}


function onPersonInfoReturned(response) {
    var xmldoc = response.responseXML.documentElement;
    if(getItems(xmldoc, "title").items() != null) {
        if ((getItems(xmldoc, "title").items())[0].firstChild.nodeValue == "m")
            document.getElementById('contTitle').selectedIndex = 0;
        else
            document.getElementById('contTitle').selectedIndex = 1;
    }
    
    var item;
    
    item = getItems(xmldoc, "firstName").items();
    if(item != null && item.length != 0)
        document.getElementById('firstname_text').value = item[0].firstChild.nodeValue;
    
    item = getItems(xmldoc, "lastName").items();
    if(item != null && item.length != 0)
        document.getElementById('lastname_text').value = item[0].firstChild.nodeValue;
    
    item = getItems(xmldoc, "function").items();
    if(item != null && item.length != 0)
        document.getElementById('function_text').value = item[0].firstChild.nodeValue;
    
    item = getItems(xmldoc, "email").items();
    if(item != null && item.length != 0)
        document.getElementById('email_text').value = item[0].firstChild.nodeValue;
    
    item = getItems(xmldoc, "phone").items();
    if(item != null && item.length != 0)
        document.getElementById('contact_phone_text').value = item[0].firstChild.nodeValue;
    
    item = getItems(xmldoc, "cellPhone").items();
    if(item != null && item.length != 0)
        document.getElementById('contact_cell_text').value = item[0].firstChild.nodeValue;
    
    item = getItems(xmldoc, "tollFree").items();
    if(item != null && item.length != 0)
        document.getElementById('contact_tollfree_text').value = item[0].firstChild.nodeValue;
}

function getFileName(what) {
    if (what.indexOf('/') > -1)
        answer = what.substring(what.lastIndexOf('/')+1,what.length);
    else
        answer = what.substring(what.lastIndexOf('\\')+1,what.length);
    document.getElementById("filename").value = answer;
    ext = answer.substring(answer.lastIndexOf('.')+1, answer.length);
    document.getElementById("ext").value = ext;
}

function validate(id) {
    if (confirm('Voulez-vous vraiment supprimer ce document ?')) {
        document.getElementById('delete_'+id).submit();
    }
}



// gallery: affichage
function chgBigImgInGallery(mediaId) {    
    if(lockedGalleryMedia == -1) {
        document.getElementById('bigLeftGal').src = 'uploaded/InfoPage/Gallery/' + mediaId + '-Large.jpg';   
        document.getElementById('lnkZoom').href = 'uploaded/InfoPage/Gallery/' + mediaId + '-Default.jpg'; 
    }
}

function lockImgInGallery(mediaId) {
    if(mediaId == lockedGalleryMedia) {        
        document.getElementById('boxGallery-' + lockedGalleryMedia).style.border = '1px solid #CCCCCC';
        lockedGalleryMedia = -1;
        return;
    }

    if(lockedGalleryMedia != -1) {
        document.getElementById('boxGallery-' + lockedGalleryMedia).style.border = '1px solid #CCCCCC';
        lockedGalleryMedia = -1;
        
        chgBigImgInGallery(mediaId);
        
        lockedGalleryMedia = mediaId;
        document.getElementById('boxGallery-' + mediaId).style.border = '1px solid black';
    }
    else {
        lockedGalleryMedia = mediaId;
        document.getElementById('boxGallery-' + mediaId).style.border = '1px solid black';
    } 
}

// gallery: edition
function editBannerImageInfoPage() {
    document.getElementById('bannerUploadForm').style.display = "block";
    document.getElementById('bannerImage').style.display = "none";
}

function cancelBannerImageInfoPage() {
    document.getElementById('bannerUploadForm').style.display = "none";
    document.getElementById('bannerImage').style.display = "block";
}

function viewGalleryThumbnail(mediaId) {
    document.getElementById('ipGalleryLarge').src = 'uploaded/InfoPage/Gallery/'+mediaId+'-Large.jpg';
}

function viewGalleryThumbnailEditMode(mediaId) {
    if (mediaId != 0) {
        //document.getElementById('ipGalleryLargeEdit').src = 'uploaded/InfoPage/Gallery/'+mediaId+'-Large.jpg';
        document.getElementById('ipGalleryLargeEdit').style.backgroundImage = 'url(uploaded/InfoPage/Gallery/'+mediaId+'-Large.jpg)';
    }
}

function cancelGalleryThumbnailEditMode() {
    if (document.getElementById('selectedItemId').value == "") {
        document.getElementById('ipGalleryLargeEdit').style.backgroundImage = 'url(uploaded/InfoPage/Gallery/0-Large.jpg)';
    } else {
        document.getElementById('ipGalleryLargeEdit').style.backgroundImage = 'url(images/guide/galleryinfopageselect.jpg)';
    }
}

/* pour le pager */



function gallerySetOrganizationId(id) {
    galOrganizationId = id;
}

                            
function selectGalleryItem(itemId, mediaId) { 
    var uploadGalleryImage = document.getElementById('uploadGalleryImage2');
    var content = '';
    
    if(galSelectedItem == "") {
        galSelectedItem = itemId;        
        

            content += '<div class="photoMorpher">Modifier une image dans la galerie</div>'
            
            content += '<div style="margin-left: 15px">';
            content += '<form method="post" enctype="multipart/form-data" action="actions-uploadGalleryItem.do">';
            content += '<input type="hidden" value="' + galOrganizationId + '" name="organizationId"/>';
            content += '<input type="hidden" value="' + itemId + '" name="itemId"/>';
            content += 'Veuillez choisir une image : ';
            content += '<input type="file" name="file"/> ';
            content += '<input class="submitBtn" type="submit" value="Modifier" />';
            content += '</form>';
            
            content += '<br/><br/>';
            
            
            content += '<form method="post" action="actions-deleteGalleryItem.do" >';
            content += '<input type="hidden" name="organizationId" value="' + galOrganizationId + '"/>';
            content += '<span style="margin-left: 15px"><input type="hidden" value="' + itemId + '" name="itemId"/></span>';
            content += '<input class="submitBtn" type="submit" value="Effacer l\'image séléctionnée" />';
            content += '</form>';
             
            content += '</div>';
        
        
        uploadGalleryImage.innerHTML = content;
        document.getElementById('galleryItemDiv-' + itemId).style.borderColor = '#005C99';        
    }
    else {        
        content += '<div class="photoMorpher">Ajouter une image dans la galerie</div>'
            
        content += '<div style="margin-left: 15px">';
        content += '<form method="post" enctype="multipart/form-data" action="actions-uploadGalleryItem.do">';
        content += '<input type="hidden" value="' + galOrganizationId + '" name="organizationId"/>';
        content += 'Veuillez choisir une image : ';
        content += '<input type="file" name="file"/> ';
        content += '<input class="submitBtn" type="submit" value="Ajouter" />';
        content += '</form>';
        content += '</div>';
        
        document.getElementById('galleryItemDiv-' + galSelectedItem).style.borderColor = '#CCC'; 
        
        galSelectedItem = "";
        
        uploadGalleryImage.innerHTML = content;
    }
    //cancelGalleryThumbnailEditMode();
}

swapdoc = new XML(); 
function swapGalleryItems(firstItemId, secondItemId) {
    swapdoc.setAttribute('firstId', firstItemId);
    swapdoc.setAttribute('secondId', secondItemId);
    swapdoc.setAttribute('uniqId', Math.round(Math.random()*10000));
    swapdoc.setAsyn(false);
    swapdoc.sendAndLoad('actions-swapGalleryItem.do');
    
    var div1 = document.getElementById('bigDiv-'+firstItemId);
    var div2 = document.getElementById('bigDiv-'+secondItemId);
    var temp = div1.innerHTML;
    div1.innerHTML = div2.innerHTML;
    div2.innerHTML = temp;        
    div1.id = 'bigDiv-'+secondItemId;
    div2.id = 'bigDiv-'+firstItemId;
}

function adminCardEditClick() {
    var display = document.getElementById('AdminCardShow').style.display;
    
    if(display != 'none') {
        document.getElementById('AdminCardShow').style.display = 'none';
        document.getElementById('AdminCardEdit').style.display = 'block';
    }
    else {
        document.getElementById('AdminCardShow').style.display = 'block';
        document.getElementById('AdminCardEdit').style.display = 'none';
    }
}

var galleryNumPages = 1;
var isGalleryEditable = false;

function setGalleryNumPages(n) {
    galleryNumPages = n;
}

function setGalleryEditable(b) {
    isGalleryEditable = b;
}

function loadGalleryPage(organizationId, page) {
    var doc = new XML(); 
    doc.addListener(onGalleryItemsLoaded);    
    doc.setAttribute("organizationId", organizationId);      
    doc.setAttribute("page", page);    
    doc.setAttribute("edit", isGalleryEditable);      
    doc.setAttribute("uniqId", Math.round(Math.random()*10000));
    doc.sendAndLoad('actions-getGalleryItems.do');
    
    updateGalleryPager(page, galleryNumPages, organizationId);
}

function onGalleryItemsLoaded(response) {
    var doc = response.responseXML.documentElement;
    var items = getItems(doc, "Item").items();
    var div = document.getElementById('thumbnailsDiv');
    var content = '';

    for(i = 0; i < items.length; i++) {
        var ext = 'jpg';
        
        var mediaId = items[i].getAttribute("mediaId");
        var id = items[i].getAttribute("id");
       
    
        if(isGalleryEditable == false) {
          content += '<div onclick="javascript:lockImgInGallery('+mediaId+')" style="cursor: pointer;"';
          content += 'id="boxGallery-'+mediaId+'" class="photoGalleryRight" ';
          content += 'onmouseover="chgBigImgInGallery('+mediaId+')">';
          content += '<img src="uploaded/InfoPage/Gallery/'+mediaId+'-Small.'+ext+'" />';
          content += '</div>';
      }
      else {
          content += '<div id="bigDiv-'+mediaId+'">';
          content += '<div class="photoGalleryRight" style="cursor: pointer; background: url(uploaded/InfoPage/Gallery/'+mediaId+'-Small.'+ext+') #fff top left no-repeat;"';
          content += 'onmouseover="viewGalleryThumbnailEditMode('+mediaId+')" id="galleryItemDiv-'+id+'" onclick="selectGalleryItem('+id+','+mediaId+')">';
          content += '</div>';
          content += '</div>';
      }
          
    }
    
    div.innerHTML = content;
}

function updateGalleryPager(page, numpages, organizationId) {
    var div = document.getElementById('galleryPager');
    var content ='';
    
    if(numpages > 1) {
        if(page > 1) {
            content += '<div class="pagerTxt"><a href="javascript:loadGalleryPage('+organizationId+', 1)">&lt;&lt;</a></div>';
            content += '<div class="pagerTxt"><a href="javascript:loadGalleryPage('+organizationId+', '+(page - 1)+')">&lt;</a></div>';
        }
        
        if(page - 2 >= 1) {
            content += '<div class="pagerTxt pagerLeftMargin">';
            content += '<a href="javascript:loadGalleryPage('+organizationId+', '+(page - 2)+')">'+(page - 2)+'</a>';
            content += '</div>';
        }
        
        if(page - 1 >= 1) {
            content += '<div class="pagerTxt pagerLeftMargin">';
            content += '<a href="javascript:loadGalleryPage('+organizationId+', '+(page - 1)+')">'+(page - 1)+'</a>';
            content += '</div>';
        }
        
        content += '<div class="pagerTxt pagerTxtBold pagerLeftMargin pagerTxtSelected">'+(page)+'</div>';
        
        if(page + 1 <= numpages) {
            content += '<div class="pagerTxt pagerLeftMargin">';
            content += '<a href="javascript:loadGalleryPage('+organizationId+', '+(page + 1)+')">'+(page + 1)+'</a>';
            content += '</div>';
        }
        
        if(page + 2 <= numpages) {
            content += '<div class="pagerTxt pagerLeftMargin">';
            content += '<a href="javascript:loadGalleryPage('+organizationId+', '+(page + 2)+')">'+(page + 2)+'</a>';
            content += '</div>';
        }
        
        if(page < numpages) {
            content += '<div class="pagerTxt pagerLeftMargin"><a href="javascript:loadGalleryPage('+organizationId+', '+(page + 1)+')">&gt;</a></div>';
            content += '<div class="pagerTxt pagerLeftMargin"><a href="javascript:loadGalleryPage('+organizationId+', '+(numpages)+')">&gt;&gt;</a></div>';
        }
    }
	    

    
    div.innerHTML = content;
}


