///////////////////////////////////////////////////////////////////////////////////////////////
// Doc-O-Matic(R) 7 script file.
// Copyright (C) 2000-2010 by toolsfactory software inc.
// http://www.toolsfactory.com
// http://www.doc-o-matic.com
//
// Distribution permitted as part of browser-based
// Help systems generated by Doc-O-Matic(R).
///////////////////////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////////////////////
// Available variables which are resolved when Doc-O-Matic use the file:
//
//    HEADER_FILE, TOCIDX_FILE, DEFAULT_TITLE_FILE, DEFAULT_TOPIC_FILE
//
//    SCRIPT_FILE, SCRIPT_FUNCTION_ONLOAD
//    STYLESHEET_FILE
//
//    WINDOW_NAME_HEADER, WINDOW_NAME_TOPIC, WINDOW_NAME_NAVIGATION
//    WINDOW_NAME_ADDINFO, WINDOW_NAME_HIERARCHY, WINDOW_NAME_SEEALSO,
//    WINDOW_NAME_LEGEND, WINDOW_NAME_BODYSOURCE, WINDOW_NAME_TOCIDX
//
//    TOC_IMAGE_PLUS, TOC_IMAGE_MINUS, SECTION_IMAGE_PLUS, SECTION_IMAGE_MINUS,
//    COLLAPSE_COOKIE_NAME, COLLAPSE_PERSISTENTSTORE_NAME,
//    COLLAPSE_STATESAVE_USECOOKIES, COLLAPSE_STATESAVE_USEPERSISTENCE
//
//    TOC_GROUP_CLASSNAME, TOC_TOPIC_CLASSNAME
//    TOC_HIGHLIGHT_GROUP_CLASSNAME, TOC_HIGHLIGHT_TOPIC_CLASSNAME
//
//    TABBEDSECTION_COOKIE_NAME, TABBEDSECTION_ELEMENT_CLASSNAMES
//
///////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////
// retrieves a variable from the search string
function getStringVar(varname) {
    var searchstr = document.location.search;
    var varidx = searchstr.indexOf(varname);

    if(varidx >= 0) {
        var startpos = varidx + varname.length +1;
        searchstr = searchstr.substring(startpos, searchstr.length);

        var nextpos = searchstr.length;
        if (searchstr.indexOf('&') >= 0) {
            nextpos = searchstr.indexOf('&');
        }

        searchstr = searchstr.substring(0, nextpos);
    } else {
        searchstr = '';
    }

    return unescape(searchstr);
}

///////////////////////////////////////////////////////////////////////////////////////////////
// searches the entire frameset and returns
// the frame with name frmname
function findFrame(w, frmname) {
    var res = null;

    if (frmname != '') {
        res = w.frames[frmname];

        // if it's not in the current window
        // search the sub-frames
        if (res == null) {
            var L = w.frames.length;
            var i;

            for (i = 0; i < L; i++) {
                res = findFrame(w.frames[i], frmname);
                if (res != null) {
                    break;
                }
            }
        }
    } else {
        result = this;
    }

    return res;
}

///////////////////////////////////////////////////////////////////////////////////////////////
// loads frame frmname with frmfile
function fillFrame(frmname, frmfile) {
    var theframe = findFrame(top, frmname);

    if (theframe != null) {
        theframe.location.replace(frmfile);
    }
    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////
// Called when the frameset file is loaded.
// Loads the framefile passed on the
// search string into the frame also passed
// on the search string
function loadTopicFrame() {
    var frmname = getStringVar('frmname');
    var frmfile = getStringVar('frmfile');

    if ((frmname != '') && (frmfile != '')) {
        fillFrame(frmname, frmfile);
    }
    
    return true;
}


var called = false;

///////////////////////////////////////////////////////////////////////////////////////////////
// ensures the current file is displayed within
// a frameset, if not loads the frame set which
// loads the file itself into the frameset.
function loadFrameSetOrTitle(framesetfile, targetframe, topicfile)
{
    if (!called) {
        called = true;
        if (self == top) {
            top.location.replace(framesetfile + '?frmname=' + escape(targetframe) + '&frmfile=' + escape(topicfile));
        }
    }

    return true;
}

function pathFromResource(path)
{
    var result = "";
    var a = path.split("/");
    var i;
    // reassemble but leave the last part out
    for (i = 0; i < (a.length-1); i++) {
        result = result + a[i] + "/";
    }
    return result;
}

function setNewImageSource(img, filename)
{
    var newsrc;
    var a = filename.split("/");
    if (a.length <= 1) {
        newsrc = pathFromResource(img.src) + filename;
    } else {
        newsrc = filename;
    }

    img.src = newsrc;
}

///////////////////////////////////////////////////////////////////////////////////////////////
// shows or hides a DIV based on whether
// it's visible or not. Also toggles the corresponding
// expand/collaps graphic.
function internalToggleVisibilityEx2(theDocument, imgID, divID, storeVisibilityState, storeID, forceHide, forceShow, imgplussrc, imgminussrc)
{
    var div = theDocument.getElementById(divID);
    var img = theDocument.getElementById(imgID);

    if (div != null) {
        // Unfold the branch if it isn't visible
        if (((!forceHide) || forceShow) && (div.style.display == 'none')) {
            if (img != null) {
                setNewImageSource(img, imgminussrc);
            }
            div.style.display = '';

            // store the state so we can recreate it
            if (storeVisibilityState) {
                saveVisibilityState(storeID, true);
            }
        // Collapse the branch if it IS visible
        } else if (!forceShow) {
            if (img != null) {
                setNewImageSource(img, imgplussrc);
            }
            div.style.display = 'none';

            // store the state so we can recreate it
            if (storeVisibilityState) {
                saveVisibilityState(storeID, false);
            }
        }
    }
}

function internalToggleVisibilityEx(imgID, divID, storeVisibilityState, storeID, forceHide, forceShow, imgplussrc, imgminussrc)
{
    internalToggleVisibilityEx2(document, imgID, divID, storeVisibilityState, storeID, forceHide, forceShow, imgplussrc, imgminussrc);
}


// toggles the visibility of divID and
// changes the img accordingly.
function toggleVisibilityTOC(imgID, divID)
{
    internalToggleVisibilityEx(imgID, divID, false, "", false, false, "btn_toc_expand.gif", "btn_toc_collapse.gif");
}

function toggleVisibilitySection(imgID, divID)
{
    internalToggleVisibilityEx(imgID, divID, false, "", false, false, "btn_expand_2.gif", "btn_collapse_2.gif");
}

// toggles the visibility of an item identified
// by storeID. To get the corresponding img
// and div ids, storeID is prefixed by
// "img" and "div".
function toggleVisibilityStored(storeID)
{
    var imgID = "img" + storeID;
    var divID = "div" + storeID;
    internalToggleVisibilityEx(imgID, divID, true, storeID, false, false, "btn_expand_2.gif", "btn_collapse_2.gif");
}

function isCorrespondingTOCItem(href, topicfile)
{
    var result = false;
    var pathidx = href.lastIndexOf("/");
    var filename = "";

    if (pathidx >= 0) {
        filename = href.substring(pathidx+1, href.length);

        if (filename == topicfile) {
            result = true;
        }
    }

    return result;
}

function expandTOC(framedoc, element)
{
    var baseid = "";
    var outerdiv = null;
    var pelement = element.parentNode;

    while (pelement != null) {
        if ((pelement.tagName == "DIV") && (pelement.id.substring(0, 3) == "div")) {
            baseid = pelement.id.substring(3, pelement.id.length);
            outerdiv = pelement;
            break;
        }

        pelement = pelement.parentNode;
    }

    if ((baseid != "") && (outerdiv != null)) {
        // expand the div if necessary
        internalToggleVisibilityEx2(framedoc, "img" + baseid, "div" + baseid, false, "", false, true, "btn_toc_expand.gif", "btn_toc_collapse.gif");

        // expand outer divs
        expandTOC(framedoc, outerdiv);
    }

    return true;
}

// ensures element is scrolled into view
// so it's visible on the page.
function ensureTOCEntryVisible(framedoc, element)
{
    var pos = 0;
    var scrollelement;
    var id = "areascroll";

    // first see if we have a scroll area div
    scrollelement = framedoc.getElementById(id);

    if (scrollelement == null) {
        scrollelement = framedoc.body;
    }

    if (scrollelement != null) {
        var delta = 0;

        var viewtop = scrollelement.scrollTop + scrollelement.offsetTop;
        var viewbottom = viewtop + scrollelement.offsetHeight;
        var scrollbarheight = 30;
        // the bottom-scrollbar's area is included in offsetHeight, so we have
        // to subtract a appropriate amount to account for that
        if (viewbottom > (scrollbarheight * 2)) {
            viewbottom = viewbottom - scrollbarheight;
        }
        
        var elementtop = element.offsetTop;
        if (navigator.family == 'ie4') {
            elementtop = elementtop + scrollelement.offsetTop;
        }
        var elementbottom = elementtop + element.offsetHeight;

        if (elementtop < viewtop) {
            delta = (elementtop - viewtop);
        } else if (elementbottom > viewbottom) {
            delta = (elementbottom-viewbottom);
        }

        if (delta != 0) {
            scrollelement.scrollTop = scrollelement.scrollTop + delta;
        }
    }
}

var currentTOCHighlightEntry = null;
var currentTOCHighlightEntryClass = "";

// hightlights the TOC entry that has been scrolled
// into view.
function highlightTOCEntry(framedoc, element)
{
    if (framedoc.currentTOCHighlightEntry != null) {
        framedoc.currentTOCHighlightEntry.className = framedoc.currentTOCHighlightEntryClass;

        framedoc.currentTOCHighlightEntry = null;
        framedoc.currentTOCHighlightEntryClass = "";
    }

    if (element != null) {
        var newclassname = "";

        if (element.className == "Element860") {
            newclassname = "Element874";
        } else if (element.className == "Element862") {
            newclassname = "Element875";
        }

        if (newclassname != "") {
            framedoc.currentTOCHighlightEntry = element;
            framedoc.currentTOCHighlightEntryClass = element.className;

            element.className = newclassname;
        }
    }
}

// searches for a link to topicfile in the TOC and
// highlights the corresponding node in the tree.
function doSynchTOC(topicfile)
{
    var frm = findFrame(top, "");
    var links = null;
    var idx;
    var toctreeid = "toctree";
    var treeroot;

    if (frm != null) {
        treeroot = frm.document.getElementById(toctreeid);

        if (treeroot != null) {
            links = treeroot.getElementsByTagName("a");

            for (idx=0; idx < links.length; idx++) {
                if (isCorrespondingTOCItem(links[idx].href, topicfile)) {
                    expandTOC(frm.document, links[idx]);
                    ensureTOCEntryVisible(frm.document, links[idx]);
                    highlightTOCEntry(frm.document, links[idx]);
                    break;
                }
            }
        }
    }

    return true;
}

// Initiates the TOC synchronization. If the
// TOC or index file is being loaded this
// functions finds the name of the topic file 
// currently displayed and synchronizes the
// TOC with that topic.
function synchTOC(topicfile)
{
    var frm = findFrame(top, "");
    if (frm != null) {
        // if we're loading the TOC or index file
        // then frm.document == document
        if (document.location == frm.document.location) {
            var topicfrm = findFrame(top, "");
            if (topicfrm != null) {
                var href = topicfrm.document.location.href;
                var pathidx = href.lastIndexOf("/");

                if (pathidx >= 0) {
                    topicfile = href.substring(pathidx+1, href.length);
                }
            }
        }
    }

    // now do the synchronization
    doSynchTOC(topicfile);
}


///////////////////////////////////////////////////////////////////////////////////////////////
// Copies the content of the element identified by ID
// to the clipboard. Works with Internet Explorer only.
function CopyElementToClipboard(ID)
{
    var element = document.getElementById(ID);

    if (element != null) {
        window.clipboardData.setData("Text", element.innerText);
    }
}


///////////////////////////////////////////////////////////////////////////////////////////////
// Popup and Fixed Header
//

///////////////////////////////////////////////////////////////////////////////////////////////
// support functions

// Returns a rectangle object initialized
// with the given parameters.
function Rectangle(left, top, width, height)
{
    this.left = left;
    this.top = top;
    this.width = width;
    this.height = height;
}

// Hides or shows a popup element
function setElementVisible(element, v) {
    if (v) {
        element.style.visibility = "visible";
    } else {
        element.style.visibility = "hidden";
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function f_filterResults(n_win, n_docel, n_body) {
    var n_result = n_win ? n_win : 0;
    if (n_docel && (!n_result || (n_result > n_docel)))
        n_result = n_docel;
    if (n_body && (!n_result || (n_result > n_body)))
        n_result = n_body;
    return n_result;
}
    
function f_clientWidth() {
    return f_filterResults (
        window.innerWidth ? window.innerWidth : 0,
        document.documentElement ? document.documentElement.clientWidth : 0,
        document.body ? document.body.clientWidth : 0);
}
function f_clientHeight() {
    return f_filterResults (
        window.innerHeight ? window.innerHeight : 0,
        document.documentElement ? document.documentElement.clientHeight : 0,
        document.body ? document.body.clientHeight : 0);
}
function f_scrollLeft() {
    return f_filterResults (
        window.pageXOffset ? window.pageXOffset : 0,
        document.documentElement ? document.documentElement.scrollLeft : 0,
        document.body ? document.body.scrollLeft : 0);
}
function f_scrollTop() {
    return f_filterResults (
        window.pageYOffset ? window.pageYOffset : 0,
        document.documentElement ? document.documentElement.scrollTop : 0,
        document.body ? document.body.scrollTop : 0);
}


// This function fills a rectange structure (r) with
// the window coordinates of the page client area
function getWindowClientArea(r)
{
    if (navigator.family == 'ie4') {
       r.left = document.body.scrollLeft;
    } else {
       r.left = window.pageXOffset;
    }

    if (navigator.family == 'ie4') {
       r.top = document.body.scrollTop;
    } else {
       r.top = window.pageYOffset;
    }

    r.width = window.document.body.clientWidth;
    if (!r.width) {
        r.width = window.innerWidth;
    }
    if (!r.width) {
        r.width = window.outerWidth;
    }

    r.height = window.document.body.clientHeight;
    if (!r.height) {
       r.height = window.innerHeight;
    }
    if (!r.height) {
       r.height = window.outerHeight;
    }
}

// Returns the absolute X coordinate of an element
// Source: DHTML Lab
function getRealLeft(theElement) {
    xPos = theElement.offsetLeft;
    tempEl = theElement.offsetParent;
    while (tempEl != null) {
        xPos += tempEl.offsetLeft;
        tempEl = tempEl.offsetParent;
    }
    return xPos;
}

// Returns the absolute Y coordinate of an element
// Source: DHTML Lab
function getRealTop(theElement) {
    yPos = theElement.offsetTop;
    tempEl = theElement.offsetParent;
    while (tempEl != null) {
        yPos += tempEl.offsetTop;
        tempEl = tempEl.offsetParent;
    }
    return yPos;
}

// This gets the extent of the given object
function getElementBounds(element, rect)
{
    if (typeof element.offsetLeft != 'undefined') {
        rect.left = getRealLeft(element);
        rect.top = getRealTop(element);
        rect.width = element.offsetWidth;
        rect.height = element.offsetHeight;
    } else {
        rect.left = 0;
        rect.top = 0;
        rect.width = 0;
        rect.height = 0;
    }
}

// Sets the x/y coordinates and the popup width but
// not the height, which auto-adjusts to the content.
function setElementBounds(element, rect)
{
    element.style.left = rect.left + "px";
    element.style.top = rect.top + "px";
    element.style.width = rect.width + "px";
    element.style.height = ""; //rect.height + "px";
}

// Browser dependent GetElementById version
function findElement(id)
{
    var ie = document.all;

    if (ie) {
        return document.all(id);
    } else {
        return document.getElementById(id);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////
// Popup Functions
//

var hidetimer = null;       // Helper timer. During the lifetime
                            // of this timer OnMouseDown events
                            // from the body will be ignored
var closetimer = null;      // Timer used to close a popup upon
                            // mouse click. Since the mouse click
                            // could be on a link, the browser would
                            // not load the target if we remove the
                            // popup immediately.
var thePopup = null;        // Holds the popup element, if one is active

// Fired when the hidetimer expires, simply
// deactivates and initializes the timer
// which signals that Body.OnMouseDown events
// will be processed.
function activateOnHide()
{
    clearTimeout(hidetimer);
    hidetimer = null;
}

// Shows a popup div
// Parameters:
//  trigger -           Element triggering the popup action. The
//                      popup will be aligned on the lower left
//                      edge of the TriggerElement.
//  divid -             The id of the DIV element that contains
//                      the popup content.
function showPopup(trigger, divid)
{
    // if there is a popup visible at the
    // moment, we need to close it.
    if (thePopup != null) {
        doClosePopup();
    }

    thePopup = findElement(divid);

    if (thePopup == null)
        return;

    var clientarea = new Rectangle;
    var popuprect = new Rectangle;
    var triggerrect = new Rectangle;

    getWindowClientArea(clientarea);
    getElementBounds(thePopup, popuprect);
    getElementBounds(trigger, triggerrect);

    // set the initial size, the height
    // will adjust automatically
    popuprect.left = 0;
    popuprect.top = triggerrect.top + triggerrect.height;
    popuprect.width = clientarea.width / 2;

    setElementBounds(thePopup, popuprect);

    // check if the popup is taller than
    // the client area and reset it in that
    // case
    getElementBounds(thePopup, popuprect);

    var maxheight = clientarea.height - popuprect.top - 20;

    if ((maxheight > 0) && (popuprect.height > maxheight)) {
        thePopup.style.overflow = "auto";
        thePopup.style.height = maxheight;
    }

    // show it
    setElementVisible(thePopup, true);

    // prevent the popup from closing
    // through a OnMouseDown on the body
    // for a short period of time
    hidetimer = setTimeout("activateOnHide();", 200);
}

// Closes the current popup (if any) and
// kills the close timer.
function doClosePopup()
{
    clearTimeout(closetimer);
    closetimer = null;

    if (thePopup != null) {
        setElementVisible(thePopup, false);
        thePopup = null;
    }
}

// Initiates closing the popup if
//  * Hiding is not blocked by the hidetimer, or
//  * the popup is already being closed
function closePopup()
{
    if ((hidetimer != null) || (closetimer != null)) {
        return;
    }

    // to give clicked links a chance for
    // begin activated, the actual closing
    // is delayed a little.
    closetimer = setTimeout("doClosePopup();", 400);
}

///////////////////////////////////////////////////////////////////////////////////////////////
// Fixed header area functions

var scrollbaroffsetright = 0;
var scrollbaroffsetbottomXHTML = 14;
var scrollbaroffsetbottomLegacy = 4;
var scrollSetupComplete = false;
    

function doSetupFixedHeader()
{
    if (document.body.clientWidth == 0)
        return;

    var divFixed = findElement("areafixed");
    var divScroll = findElement("areascroll");

    if ((divScroll != null) && (divFixed != null)) {

        if (!scrollSetupComplete) {
            document.body.scroll = "no"; // legacy
            document.body.style.overflow = "hidden";
            document.body.style.margin = "0px";
            document.body.style.height = "100%";
            document.body.parentNode.style.height = "100%";
            divScroll.style.overflow= "auto";
            scrollSetupComplete = true;
        }

        var bh = f_clientHeight();
        var bw = f_clientWidth();

        var h = bh - (divFixed.offsetHeight + scrollbaroffsetbottomXHTML);
        var b = bw - scrollbaroffsetright;

        if ((h > 0) && (b > 0)) {
            divScroll.style.top=0;
            divScroll.style.height = h + "px";
            //divScroll.style.width = b + "px";
        }
    }
}

//// Sets up the non-scrolling region and scroll area
//// must be called whenever the window size changes
//function doSetupFixedHeaderLegacy()
//{
//	if (document.body.clientWidth == 0)
//        return;
//
//	var divFixed = findElement("areafixed");
//	var divScroll = findElement("areascroll");
//
//    if ((divScroll != null) && (divFixed != null)) {
//        if (navigator.family == 'ie4') {
//		    document.body.scroll = "no";
// 		    divFixed.style.width = document.body.offsetWidth - 1;
//		    divScroll.style.paddingRight = "20px";
//        }
//
//		divScroll.style.overflow = "auto";
//
//	    var clientarea = new Rectangle;
//	    getWindowClientArea(clientarea);
//
//		divScroll.style.width = clientarea.width - scrollbaroffsetright;
//		divScroll.style.top=0;
//
//		if (clientarea.height > (divFixed.offsetHeight + scrollbaroffsetbottomLegacy)) {
//            var h = clientarea.height - (divFixed.offsetHeight + scrollbaroffsetbottomLegacy);
//    		divScroll.style.height = h + "px";
//        } else {
//		    divScroll.style.height = 0;
//		}
//	}
//}

// makes the page scoll normally so
// the print out will look ok.
function doBeforePrinting() {
    var i;

    if (window.text) {
        document.all.text.style.height = "auto";
    }

    for (i=0; i < document.all.length; i++){
        if (document.all[i].tagName == "BODY") {
            document.all[i].scroll = "yes";
        }
        if (document.all[i].id == "areafixed") {
            document.all[i].style.margin = "0px 0px 0px 0px";
            document.all[i].style.width = "100%";
        }
        if (document.all[i].id == "areascroll") {
            document.all[i].style.overflow = "visible";
            document.all[i].style.top = "5px";
            document.all[i].style.width = "100%";
            document.all[i].style.padding = "0px 10px 0px 30px";
        }
    }

    return;
}

// reloads the page to reset after changes
// in doBeforePrinting().
function reloadPage() {
    document.location.reload();
    return;
}

///////////////////////////////////////////////////////////////////////////////////////////////
// Expand/Collapse storage functions

var collapseStateCookieName = "DOM_Collapsed_Sections";
var collapsePersistenceName = "domdocSettings";

// If we create browser based HTML files, this variable will be true
var useCookies = true;

// If we create HTML Help or Help 2, this variable will be true
var usePersistence = false;

var tabbedSectionCookieName = "DOM_Tabbed_Sections";
var tabbedSectionElementClassNames = ["Element912", "Element911", "Element914", "Element913", "Element916", "Element915"];

///////////////////////////////////////////////////////////////////////////////////////////////
// Cookie helper functions
// from http://www.quirksmode.org/js/cookies.html

function createCookie(name,value,days)
{
    var expires = "";

    if (days) {
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        expires = "; expires="+date.toGMTString();
    }

    document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name)
{
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}

function eraseCookie(name)
{
    createCookie(name,"",-1);
}

///////////////////////////////////////////////////////////////////////////////////////////////
// Persistence functions for use in HTML Help and Help 2

// This variable temporarily holds the collapsed section
// ids until the get stored using persistence.
var persistentCollapsedIDs = "";

// Saves the persistent data from our temporary
// variable which holds the value to the persistent
// storage.
function savePersistentData()
{
    var id = "persistenceDiv";
    var pdiv = document.getElementById(id);
    if (pdiv != null) {
        try {
            pdiv.setAttribute("collapsedIDs", persistentCollapsedIDs);
            pdiv.save(collapsePersistenceName);
        } catch (e) {
            // HTML Help may trigger an exception
        }
    }
    return;
}

// Loads the persistent data from the persistent
// storage into our temporary variable which holds
// the value for further use.
function loadPersistentData()
{
    persistentCollapsedIDs = "";

    var id = "persistenceDiv";
    var pdiv = document.getElementById(id);
    if (pdiv != null) {
        try {
            pdiv.load(collapsePersistenceName);
            var data = pdiv.getAttribute("collapsedIDs");
            if (data != null) {
                persistentCollapsedIDs = data;
            }
        }
        catch (e) {
            // HTML Help may trigger an exception
        }
    }
    return;
}

// Removes the persistent data from the storage.
function removePersistenceData()
{
    var id = "persistenceDiv";
    var pdiv = document.getElementById(id);
    if (pdiv != null) {
        try {
            pdiv.removeAttribute("collapsedIDs");
            pdiv.save(collapsePersistenceName);
        }
        catch (e) {
            // HTML Help may trigger an exception
        }
    }
    return;
}

// Saves the persistent data to our temporary variable that
// acts as storage while the page is being displayed.
function savePersistentKey(key, value)
{
    persistentCollapsedIDs = value;
    return;
}

// Returns the content in our temporary variable that
// acts as storage while the page is being displayed.
function loadPersistentKey(key)
{
    return persistentCollapsedIDs;
}

// Clears our temporary variable and erases
// the value from the persistent storage.
function removePersitentKey(key)
{
    persistentCollapsedIDs = "";
    removePersistenceData();
    return;
}

///////////////////////////////////////////////////////////////////////////////////////////////
// Collapsed section storage functions

// Saves the ID list in ids either using
// cookies or persistent storage,
// depending on what we use right now.
function saveExpandState(ids)
{
    if (useCookies) {
        createCookie(collapseStateCookieName, ids, 14);  // we store the cookie for 14 days
    } else if (usePersistence) {
        savePersistentKey(collapsePersistenceName, ids);
    }

    return;
}

// Loads the collapsed ID list either from
// cookies or persistent storage,
// depending on what we use right now.
function loadExpandState()
{
    var data = "";
    if (useCookies) {
        data = readCookie(collapseStateCookieName);
    } else if (usePersistence) {
        data = loadPersistentKey(collapsePersistenceName);
    }

    return data;
}

// Removes the collapsed ID list either from
// cookies or persistent storage,
// depending on what we use right now.
function eraseExpandState()
{
    if (useCookies) {
        eraseCookie(collapseStateCookieName);
    } else if (usePersistence) {
        removePersitentKey(collapsePersistenceName);
    }

    return;
}

//////////////////////////////////////////////////////////////////////////////////////////////

// Adds an ID to a list of IDs
function doAddId(res, addId)
{
    var result = res;

    if (result != "") {
        result = result + ",";
    }

    result = result + addId;

    return result;
}

// Converts the stored id into a div and
// img Id an calls the showing function
function doShowHideCollapsedId(id, visible)
{
    var imgid = "img" + id;
    var divid = "div" + id;

    internalToggleVisibilityEx(imgid, divid, false, "", !visible, visible, "btn_expand_2.gif", "btn_collapse_2.gif");
}

// Goes through the list of Ids passed in ids and
// either adds a new ID, removes an ID, collapses
// or expands the elements in the list.
// Returns:
//   The new list of IDs.
// Parameters:
//   ids -        a string with the list of IDs, separated
//                by commas, ("ID1,ID2,ID3").
//   addId -      an ID to be added to the list.
//   removeId -   an ID to be removed from the list.
//   collapsIds - a boolean that indicates if the elements
//                in the list shall be collapsed.
//   expandIds -  a boolean that indicates if the elements
//                in the list shall be expanded.
function processCollapsedIds(ids, addId, removeId, collapsIds, expandIds)
{
    var result = "";
    var idlist = ids;

    while (idlist.length > 0) {
        var id = "";
        var idx = idlist.indexOf(',');

        if (idx >= 0) {
            id = idlist.substring(0, idx);
            idlist = idlist.substring(idx+1);
        } else {
            id = idlist;
            idlist = "";
        }

        if (collapsIds) {
            doShowHideCollapsedId(id, false);
        }

        if (expandIds) {
            doShowHideCollapsedId(id, true);
        }

        // check if add Id is
        // already in the list
        // so we don't add it twice
        if (addId.length > 0) {
            if (id == addId) {
                addId = "";
            }
        }

        // if the Id doesn't match
        // removeId, we preserve it.
        if (removeId.length > 0) {
            if (id == removeId) {
                id = "";
            }
        }

        if (id.length > 0) {
            result = doAddId(result, id);
        }
    }

    // if addId was not removed
    // we add it.
    if (addId != "") {
        result = doAddId(result, addId);
    }

    return result;
}

// Reads the current collapse list and adds or
// removes an ID to/from it.
function modifyCollapseState(addid, removeid)
{
    var ids = loadExpandState();

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

    ids = processCollapsedIds(ids, addid, removeid, false, false);

    if (ids != "") {
        saveExpandState(ids);
    } else {
        eraseExpandState();
    }
}

// Depending on visibility, removes or adds
// an ID to the collaps list.
function saveVisibilityState(id, visible)
{
    if (visible) {
        modifyCollapseState("", id);
    } else {
        modifyCollapseState(id, "");
    }
}

// Restores the collaps states of all
// stored elements.
function loadCollapseStates()
{
    var ids = loadExpandState();

    if (ids != null) {
        processCollapsedIds(ids, "", "", true, false);
    }
}

// this is the initial state the sections
// are displayed in.
var currentSectionStateExpanded = true;

// toggles the expand state of all sections
// identified by "ids" and updates the link
// text and link image.
function ToggleAllElements(ids, linkTextID, imgID, collapseAllText, expandAllText)
{
    var link = document.getElementById(linkTextID);
    var img = document.getElementById(imgID);

    if (ids != null) {
        processCollapsedIds(ids, "", "", currentSectionStateExpanded, !currentSectionStateExpanded);
        currentSectionStateExpanded = !currentSectionStateExpanded;
    }

    if (link != null) {
        if (currentSectionStateExpanded) {
            link.innerHTML = collapseAllText;
        } else {
            link.innerHTML = expandAllText;
        }
    }

    if (img != null) {
        if (currentSectionStateExpanded) {
            setNewImageSource(img, "btn_collapse_2.gif");
        } else {
            setNewImageSource(img, "btn_expand_2.gif");
        }
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////
// Dynamic Index Display
          

// trims search text and converts to uppercase
function IndexPrepareSearchText(text)
{
  text = text.replace( /^\s+/g, "" );// strip leading
  text = text.replace( /\s+$/g, "" );// strip trailing
  text = text.toUpperCase();
  return text;
}

function IndexMatchesEntry(entry, text)
{
    if ((entry[0].indexOf(text) >= 0) || (entry[1].indexOf(text) >= 0)) {
        return true;
    } else {
        return false;
    }
}

function GetQuote()
{
    return unescape("%22");
}

function IndexPrintEntry(text, url, divclass)
{
    var result = "";
    var target = "";

    result = "<div class=" + GetQuote() + divclass + GetQuote() + ">";

    if (url.length > 0) {
        if (target.length > 0) {
            result = result + "<a href=" + GetQuote() + url + GetQuote() + " target=" + GetQuote() + target + GetQuote() + ">";
        } else {
            result = result + "<a href=" + GetQuote() + url + GetQuote() + ">";
        }
    }

    result = result + text;

    if (url.length > 0) {
        result = result + "</a>";
    }

    result = result + "</div>";

    return result;
}

function IndexGetEntry(lastentry, entry, classmain, classsub)
{
    var result = "";

    var printmainentry = true;
    var printsubentry = false;
    var urlmainentry = "";
    var urlsubentry = "";

    if (entry[1].length > 0) {
        printsubentry = true;

        if (lastentry != null) {
            if (lastentry[0] == entry[0]) {
                printmainentry = false;
            }
        }
    }

    if ((printmainentry) && (!printsubentry)) {
        urlmainentry = entry[2];
    }

    if (printsubentry) {
        urlsubentry = entry[2];
    }

    if (printmainentry) {
        result = result + IndexPrintEntry(entry[3], urlmainentry, classmain);
    }
    if (printsubentry) {
        result = result + IndexPrintEntry(entry[4], urlsubentry, classsub);
    }

    return result;
}

var searchTimer = null;
var currentSearchText = "";
var searchDynamicDivID = "";
var searchResultDivID = "";
var searchClassMainEntry = "";
var searchClassSubEntry = "";

function IndexClearSearchTimer()
{
    if (searchTimer != null) {
       clearTimeout(searchTimer);
       searchTimer = null;
    }

    return true;
}

function IndexUnescape()
{
    var entry, k, i;
    for(k = 0; k < theIndex.length; k++) {
        entry = theIndex[k];

        for(i = 0; i < 5; i++) {
            entry[i] = unescape(entry[i]);
        }
    }
}

function DoIndexSearch()
{
    var dynamicdiv, resultdiv;
    var entry, lastentry, cnt, k, searchtext;
    var outputHTML = "";

    IndexClearSearchTimer();

    dynamicdiv = document.getElementById(searchDynamicDivID);
    resultdiv = document.getElementById(searchResultDivID);

    if ((dynamicdiv != null) && (resultdiv != null)) {
        cnt = 0;
        searchtext = IndexPrepareSearchText(currentSearchText);

        if (searchtext.length > 0) {
            IndexFill();
            IndexUnescape();

            lastentry = null;

            for(k = 0; k < theIndex.length; k++) {
                entry = theIndex[k];

                if (IndexMatchesEntry(entry, searchtext)) {
                    outputHTML = outputHTML + IndexGetEntry(lastentry, entry, searchClassMainEntry, searchClassSubEntry);

                    lastentry = entry;
                    cnt++;
                }
            }
        }

        if (cnt > 0) {
            resultdiv.innerHTML = outputHTML;
            dynamicdiv.style.display = '';
        } else {
            dynamicdiv.style.display = 'none';
        }
    }

    return true;
}

// instant index search invoked by pressing the search button
function IndexSearch(text, dynamicdivid, resultdivid, classmain, classsub)
{
    currentSearchText = text;
    searchDynamicDivID = dynamicdivid;
    searchResultDivID = resultdivid;
    searchClassMainEntry = classmain;
    searchClassSubEntry = classsub;

    DoIndexSearch();
}

// delayed index search invoked when entering text in the search field.
function IndexDelaySearch(text, dynamicdivid, resultdivid, classmain, classsub)
{
    if (text != currentSearchText) {
        IndexClearSearchTimer();

        currentSearchText = text;
        searchDynamicDivID = dynamicdivid;
        searchResultDivID = resultdivid;
        searchClassMainEntry = classmain;
        searchClassSubEntry = classsub;

        searchTimer = setTimeout("DoIndexSearch();", 500);
    }

    return true;
}


///////////////////////////////////////////////////////////////////////////////////////////////
// event handlers

// Process key input
function ieKey()
{
    if (window.event.keyCode == 27) {
        closePopup();
        doSetupFixedHeader();
        onResizeWindow();
    }
}

// Called when the brower window resizes
function onResizeWindow()
{
    doSetupFixedHeader();  //resize the scroll area
    return;
}

function fixMoniker()
{
    var curURL = document.location + ".";
    var pos = curURL.indexOf("mk:@MSITStore");
    if( pos == 0 ) {
        alert("old URL: " + curURL);
        curURL = "ms-its:" + curURL.substring(14,curURL.length-1);
        alert("replacing URL with: " + curURL);
        document.location.replace(curURL);
        return false;
    } else {
        return true;
    }
}

//fixMoniker();

// Initialize the Header
function onBodyLoad()
{
    doSetupFixedHeader();
    document.onkeypress = ieKey;
    window.onresize = onResizeWindow;

    if (navigator.family == 'ie4') {
        window.onbeforeprint = doBeforePrinting;
        window.onafterprint = reloadPage;
    }

    // if we use persistence we
    // load the settings now
    if (usePersistence) {
        loadPersistentData();
        window.onunload = onUnloadWindow;
    }

    // restore collapsed sections
    loadCollapseStates();

    // restore tabbed section selections
    restoreTabbedSectionStates();
}

// used to save settings to the persistent
// storage if we use it.
function onUnloadWindow()
{
    if (usePersistence) {
        savePersistentData();
    }
    return;
}

// called if we're using framesets in
function onBodyLoadEx(framesetfile, targetframe, topicfile)
{
    loadFrameSetOrTitle(framesetfile, targetframe, topicfile);
    onBodyLoad();
    synchTOC(topicfile);
    return true;
}

// Process mouse down events, close open popups
// and realign the fixed header area.
function onBodyMouseDown()
{
    closePopup();
    doSetupFixedHeader();
}

// Opens the big version of an image in a secondary window
function openBigImage(image)
{
    window.open(image, "_blank", "toolbar=no,status=no,menubar=no,resizable=yes");
    return true;
}

function openExternalLink(href)
{
    window.open(href, "_blank", "");
    return true;
}

function switchImage(img, src)
{
    setNewImageSource(img, src);
    return true;
}

// opens a mail window and fills the
// address, subject and body
function sendFeedback(mailto, subject, body)
{
    var href = "mailto:" + mailto + "?subject=" + subject + "&body=" + body;
    window.open(href, "_top");
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// tabbed section

function addTabbedSectionId(tabidlist, tabsetid)
{
    if (tabidlist == null) {
        return tabsetid;
    } else {
        var result = tabidlist;
        var addId = true;
        var tabsetids = tabidlist.split(",");
        for(var i=0; i < tabsetids.length; i++) {
            var ts = tabsetids[i];

            if (ts == tabsetid) {
                addId = false;
                break;
            }
        }
        if (addId) {
            if (result = "")
                result = tabsetid;
            else
                result = tabsetid + "," + result;
        }

        return result;
    }
}

function storeTabbedSectionState(tabsetid, selectedIdx)
{
    var tabsetids = readCookie(tabbedSectionCookieName);
    tabsetids = addTabbedSectionId(tabsetids, tabsetid);
    createCookie(tabbedSectionCookieName, tabsetids, 14);

    var cookieName = tabbedSectionCookieName + tabsetid;
    var idx = selectedIdx + "";
    createCookie(cookieName, idx, 14);
}

function restoreTabbedSectionState(tabsetid)
{
    var cookieName = tabbedSectionCookieName + tabsetid;
    var selectedTab = readCookie(cookieName);
    if (selectedTab != null) {
        var idx = parseInt(selectedTab, 10);

        doSwitchTabs(tabsetid, idx, -1, false);
    }
}

function restoreTabbedSectionStates()
{
    var tabidlist = readCookie(tabbedSectionCookieName);
    if (tabidlist != null) {
        var ids = tabidlist.split(",");
        for(var i=0; i < ids.length; i++) {
            restoreTabbedSectionState(ids[i]);
        }
    }
}

function setTabSelectionState(tabSetId, index, maxIdx, selected)
{
    var result = false;

    var tabid = "tab" + tabSetId + "_" + index;
    var divid = "div" + tabSetId + "_" + index;

    var tab = document.getElementById(tabid);
    var div = document.getElementById(divid);

    if ((tab != null) && (div != null)) {
        var elementIdx = 0;
        if (index > 0) {
            if (index == maxIdx) {
                elementIdx = 4;
            } else {
                elementIdx = 2;
            }
        }

        if (selected) {
            tab.className = tabbedSectionElementClassNames[elementIdx];
            div.style.display = "";
        } else {
            tab.className = tabbedSectionElementClassNames[elementIdx+1];
            div.style.display = "none";
        }

        result = true;
    }

    return result;
}

function doSwitchTabs(tabSetId, selectedIndex, tabCount, storeState)
{
    var foundSelected = false;
    var maxIdx = tabCount-1;
    var realMaxIdx = -1;
    var i = 0;
    while ((i <= maxIdx) || (maxIdx < 0)) {
        if (setTabSelectionState(tabSetId, i, maxIdx, (i == selectedIndex))) {
            realMaxIdx = i;
            if (i == selectedIndex) {
                foundSelected = true;
            }

            i++;
        } else {
            break;
        }
    }

    if (realMaxIdx > -1) {
        // if we didn't find the selected
        // tab (can happend when restoring)
        // we select the first
        if (!foundSelected) {
            setTabSelectionState(tabSetId, 0, maxIdx, true);
        }
        // When we're restoring redo the last tab so it gets the
        // correct class applied.
        if (maxIdx < 0) {
            setTabSelectionState(tabSetId, realMaxIdx, realMaxIdx, selectedIndex == realMaxIdx);
        }
    }

    if (storeState) {
        storeTabbedSectionState(tabSetId, selectedIndex);
    }
}

function switchTabs(tabSetId, selectedIndex, tabCount)
{
    doSwitchTabs(tabSetId, selectedIndex, tabCount, true);
}

///////////////////////////////////////////////////////////////////////////////////////////////
// Browser detection
// Source: http://devedge.netscape.com/toolbox/examples/2002/xb/ua/

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Netscape code.
 *
 * The Initial Developer of the Original Code is
 * Netscape Corporation.
 * Portions created by the Initial Developer are Copyright (C) 2001
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s): Bob Clary <bclary@netscape.com>
 *
 * ***** END LICENSE BLOCK ***** */

function xbDetectBrowser()
{
  var oldOnError = window.onerror;
  var element = null;

  window.onerror = null;
  
  // work around bug in xpcdom Mozilla 0.9.1
  window.saveNavigator = window.navigator;

  navigator.OS    = '';
  navigator.version  = parseFloat(navigator.appVersion);
  navigator.org    = '';
  navigator.family  = '';

  var platform;
  if (typeof(window.navigator.platform) != 'undefined')
  {
    platform = window.navigator.platform.toLowerCase();
    if (platform.indexOf('win') != -1)
      navigator.OS = 'win';
    else if (platform.indexOf('mac') != -1)
      navigator.OS = 'mac';
    else if (platform.indexOf('unix') != -1 || platform.indexOf('linux') != -1 || platform.indexOf('sun') != -1)
      navigator.OS = 'nix';
  }

  var i = 0;
  var ua = window.navigator.userAgent.toLowerCase();
  
  if (ua.indexOf('opera') != -1)
  {
    i = ua.indexOf('opera');
    navigator.family  = 'opera';
    navigator.org    = 'opera';
    navigator.version  = parseFloat('0' + ua.substr(i+6), 10);
  }
  else if ((i = ua.indexOf('msie')) != -1)
  {
    navigator.org    = 'microsoft';
    navigator.version  = parseFloat('0' + ua.substr(i+5), 10);
    
    if (navigator.version < 4)
      navigator.family = 'ie3';
    else
      navigator.family = 'ie4';
  }
  else if (ua.indexOf('gecko') != -1)
  {
    navigator.family = 'gecko';
    var rvStart = ua.indexOf('rv:');
    var rvEnd   = ua.indexOf(')', rvStart);
    var rv      = ua.substring(rvStart+3, rvEnd);
    var rvParts = rv.split('.');
    var rvValue = 0;
    var exp     = 1;

    for (var i2 = 0; i2 < rvParts.length; i2++)
    {
      var val = parseInt(rvParts[i2]);
      rvValue += val / exp;
      exp *= 100;
    }
    navigator.version = rvValue;

    if (ua.indexOf('netscape') != -1)
      navigator.org = 'netscape';
    else if (ua.indexOf('compuserve') != -1)
      navigator.org = 'compuserve';
    else
      navigator.org = 'mozilla';
  }
  else if ((ua.indexOf('mozilla') !=-1) && (ua.indexOf('spoofer')==-1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera')==-1)&& (ua.indexOf('webtv')==-1) && (ua.indexOf('hotjava')==-1))
  {
    var is_major = parseFloat(navigator.appVersion);
    
    if (is_major < 4)
      navigator.version = is_major;
    else
    {
      i = ua.lastIndexOf('/');
      navigator.version = parseFloat('0' + ua.substr(i+1), 10);
    }
    navigator.org = 'netscape';
    navigator.family = 'nn' + parseInt(navigator.appVersion);
  }
  else if ((i = ua.indexOf('aol')) != -1 )
  {
    // aol
    navigator.family  = 'aol';
    navigator.org    = 'aol';
    navigator.version  = parseFloat('0' + ua.substr(i+4), 10);
  }
  else if ((i = ua.indexOf('hotjava')) != -1 )
  {
    // hotjava
    navigator.family  = 'hotjava';
    navigator.org    = 'sun';
    navigator.version  = parseFloat(navigator.appVersion);
  }

  window.onerror = oldOnError;
}

xbDetectBrowser();

