var log4javascript;(function(){function ff(){return function(){}}function copy(obj,props){for(var i in props){obj[i]=props[i]}}var f=ff();var Logger=ff();copy(Logger.prototype,{addAppender:f,removeAppender:f,removeAllAppenders:f,log:f,setLevel:f,getLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f});var getLogger=function(){return new Logger()};log4javascript={isStub:true,version:"dummy",logLog:{setQuietMode:f,setAlertAllErrors:f,debug:f,warn:f,error:f},addErrorListener:f,removeErrorListener:f,setEnabled:f,setShowStackTraces:f,isEnabled:f,evalInScope:f,getLogger:getLogger,getDefaultLogger:getLogger,getNullLogger:getLogger,Level:ff(),LoggingEvent:ff(),Layout:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Layout.prototype={defaults:{},format:f,ignoresThrowable:f,getContentType:f,allowBatching:f,getDataValues:f,setKeys:f,setCustomField:f,hasCustomFields:f};log4javascript.SimpleLayout=ff();log4javascript.SimpleLayout.prototype=new log4javascript.Layout();log4javascript.XmlLayout=ff();log4javascript.XmlLayout.prototype=new log4javascript.Layout();log4javascript.XmlLayout.prototype.escapeCdata=f;log4javascript.JsonLayout=ff();log4javascript.JsonLayout.prototype=new log4javascript.Layout();copy(log4javascript.JsonLayout.prototype,{setReadable:f,isReadable:f});log4javascript.HttpPostDataLayout=ff();log4javascript.HttpPostDataLayout.prototype=new log4javascript.Layout();log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.NullLayout=ff();log4javascript.NullLayout.prototype=new log4javascript.Layout();log4javascript.Appender=ff();log4javascript.Appender.prototype={layout:new log4javascript.PatternLayout(),threshold:log4javascript.Level.ALL,doAppend:f,append:f,setLayout:f,getLayout:f,setThreshold:f,getThreshold:f,toString:f};log4javascript.AlertAppender=ff();log4javascript.AlertAppender.prototype=new log4javascript.Appender();log4javascript.ArrayAppender=ff();log4javascript.ArrayAppender.prototype=new log4javascript.Appender();log4javascript.AjaxAppender=ff();log4javascript.AjaxAppender.prototype=new log4javascript.Appender();copy(log4javascript.AjaxAppender.prototype,{isTimed:f,setTimed:f,getTimerInterval:f,setTimerInterval:f,isWaitForResponse:f,setWaitForResponse:f,getBatchSize:f,setBatchSize:f,setRequestSuccessCallback:f,setFailCallback:f,sendAll:f,defaults:{requestSuccessCallback:null,failCallback:null}});function ConsoleAppender(){}ConsoleAppender.prototype=new log4javascript.Appender();copy(ConsoleAppender.prototype,{create:f,isNewestMessageAtTop:f,setNewestMessageAtTop:f,isScrollToLatestMessage:f,setScrollToLatestMessage:f,getWidth:f,setWidth:f,getHeight:f,setHeight:f,getMaxMessages:f,setMaxMessages:f});log4javascript.InPageAppender=ff();log4javascript.InPageAppender.prototype=new ConsoleAppender();copy(log4javascript.InPageAppender.prototype,{isInitiallyMinimized:f,setInitiallyMinimized:f,hide:f,show:f,isVisible:f,close:f,defaults:{layout:new log4javascript.PatternLayout(),maxMessages:null}});log4javascript.InlineAppender=log4javascript.InPageAppender;log4javascript.PopUpAppender=ff();log4javascript.PopUpAppender.prototype=new ConsoleAppender();copy(log4javascript.PopUpAppender.prototype,{isUseOldPopUp:f,setUseOldPopUp:f,isComplainAboutPopUpBlocking:f,setComplainAboutPopUpBlocking:f,isFocusPopUp:f,setFocusPopUp:f,isReopenWhenClosed:f,setReopenWhenClosed:f,close:f,defaults:{layout:new log4javascript.PatternLayout(),maxMessages:null}});log4javascript.BrowserConsoleAppender=ff();log4javascript.BrowserConsoleAppender.prototype=new log4javascript.Appender()})();var log4javascript_dummy=log4javascript;
/* OnlineOpinion (S3tS,1424b) */
/* This product and other products of OpinionLab, Inc. are protected by U.S. Patent No. 6606581, 6421724, 6785717 B1 and other patents pending. */
var timePass = "";
var custom_var,_sp='%3A\\/\\/',_rp='%3A//',_poE=0.0, _poX=0.0,_sH=screen.height,_d=document,_w=window,_ht=escape(_w.location.href),_hr=_d.referrer,_tm=(new Date()).getTime(),_kp=0,_sW=screen.width;_d.onkeypress=_fK;function _fK(_e){if(!_e)_e=_w.event;var _k=(typeof _e.which=='number')?_e.which:_e.keyCode;if((_kp==15&&_k==12))_w.open('https://dashboard.opinionlab.com/pv_controlboard.html?url='+_fC(_ht),'PageViewer','height=529,width=705,screenX='+((_sW-705)/2)+',screenY='+((_sH-529)/2)+',top='+((_sH-529)/2)+',left='+((_sW-705)/2)+',status=yes,toolbar=no,menubar=no,location=no,resizable=yes');_kp=_k};function _fC(_u){_aT=_sp+',\\/,\\.,-,_,'+_rp+',%2F,%2E,%2D,%5F';_aA=_aT.split(',');for(i=0;i<5;i++){eval('_u=_u.replace(/'+_aA[i]+'/g,_aA[i+5])')}return _u};function O_LC(){_w.open('https://secure.opinionlab.com/ccc01/comment_card.asp?time1='+_tm+'&time2='+(new Date()).getTime()+'&prev='+_fC(escape(_hr))+'&referer='+_fC(_ht)+'&height='+_sH+'&width='+_sW+'&custom_var='+custom_var,'comments','width=535,height=192,screenX='+((_sW-535)/2)+',screenY='+((_sH-192)/2)+',top='+((_sH-192)/2)+',left='+((_sW-535)/2)+',resizable=yes,copyhistory=yes,scrollbars=no')};function _fPe(){if(Math.random()>=1.0-_poE){O_LC();_poX=0.0}};function _fPx(){if(Math.random()>=1.0-_poX)O_LC()};window.onunload=_fPx;function O_GoT(_p){_d.write('<a href=\'javascript:O_LC()\' class=\'lightGreySmall\'>'+_p+'</a>');_fPe()}

function goOP() {
    _fPe();
    custom_var=s.pageName;
    O_LC();
}/*
* Browser detection, taken from http://www.quirksmode.org/js/detect.html
*/
var BrowserDetect = {
    init: function () {
        this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
        this.version = this.searchVersion(navigator.userAgent)
            || this.searchVersion(navigator.appVersion)
            || "an unknown version";
        this.OS = this.searchString(this.dataOS) || "an unknown OS";
    },
    searchString: function (data) {
        for (var i=0;i<data.length;i++) {
            var dataString = data[i].string;
            var dataProp = data[i].prop;
            this.versionSearchString = data[i].versionSearch || data[i].identity;
            if (dataString) {
                if (dataString.indexOf(data[i].subString) != -1)
                    return data[i].identity;
            }
            else if (dataProp)
                return data[i].identity;
        }
    },
    searchVersion: function (dataString) {
        var index = dataString.indexOf(this.versionSearchString);
        if (index == -1) return;
        return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
    },
    dataBrowser: [
        {   string: navigator.userAgent,
            subString: "OmniWeb",
            versionSearch: "OmniWeb/",
            identity: "OmniWeb"
        },
        {
            string: navigator.vendor,
            subString: "Apple",
            identity: "Safari"
        },
        {
            prop: window.opera,
            identity: "Opera"
        },
        {
            string: navigator.vendor,
            subString: "iCab",
            identity: "iCab"
        },
        {
            string: navigator.vendor,
            subString: "KDE",
            identity: "Konqueror"
        },
        {
            string: navigator.userAgent,
            subString: "Firefox",
            identity: "Firefox"
        },
        {
            string: navigator.vendor,
            subString: "Camino",
            identity: "Camino"
        },
        {       // for newer Netscapes (6+)
            string: navigator.userAgent,
            subString: "Netscape",
            identity: "Netscape"
        },
        {
            string: navigator.userAgent,
            subString: "MSIE",
            identity: "Explorer",
            versionSearch: "MSIE"
        },
        {
            string: navigator.userAgent,
            subString: "Gecko",
            identity: "Mozilla",
            versionSearch: "rv"
        },
        {       // for older Netscapes (4-)
            string: navigator.userAgent,
            subString: "Mozilla",
            identity: "Netscape",
            versionSearch: "Mozilla"
        }
    ],
    dataOS : [
        {
            string: navigator.platform,
            subString: "Win",
            identity: "Windows"
        },
        {
            string: navigator.platform,
            subString: "Mac",
            identity: "Mac"
        },
        {
            string: navigator.platform,
            subString: "Linux",
            identity: "Linux"
        }
    ],
    getWindowSize: function () {
        var myWidth = 0, myHeight = 0;
        if( typeof( window.innerWidth ) == 'number' ) {
            //Non-IE
            myWidth = window.innerWidth;
            myHeight = window.innerHeight;
        } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
            //IE 6+ in 'standards compliant mode'
            myWidth = document.documentElement.clientWidth;
            myHeight = document.documentElement.clientHeight;
        } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
            //IE 4 compatible
            myWidth = document.body.clientWidth;
            myHeight = document.body.clientHeight;
        }
        var size=new Object();
        size.width=myWidth;
        size.height=myHeight;
        return size;
    }

};
BrowserDetect.init();/*
Copyright (c) 2009, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.8.0r4
*/
/**
 * The Browser History Manager provides the ability to use the back/forward
 * navigation buttons in a DHTML application. It also allows a DHTML
 * application to be bookmarked in a specific state.
 *
 * This library requires the following static markup:
 *
 * &lt;iframe id="yui-history-iframe" src="path-to-real-asset-in-same-domain"&gt;&lt;/iframe&gt;
 * &lt;input id="yui-history-field" type="hidden"&gt;
 *
 * @module history
 * @requires yahoo,event
 * @namespace YAHOO.util
 * @title Browser History Manager
 */

/**
 * The History class provides the ability to use the back/forward navigation
 * buttons in a DHTML application. It also allows a DHTML application to
 * be bookmarked in a specific state.
 *
 * @class History
 * @constructor
 */
YAHOO.util.History = (function () {

    /**
     * Our hidden IFrame used to store the browsing history.
     *
     * @property _histFrame
     * @type HTMLIFrameElement
     * @default null
     * @private
     */
    var _histFrame = null;

    /**
     * INPUT field (with type="hidden" or type="text") or TEXTAREA.
     * This field keeps the value of the initial state, current state
     * the list of all states across pages within a single browser session.
     *
     * @property _stateField
     * @type HTMLInputElement|HTMLTextAreaElement
     * @default null
     * @private
     */
    var _stateField = null;

    /**
     * Flag used to tell whether YAHOO.util.History.initialize has been called.
     *
     * @property _initialized
     * @type boolean
     * @default false
     * @private
     */
    var _initialized = false;

    /**
     * List of registered modules.
     *
     * @property _modules
     * @type array
     * @default []
     * @private
     */
    var _modules = [];

    /**
     * List of fully qualified states. This is used only by Safari.
     *
     * @property _fqstates
     * @type array
     * @default []
     * @private
     */
    var _fqstates = [];

    /**
     * location.hash is a bit buggy on Opera. I have seen instances where
     * navigating the history using the back/forward buttons, and hence
     * changing the URL, would not change location.hash. That's ok, the
     * implementation of an equivalent is trivial.
     *
     * @method _getHash
     * @return {string} The hash portion of the document's location
     * @private
     */
    function _getHash() {
        var i, href;
        href = top.location.href;
        i = href.indexOf("#");
        return i >= 0 ? href.substr(i + 1) : null;
    }

    /**
     * Stores all the registered modules' initial state and current state.
     * On Safari, we also store all the fully qualified states visited by
     * the application within a single browser session. The storage takes
     * place in the form field specified during initialization.
     *
     * @method _storeStates
     * @private
     */
    function _storeStates() {

        var moduleName, moduleObj, initialStates = [], currentStates = [];

        for (moduleName in _modules) {
            if (YAHOO.lang.hasOwnProperty(_modules, moduleName)) {
                moduleObj = _modules[moduleName];
                initialStates.push(moduleName + "=" + moduleObj.initialState);
                currentStates.push(moduleName + "=" + moduleObj.currentState);
            }
        }

        _stateField.value = initialStates.join("&") + "|" + currentStates.join("&");

        if (YAHOO.env.ua.webkit) {
            _stateField.value += "|" + _fqstates.join(",");
        }
    }

    /**
     * Sets the new currentState attribute of all modules depending on the new
     * fully qualified state. Also notifies the modules which current state has
     * changed.
     *
     * @method _handleFQStateChange
     * @param {string} fqstate Fully qualified state
     * @private
     */
    function _handleFQStateChange(fqstate) {

        var i, len, moduleName, moduleObj, modules, states, tokens, currentState;

        if (!fqstate) {
            // Notifies all modules
            for (moduleName in _modules) {
                if (YAHOO.lang.hasOwnProperty(_modules, moduleName)) {
                    moduleObj = _modules[moduleName];
                    moduleObj.currentState = moduleObj.initialState;
                    moduleObj.onStateChange(unescape(moduleObj.currentState));
                }
            }
            return;
        }

        modules = [];
        states = fqstate.split("&");
        for (i = 0, len = states.length; i < len; i++) {
            tokens = states[i].split("=");
            if (tokens.length === 2) {
                moduleName = tokens[0];
                currentState = tokens[1];
                modules[moduleName] = currentState;
            }
        }

        for (moduleName in _modules) {
            if (YAHOO.lang.hasOwnProperty(_modules, moduleName)) {
                moduleObj = _modules[moduleName];
                currentState = modules[moduleName];
                if (!currentState || moduleObj.currentState !== currentState) {
                    moduleObj.currentState = currentState || moduleObj.initialState;
                    moduleObj.onStateChange(unescape(moduleObj.currentState));
                }
            }
        }
    }

    /**
     * Update the IFrame with our new state.
     *
     * @method _updateIFrame
     * @private
     * @return {boolean} true if successful. false otherwise.
     */
    function _updateIFrame (fqstate) {

        var html, doc;

        html = '<html><body><div id="state">' + fqstate + '</div></body></html>';

        try {
            doc = _histFrame.contentWindow.document;
            doc.open();
            doc.write(html);
            doc.close();
            return true;
        } catch (e) {
            return false;
        }
    }

    /**
     * Periodically checks whether our internal IFrame is ready to be used.
     *
     * @method _checkIframeLoaded
     * @private
     */
    function _checkIframeLoaded() {

        var doc, elem, fqstate, hash;

        if (!_histFrame.contentWindow || !_histFrame.contentWindow.document) {
            // Check again in 10 msec...
            setTimeout(_checkIframeLoaded, 10);
            return;
        }

        // Start the thread that will have the responsibility to
        // periodically check whether a navigate operation has been
        // requested on the main window. This will happen when
        // YAHOO.util.History.navigate has been called or after
        // the user has hit the back/forward button.

        doc = _histFrame.contentWindow.document;
        elem = doc.getElementById("state");
        // We must use innerText, and not innerHTML because our string contains
        // the "&" character (which would end up being escaped as "&amp;") and
        // the string comparison would fail...
        fqstate = elem ? elem.innerText : null;

        hash = _getHash();

        setInterval(function () {

            var newfqstate, states, moduleName, moduleObj, newHash, historyLength;

            doc = _histFrame.contentWindow.document;
            elem = doc.getElementById("state");
            // See my comment above about using innerText instead of innerHTML...
            newfqstate = elem ? elem.innerText : null;

            newHash = _getHash();

            if (newfqstate !== fqstate) {

                fqstate = newfqstate;
                _handleFQStateChange(fqstate);

                if (!fqstate) {
                    states = [];
                    for (moduleName in _modules) {
                        if (YAHOO.lang.hasOwnProperty(_modules, moduleName)) {
                            moduleObj = _modules[moduleName];
                            states.push(moduleName + "=" + moduleObj.initialState);
                        }
                    }
                    newHash = states.join("&");
                } else {
                    newHash = fqstate;
                }

                // Allow the state to be bookmarked by setting the top window's
                // URL fragment identifier. Note that here, we are on IE, and
                // IE does not touch the browser history when setting the hash
                // (unlike all the other browsers). I used to write:
                //     top.location.replace( "#" + hash );
                // but this had a side effect when the page was not the top frame.
                top.location.hash = newHash;
                hash = newHash;

                _storeStates();

            } else if (newHash !== hash) {

                // The hash has changed. The user might have clicked on a link,
                // or modified the URL directly, or opened the same application
                // bookmarked in a specific state using a bookmark. However, we
                // know the hash change was not caused by a hit on the back or
                // forward buttons, or by a call to navigate() (because it would
                // have been handled above) We must handle these cases, which is
                // why we also need to keep track of hash changes on IE!

                // Note that IE6 has some major issues with this kind of user
                // interaction (the history stack gets completely messed up)
                // but it seems to work fine on IE7.

                hash = newHash;

                // Now, store a new history entry. The following will cause the
                // code above to execute, doing all the dirty work for us...
                _updateIFrame(newHash);
            }

        }, 50);

        _initialized = true;
        YAHOO.util.History.onLoadEvent.fire();
    }

    /**
     * Finish up the initialization of the Browser History Manager.
     *
     * @method _initialize
     * @private
     */
    function _initialize() {

        var i, len, parts, tokens, moduleName, moduleObj, initialStates, initialState, currentStates, currentState, counter, hash;

        // Decode the content of our storage field...
        parts = _stateField.value.split("|");

        if (parts.length > 1) {

            initialStates = parts[0].split("&");
            for (i = 0, len = initialStates.length; i < len; i++) {
                tokens = initialStates[i].split("=");
                if (tokens.length === 2) {
                    moduleName = tokens[0];
                    initialState = tokens[1];
                    moduleObj = _modules[moduleName];
                    if (moduleObj) {
                        moduleObj.initialState = initialState;
                    }
                }
            }

            currentStates = parts[1].split("&");
            for (i = 0, len = currentStates.length; i < len; i++) {
                tokens = currentStates[i].split("=");
                if (tokens.length >= 2) {
                    moduleName = tokens[0];
                    currentState = tokens[1];
                    moduleObj = _modules[moduleName];
                    if (moduleObj) {
                        moduleObj.currentState = currentState;
                    }
                }
            }
        }

        if (parts.length > 2) {
            _fqstates = parts[2].split(",");
        }

        if (YAHOO.env.ua.ie) {

            if (typeof document.documentMode === "undefined" || document.documentMode < 8) {

                // IE < 8 or IE8 in quirks mode or IE7 standards mode
                _checkIframeLoaded();

            } else {

                // IE8 in IE8 standards mode
                YAHOO.util.Event.on(top, "hashchange",
                    function () {
                        var hash = _getHash();
                        _handleFQStateChange(hash);
                        _storeStates();
                    });

                _initialized = true;
                YAHOO.util.History.onLoadEvent.fire();

            }

        } else {

            // Start the thread that will have the responsibility to
            // periodically check whether a navigate operation has been
            // requested on the main window. This will happen when
            // YAHOO.util.History.navigate has been called or after
            // the user has hit the back/forward button.

            // On Safari 1.x and 2.0, the only way to catch a back/forward
            // operation is to watch history.length... We basically exploit
            // what I consider to be a bug (history.length is not supposed
            // to change when going back/forward in the history...) This is
            // why, in the following thread, we first compare the hash,
            // because the hash thing will be fixed in the next major
            // version of Safari. So even if they fix the history.length
            // bug, all this will still work!
            counter = history.length;

            // On Gecko and Opera, we just need to watch the hash...
            hash = _getHash();

            setInterval(function () {

                var state, newHash, newCounter;

                newHash = _getHash();
                newCounter = history.length;
                if (newHash !== hash) {
                    hash = newHash;
                    counter = newCounter;
                    _handleFQStateChange(hash);
                    _storeStates();
                } else if (newCounter !== counter && YAHOO.env.ua.webkit) {
                    hash = newHash;
                    counter = newCounter;
                    state = _fqstates[counter - 1];
                    _handleFQStateChange(state);
                    _storeStates();
                }

            }, 50);

            _initialized = true;
            YAHOO.util.History.onLoadEvent.fire();
        }
    }

    return {

        /**
         * Fired when the Browser History Manager is ready. If you subscribe to
         * this event after the Browser History Manager has been initialized,
         * it will not fire. Therefore, it is recommended to use the onReady
         * method instead.
         *
         * @event onLoadEvent
         * @see onReady
         */
        onLoadEvent: new YAHOO.util.CustomEvent("onLoad"),

        /**
         * Executes the supplied callback when the Browser History Manager is
         * ready. This will execute immediately if called after the Browser
         * History Manager onLoad event has fired.
         *
         * @method onReady
         * @param {function} fn what to execute when the Browser History Manager is ready.
         * @param {object} obj an optional object to be passed back as a parameter to fn.
         * @param {boolean|object} overrideContext If true, the obj passed in becomes fn's execution scope.
         * @see onLoadEvent
         */
        onReady: function (fn, obj, overrideContext) {

            if (_initialized) {

                setTimeout(function () {
                    var ctx = window;
                    if (overrideContext) {
                        if (overrideContext === true) {
                            ctx = obj;
                        } else {
                            ctx = overrideContext;
                        }
                    }
                    fn.call(ctx, "onLoad", [], obj);
                }, 0);

            } else {

                YAHOO.util.History.onLoadEvent.subscribe(fn, obj, overrideContext);

            }
        },

        /**
         * Registers a new module.
         *
         * @method register
         * @param {string} module Non-empty string uniquely identifying the
         *     module you wish to register.
         * @param {string} initialState The initial state of the specified
         *     module corresponding to its earliest history entry.
         * @param {function} onStateChange Callback called when the
         *     state of the specified module has changed.
         * @param {object} obj An arbitrary object that will be passed as a
         *     parameter to the handler.
         * @param {boolean} overrideContext If true, the obj passed in becomes the
         *     execution scope of the listener.
         */
        register: function (module, initialState, onStateChange, obj, overrideContext) {

            var scope, wrappedFn;

            if (typeof module !== "string" || YAHOO.lang.trim(module) === "" ||
                typeof initialState !== "string" ||
                typeof onStateChange !== "function") {
                throw new Error("Missing or invalid argument");
            }

            if (_modules[module]) {
                // Here, we used to throw an exception. However, users have
                // complained about this behavior, so we now just return.
                return;
            }

            // Note: A module CANNOT be registered after calling
            // YAHOO.util.History.initialize. Indeed, we set the initial state
            // of each registered module in YAHOO.util.History.initialize.
            // If you could register a module after initializing the Browser
            // History Manager, you would not read the correct state using
            // YAHOO.util.History.getCurrentState when coming back to the
            // page using the back button.
            if (_initialized) {
                throw new Error("All modules must be registered before calling YAHOO.util.History.initialize");
            }

            // Make sure the strings passed in do not contain our separators "," and "|"
            module = escape(module);
            initialState = escape(initialState);

            // If the user chooses to override the scope, we use the
            // custom object passed in as the execution scope.
            scope = null;
            if (overrideContext === true) {
                scope = obj;
            } else {
                scope = overrideContext;
            }

            wrappedFn = function (state) {
                return onStateChange.call(scope, state, obj);
            };

            _modules[module] = {
                name: module,
                initialState: initialState,
                currentState: initialState,
                onStateChange: wrappedFn
            };
        },

        /**
         * Initializes the Browser History Manager. Call this method
         * from a script block located right after the opening body tag.
         *
         * @method initialize
         * @param {string|HTML Element} stateField <input type="hidden"> used
         *     to store application states. Must be in the static markup.
         * @param {string|HTML Element} histFrame IFrame used to store
         *     the history (only required on Internet Explorer)
         * @public
         */
        initialize: function (stateField, histFrame) {

            if (_initialized) {
                // The browser history manager has already been initialized.
                return;
            }

            if (YAHOO.env.ua.opera && typeof history.navigationMode !== "undefined") {
                // Disable Opera's fast back/forward navigation mode and puts
                // it in compatible mode. This makes anchor-based history
                // navigation work after the page has been navigated away
                // from and re-activated, at the cost of slowing down
                // back/forward navigation to and from that page.
                history.navigationMode = "compatible";
            }

            if (typeof stateField === "string") {
                stateField = document.getElementById(stateField);
            }

            if (!stateField ||
                stateField.tagName.toUpperCase() !== "TEXTAREA" &&
                (stateField.tagName.toUpperCase() !== "INPUT" ||
                 stateField.type !== "hidden" &&
                 stateField.type !== "text")) {
                throw new Error("Missing or invalid argument");
            }

            _stateField = stateField;

            // IE < 8 or IE8 in quirks mode or IE7 standards mode
            if (YAHOO.env.ua.ie && (typeof document.documentMode === "undefined" || document.documentMode < 8)) {

                if (typeof histFrame === "string") {
                    histFrame = document.getElementById(histFrame);
                }

                if (!histFrame || histFrame.tagName.toUpperCase() !== "IFRAME") {
                    throw new Error("Missing or invalid argument");
                }

                _histFrame = histFrame;
            }

            // Note that the event utility MUST be included inline in the page.
            // If it gets loaded later (which you may want to do to improve the
            // loading speed of your site), the onDOMReady event never fires,
            // and the history library never gets fully initialized.
            YAHOO.util.Event.onDOMReady(_initialize);
        },

        /**
         * Call this method when you want to store a new entry in the browser's history.
         *
         * @method navigate
         * @param {string} module Non-empty string representing your module.
         * @param {string} state String representing the new state of the specified module.
         * @return {boolean} Indicates whether the new state was successfully added to the history.
         * @public
         */
        navigate: function (module, state) {

            var states;

            if (typeof module !== "string" || typeof state !== "string") {
                throw new Error("Missing or invalid argument");
            }

            states = {};
            states[module] = state;

            return YAHOO.util.History.multiNavigate(states);
        },

        /**
         * Call this method when you want to store a new entry in the browser's history.
         *
         * @method multiNavigate
         * @param {object} states Associative array of module-state pairs to set simultaneously.
         * @return {boolean} Indicates whether the new state was successfully added to the history.
         * @public
         */
        multiNavigate: function (states) {

            var currentStates, moduleName, moduleObj, currentState, fqstate;

            if (typeof states !== "object") {
                throw new Error("Missing or invalid argument");
            }

            if (!_initialized) {
                throw new Error("The Browser History Manager is not initialized");
            }

            for (moduleName in states) {
                if (!_modules[moduleName]) {
                    throw new Error("The following module has not been registered: " + moduleName);
                }
            }

            // Generate our new full state string mod1=xxx&mod2=yyy
            currentStates = [];

            for (moduleName in _modules) {
                if (YAHOO.lang.hasOwnProperty(_modules, moduleName)) {
                    moduleObj = _modules[moduleName];
                    if (YAHOO.lang.hasOwnProperty(states, moduleName)) {
                        currentState = states[unescape(moduleName)];
                    } else {
                        currentState = unescape(moduleObj.currentState);
                    }

                    // Make sure the strings passed in do not contain our separators "," and "|"
                    moduleName = escape(moduleName);
                    currentState = escape(currentState);

                    currentStates.push(moduleName + "=" + currentState);
                }
            }

            fqstate = currentStates.join("&");

            if (YAHOO.env.ua.ie && (typeof document.documentMode === "undefined" || document.documentMode < 8)) {

                return _updateIFrame(fqstate);

            } else {

                // Known bug: On Safari 1.x and 2.0, if you have tab browsing
                // enabled, Safari will show an endless loading icon in the
                // tab. This has apparently been fixed in recent WebKit builds.
                // One work around found by Dav Glass is to submit a form that
                // points to the same document. This indeed works on Safari 1.x
                // and 2.0 but creates bigger problems on WebKit. So for now,
                // we'll consider this an acceptable bug, and hope that Apple
                // comes out with their next version of Safari very soon.
                top.location.hash = fqstate;
                if (YAHOO.env.ua.webkit) {
                    // The following two lines are only useful for Safari 1.x
                    // and 2.0. Recent nightly builds of WebKit do not require
                    // that, but unfortunately, it is not easy to differentiate
                    // between the two. Once Safari 2.0 departs the A-grade
                    // list, we can remove the following two lines...
                    _fqstates[history.length] = fqstate;
                    _storeStates();
                }

                return true;

            }
        },

        /**
         * Returns the current state of the specified module.
         *
         * @method getCurrentState
         * @param {string} module Non-empty string representing your module.
         * @return {string} The current state of the specified module.
         * @public
         */
        getCurrentState: function (module) {

            var moduleObj;

            if (typeof module !== "string") {
                throw new Error("Missing or invalid argument");
            }

            if (!_initialized) {
                throw new Error("The Browser History Manager is not initialized");
            }

            moduleObj = _modules[module];
            if (!moduleObj) {
                throw new Error("No such registered module: " + module);
            }

            return unescape(moduleObj.currentState);
        },

        /**
         * Returns the state of a module according to the URL fragment
         * identifier. This method is useful to initialize your modules
         * if your application was bookmarked from a particular state.
         *
         * @method getBookmarkedState
         * @param {string} module Non-empty string representing your module.
         * @return {string} The bookmarked state of the specified module.
         * @public
         */
        getBookmarkedState: function (module) {

            var i, len, idx, hash, states, tokens, moduleName;

            if (typeof module !== "string") {
                throw new Error("Missing or invalid argument");
            }

            // Use location.href instead of location.hash which is already
            // URL-decoded, which creates problems if the state value
            // contained special characters...
            idx = top.location.href.indexOf("#");
            if (idx >= 0) {
                hash = top.location.href.substr(idx + 1);
                states = hash.split("&");
                for (i = 0, len = states.length; i < len; i++) {
                    tokens = states[i].split("=");
                    if (tokens.length === 2) {
                        moduleName = tokens[0];
                        if (moduleName === module) {
                            return unescape(tokens[1]);
                        }
                    }
                }
            }

            return null;
        },

        /**
         * Returns the value of the specified query string parameter.
         * This method is not used internally by the Browser History Manager.
         * However, it is provided here as a helper since many applications
         * using the Browser History Manager will want to read the value of
         * url parameters to initialize themselves.
         *
         * @method getQueryStringParameter
         * @param {string} paramName Name of the parameter we want to look up.
         * @param {string} queryString Optional URL to look at. If not specified,
         *     this method uses the URL in the address bar.
         * @return {string} The value of the specified parameter, or null.
         * @public
         */
        getQueryStringParameter: function (paramName, url) {

            var i, len, idx, queryString, params, tokens;

            url = url || top.location.href;

            idx = url.indexOf("?");
            queryString = idx >= 0 ? url.substr(idx + 1) : url;

            // Remove the hash if any
            idx = queryString.lastIndexOf("#");
            queryString = idx >= 0 ? queryString.substr(0, idx) : queryString;

            params = queryString.split("&");

            for (i = 0, len = params.length; i < len; i++) {
                tokens = params[i].split("=");
                if (tokens.length >= 2) {
                    if (tokens[0] === paramName) {
                        return unescape(tokens[1]);
                    }
                }
            }

            return null;
        }

    };

})();
YAHOO.register("history", YAHOO.util.History, {version: "2.8.0r4", build: "2449"});
/*
Copyright (c) 2009, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.8.0r4
*/
/**
 * The Connection Manager provides a simplified interface to the XMLHttpRequest
 * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
 * interactive states and server response, returning the results to a pre-defined
 * callback you create.
 *
 * @namespace YAHOO.util
 * @module connection
 * @requires yahoo
 * @requires event
 */

/**
 * The Connection Manager singleton provides methods for creating and managing
 * asynchronous transactions.
 *
 * @class Connect
 */

YAHOO.util.Connect =
{
  /**
   * @description Array of MSFT ActiveX ids for XMLHttpRequest.
   * @property _msxml_progid
   * @private
   * @static
   * @type array
   */
	_msxml_progid:[
		'Microsoft.XMLHTTP',
		'MSXML2.XMLHTTP.3.0',
		'MSXML2.XMLHTTP'
		],

  /**
   * @description Object literal of HTTP header(s)
   * @property _http_header
   * @private
   * @static
   * @type object
   */
	_http_headers:{},

  /**
   * @description Determines if HTTP headers are set.
   * @property _has_http_headers
   * @private
   * @static
   * @type boolean
   */
	_has_http_headers:false,

 /**
  * @description Determines if a default header of
  * Content-Type of 'application/x-www-form-urlencoded'
  * will be added to any client HTTP headers sent for POST
  * transactions.
  * @property _use_default_post_header
  * @private
  * @static
  * @type boolean
  */
    _use_default_post_header:true,

 /**
  * @description The default header used for POST transactions.
  * @property _default_post_header
  * @private
  * @static
  * @type boolean
  */
    _default_post_header:'application/x-www-form-urlencoded; charset=UTF-8',

 /**
  * @description The default header used for transactions involving the
  * use of HTML forms.
  * @property _default_form_header
  * @private
  * @static
  * @type boolean
  */
    _default_form_header:'application/x-www-form-urlencoded',

 /**
  * @description Determines if a default header of
  * 'X-Requested-With: XMLHttpRequest'
  * will be added to each transaction.
  * @property _use_default_xhr_header
  * @private
  * @static
  * @type boolean
  */
    _use_default_xhr_header:true,

 /**
  * @description The default header value for the label
  * "X-Requested-With".  This is sent with each
  * transaction, by default, to identify the
  * request as being made by YUI Connection Manager.
  * @property _default_xhr_header
  * @private
  * @static
  * @type boolean
  */
    _default_xhr_header:'XMLHttpRequest',

 /**
  * @description Determines if custom, default headers
  * are set for each transaction.
  * @property _has_default_header
  * @private
  * @static
  * @type boolean
  */
    _has_default_headers:true,

 /**
  * @description Determines if custom, default headers
  * are set for each transaction.
  * @property _has_default_header
  * @private
  * @static
  * @type boolean
  */
    _default_headers:{},

 /**
  * @description Collection of polling references to the polling mechanism in handleReadyState.
  * @property _poll
  * @private
  * @static
  * @type object
  */
    _poll:{},

 /**
  * @description Queue of timeout values for each transaction callback with a defined timeout value.
  * @property _timeOut
  * @private
  * @static
  * @type object
  */
    _timeOut:{},

  /**
   * @description The polling frequency, in milliseconds, for HandleReadyState.
   * when attempting to determine a transaction's XHR readyState.
   * The default is 50 milliseconds.
   * @property _polling_interval
   * @private
   * @static
   * @type int
   */
     _polling_interval:50,

  /**
   * @description A transaction counter that increments the transaction id for each transaction.
   * @property _transaction_id
   * @private
   * @static
   * @type int
   */
     _transaction_id:0,

  /**
   * @description Custom event that fires at the start of a transaction
   * @property startEvent
   * @private
   * @static
   * @type CustomEvent
   */
	startEvent: new YAHOO.util.CustomEvent('start'),

  /**
   * @description Custom event that fires when a transaction response has completed.
   * @property completeEvent
   * @private
   * @static
   * @type CustomEvent
   */
	completeEvent: new YAHOO.util.CustomEvent('complete'),

  /**
   * @description Custom event that fires when handleTransactionResponse() determines a
   * response in the HTTP 2xx range.
   * @property successEvent
   * @private
   * @static
   * @type CustomEvent
   */
	successEvent: new YAHOO.util.CustomEvent('success'),

  /**
   * @description Custom event that fires when handleTransactionResponse() determines a
   * response in the HTTP 4xx/5xx range.
   * @property failureEvent
   * @private
   * @static
   * @type CustomEvent
   */
	failureEvent: new YAHOO.util.CustomEvent('failure'),

  /**
   * @description Custom event that fires when a transaction is successfully aborted.
   * @property abortEvent
   * @private
   * @static
   * @type CustomEvent
   */
	abortEvent: new YAHOO.util.CustomEvent('abort'),

  /**
   * @description A reference table that maps callback custom events members to its specific
   * event name.
   * @property _customEvents
   * @private
   * @static
   * @type object
   */
	_customEvents:
	{
		onStart:['startEvent', 'start'],
		onComplete:['completeEvent', 'complete'],
		onSuccess:['successEvent', 'success'],
		onFailure:['failureEvent', 'failure'],
		onUpload:['uploadEvent', 'upload'],
		onAbort:['abortEvent', 'abort']
	},

  /**
   * @description Member to add an ActiveX id to the existing xml_progid array.
   * In the event(unlikely) a new ActiveX id is introduced, it can be added
   * without internal code modifications.
   * @method setProgId
   * @public
   * @static
   * @param {string} id The ActiveX id to be added to initialize the XHR object.
   * @return void
   */
	setProgId:function(id)
	{
		this._msxml_progid.unshift(id);
	},

  /**
   * @description Member to override the default POST header.
   * @method setDefaultPostHeader
   * @public
   * @static
   * @param {boolean} b Set and use default header - true or false .
   * @return void
   */
	setDefaultPostHeader:function(b)
	{
		if(typeof b == 'string'){
			this._default_post_header = b;
		}
		else if(typeof b == 'boolean'){
			this._use_default_post_header = b;
		}
	},

  /**
   * @description Member to override the default transaction header..
   * @method setDefaultXhrHeader
   * @public
   * @static
   * @param {boolean} b Set and use default header - true or false .
   * @return void
   */
	setDefaultXhrHeader:function(b)
	{
		if(typeof b == 'string'){
			this._default_xhr_header = b;
		}
		else{
			this._use_default_xhr_header = b;
		}
	},

  /**
   * @description Member to modify the default polling interval.
   * @method setPollingInterval
   * @public
   * @static
   * @param {int} i The polling interval in milliseconds.
   * @return void
   */
	setPollingInterval:function(i)
	{
		if(typeof i == 'number' && isFinite(i)){
			this._polling_interval = i;
		}
	},

  /**
   * @description Instantiates a XMLHttpRequest object and returns an object with two properties:
   * the XMLHttpRequest instance and the transaction id.
   * @method createXhrObject
   * @private
   * @static
   * @param {int} transactionId Property containing the transaction id for this transaction.
   * @return object
   */
	createXhrObject:function(transactionId)
	{
		var obj,http,i;
		try
		{
			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
			http = new XMLHttpRequest();
			//  Object literal with http and tId properties
			obj = { conn:http, tId:transactionId, xhr: true };
		}
		catch(e)
		{
			for(i=0; i<this._msxml_progid.length; ++i){
				try
				{
					// Instantiates XMLHttpRequest for IE and assign to http
					http = new ActiveXObject(this._msxml_progid[i]);
					//  Object literal with conn and tId properties
					obj = { conn:http, tId:transactionId, xhr: true };
					break;
				}
				catch(e1){}
			}
		}
		finally
		{
			return obj;
		}
	},

  /**
   * @description This method is called by asyncRequest to create a
   * valid connection object for the transaction.  It also passes a
   * transaction id and increments the transaction id counter.
   * @method getConnectionObject
   * @private
   * @static
   * @return {object}
   */
	getConnectionObject:function(t)
	{
		var o, tId = this._transaction_id;

		try
		{
			if(!t){
				o = this.createXhrObject(tId);
			}
			else{
				o = {tId:tId};
				if(t==='xdr'){
					o.conn = this._transport;
					o.xdr = true;
				}
				else if(t==='upload'){
					o.upload = true;
				}
			}

			if(o){
				this._transaction_id++;
			}
		}
		catch(e){}
		return o;
	},

  /**
   * @description Method for initiating an asynchronous request via the XHR object.
   * @method asyncRequest
   * @public
   * @static
   * @param {string} method HTTP transaction method
   * @param {string} uri Fully qualified path of resource
   * @param {callback} callback User-defined callback function or object
   * @param {string} postData POST body
   * @return {object} Returns the connection object
   */
	asyncRequest:function(method, uri, callback, postData)
	{
		var o,t,args = (callback && callback.argument)?callback.argument:null;

		if(this._isFileUpload){
			t = 'upload';
		}
		else if(callback.xdr){
			t = 'xdr';
		}

		o = this.getConnectionObject(t);
		if(!o){
			return null;
		}
		else{

			// Intialize any transaction-specific custom events, if provided.
			if(callback && callback.customevents){
				this.initCustomEvents(o, callback);
			}

			if(this._isFormSubmit){
				if(this._isFileUpload){
					this.uploadFile(o, callback, uri, postData);
					return o;
				}

				// If the specified HTTP method is GET, setForm() will return an
				// encoded string that is concatenated to the uri to
				// create a querystring.
				if(method.toUpperCase() == 'GET'){
					if(this._sFormData.length !== 0){
						// If the URI already contains a querystring, append an ampersand
						// and then concatenate _sFormData to the URI.
						uri += ((uri.indexOf('?') == -1)?'?':'&') + this._sFormData;
					}
				}
				else if(method.toUpperCase() == 'POST'){
					// If POST data exist in addition to the HTML form data,
					// it will be concatenated to the form data.
					postData = postData?this._sFormData + "&" + postData:this._sFormData;
				}
			}

			if(method.toUpperCase() == 'GET' && (callback && callback.cache === false)){
				// If callback.cache is defined and set to false, a
				// timestamp value will be added to the querystring.
				uri += ((uri.indexOf('?') == -1)?'?':'&') + "rnd=" + new Date().valueOf().toString();
			}

			// Each transaction will automatically include a custom header of
			// "X-Requested-With: XMLHttpRequest" to identify the request as
			// having originated from Connection Manager.
			if(this._use_default_xhr_header){
				if(!this._default_headers['X-Requested-With']){
					this.initHeader('X-Requested-With', this._default_xhr_header, true);
				}
			}

			//If the transaction method is POST and the POST header value is set to true
			//or a custom value, initalize the Content-Type header to this value.
			if((method.toUpperCase() === 'POST' && this._use_default_post_header) && this._isFormSubmit === false){
				this.initHeader('Content-Type', this._default_post_header);
			}

			if(o.xdr){
				this.xdr(o, method, uri, callback, postData);
				return o;
			}

			o.conn.open(method, uri, true);
			//Initialize all default and custom HTTP headers,
			if(this._has_default_headers || this._has_http_headers){
				this.setHeader(o);
			}

			this.handleReadyState(o, callback);
			o.conn.send(postData || '');

			// Reset the HTML form data and state properties as
			// soon as the data are submitted.
			if(this._isFormSubmit === true){
				this.resetFormState();
			}

			// Fire global custom event -- startEvent
			this.startEvent.fire(o, args);

			if(o.startEvent){
				// Fire transaction custom event -- startEvent
				o.startEvent.fire(o, args);
			}

			return o;
		}
	},

  /**
   * @description This method creates and subscribes custom events,
   * specific to each transaction
   * @method initCustomEvents
   * @private
   * @static
   * @param {object} o The connection object
   * @param {callback} callback The user-defined callback object
   * @return {void}
   */
	initCustomEvents:function(o, callback)
	{
		var prop;
		// Enumerate through callback.customevents members and bind/subscribe
		// events that match in the _customEvents table.
		for(prop in callback.customevents){
			if(this._customEvents[prop][0]){
				// Create the custom event
				o[this._customEvents[prop][0]] = new YAHOO.util.CustomEvent(this._customEvents[prop][1], (callback.scope)?callback.scope:null);

				// Subscribe the custom event
				o[this._customEvents[prop][0]].subscribe(callback.customevents[prop]);
			}
		}
	},

  /**
   * @description This method serves as a timer that polls the XHR object's readyState
   * property during a transaction, instead of binding a callback to the
   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
   * will process the response, and the timer will be cleared.
   * @method handleReadyState
   * @private
   * @static
   * @param {object} o The connection object
   * @param {callback} callback The user-defined callback object
   * @return {void}
   */

    handleReadyState:function(o, callback)

    {
		var oConn = this,
			args = (callback && callback.argument)?callback.argument:null;

		if(callback && callback.timeout){
			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
		}

		this._poll[o.tId] = window.setInterval(
			function(){
				if(o.conn && o.conn.readyState === 4){

					// Clear the polling interval for the transaction
					// and remove the reference from _poll.
					window.clearInterval(oConn._poll[o.tId]);
					delete oConn._poll[o.tId];

					if(callback && callback.timeout){
						window.clearTimeout(oConn._timeOut[o.tId]);
						delete oConn._timeOut[o.tId];
					}

					// Fire global custom event -- completeEvent
					oConn.completeEvent.fire(o, args);

					if(o.completeEvent){
						// Fire transaction custom event -- completeEvent
						o.completeEvent.fire(o, args);
					}

					oConn.handleTransactionResponse(o, callback);
				}
			}
		,this._polling_interval);
    },

  /**
   * @description This method attempts to interpret the server response and
   * determine whether the transaction was successful, or if an error or
   * exception was encountered.
   * @method handleTransactionResponse
   * @private
   * @static
   * @param {object} o The connection object
   * @param {object} callback The user-defined callback object
   * @param {boolean} isAbort Determines if the transaction was terminated via abort().
   * @return {void}
   */
    handleTransactionResponse:function(o, callback, isAbort)
    {
		var httpStatus, responseObject,
			args = (callback && callback.argument)?callback.argument:null,
			xdrS = (o.r && o.r.statusText === 'xdr:success')?true:false,
			xdrF = (o.r && o.r.statusText === 'xdr:failure')?true:false,
			xdrA = isAbort;

		try
		{
			if((o.conn.status !== undefined && o.conn.status !== 0) || xdrS){
				// XDR requests will not have HTTP status defined. The
				// statusText property will define the response status
				// set by the Flash transport.
				httpStatus = o.conn.status;
			}
			else if(xdrF && !xdrA){
				// Set XDR transaction failure to a status of 0, which
				// resolves as an HTTP failure, instead of an exception.
				httpStatus = 0;
			}
			else{
				httpStatus = 13030;
			}
		}
		catch(e){

			 // 13030 is a custom code to indicate the condition -- in Mozilla/FF --
			 // when the XHR object's status and statusText properties are
			 // unavailable, and a query attempt throws an exception.
			httpStatus = 13030;
		}

		if((httpStatus >= 200 && httpStatus < 300) || httpStatus === 1223 || xdrS){
			responseObject = o.xdr ? o.r : this.createResponseObject(o, args);
			if(callback && callback.success){
				if(!callback.scope){
					callback.success(responseObject);
				}
				else{
					// If a scope property is defined, the callback will be fired from
					// the context of the object.
					callback.success.apply(callback.scope, [responseObject]);
				}
			}

			// Fire global custom event -- successEvent
			this.successEvent.fire(responseObject);

			if(o.successEvent){
				// Fire transaction custom event -- successEvent
				o.successEvent.fire(responseObject);
			}
		}
		else{
			switch(httpStatus){
				// The following cases are wininet.dll error codes that may be encountered.
				case 12002: // Server timeout
				case 12029: // 12029 to 12031 correspond to dropped connections.
				case 12030:
				case 12031:
				case 12152: // Connection closed by server.
				case 13030: // See above comments for variable status.
					// XDR transactions will not resolve to this case, since the
					// response object is already built in the xdr response.
					responseObject = this.createExceptionObject(o.tId, args, (isAbort?isAbort:false));
					if(callback && callback.failure){
						if(!callback.scope){
							callback.failure(responseObject);
						}
						else{
							callback.failure.apply(callback.scope, [responseObject]);
						}
					}

					break;
				default:
					responseObject = (o.xdr) ? o.response : this.createResponseObject(o, args);
					if(callback && callback.failure){
						if(!callback.scope){
							callback.failure(responseObject);
						}
						else{
							callback.failure.apply(callback.scope, [responseObject]);
						}
					}
			}

			// Fire global custom event -- failureEvent
			this.failureEvent.fire(responseObject);

			if(o.failureEvent){
				// Fire transaction custom event -- failureEvent
				o.failureEvent.fire(responseObject);
			}

		}

		this.releaseObject(o);
		responseObject = null;
    },

  /**
   * @description This method evaluates the server response, creates and returns the results via
   * its properties.  Success and failure cases will differ in the response
   * object's property values.
   * @method createResponseObject
   * @private
   * @static
   * @param {object} o The connection object
   * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
   * @return {object}
   */
    createResponseObject:function(o, callbackArg)
    {
		var obj = {}, headerObj = {},
			i, headerStr, header, delimitPos;

		try
		{
			headerStr = o.conn.getAllResponseHeaders();
			header = headerStr.split('\n');
			for(i=0; i<header.length; i++){
				delimitPos = header[i].indexOf(':');
				if(delimitPos != -1){
					headerObj[header[i].substring(0,delimitPos)] = YAHOO.lang.trim(header[i].substring(delimitPos+2));
				}
			}
		}
		catch(e){}

		obj.tId = o.tId;
		// Normalize IE's response to HTTP 204 when Win error 1223.
		obj.status = (o.conn.status == 1223)?204:o.conn.status;
		// Normalize IE's statusText to "No Content" instead of "Unknown".
		obj.statusText = (o.conn.status == 1223)?"No Content":o.conn.statusText;
		obj.getResponseHeader = headerObj;
		obj.getAllResponseHeaders = headerStr;
		obj.responseText = o.conn.responseText;
		obj.responseXML = o.conn.responseXML;

		if(callbackArg){
			obj.argument = callbackArg;
		}

		return obj;
    },

  /**
   * @description If a transaction cannot be completed due to dropped or closed connections,
   * there may be not be enough information to build a full response object.
   * The failure callback will be fired and this specific condition can be identified
   * by a status property value of 0.
   *
   * If an abort was successful, the status property will report a value of -1.
   *
   * @method createExceptionObject
   * @private
   * @static
   * @param {int} tId The Transaction Id
   * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
   * @param {boolean} isAbort Determines if the exception case is caused by a transaction abort
   * @return {object}
   */
    createExceptionObject:function(tId, callbackArg, isAbort)
    {
		var COMM_CODE = 0,
			COMM_ERROR = 'communication failure',
			ABORT_CODE = -1,
			ABORT_ERROR = 'transaction aborted',
			obj = {};

		obj.tId = tId;
		if(isAbort){
			obj.status = ABORT_CODE;
			obj.statusText = ABORT_ERROR;
		}
		else{
			obj.status = COMM_CODE;
			obj.statusText = COMM_ERROR;
		}

		if(callbackArg){
			obj.argument = callbackArg;
		}

		return obj;
    },

  /**
   * @description Method that initializes the custom HTTP headers for the each transaction.
   * @method initHeader
   * @public
   * @static
   * @param {string} label The HTTP header label
   * @param {string} value The HTTP header value
   * @param {string} isDefault Determines if the specific header is a default header
   * automatically sent with each transaction.
   * @return {void}
   */
	initHeader:function(label, value, isDefault)
	{
		var headerObj = (isDefault)?this._default_headers:this._http_headers;

		headerObj[label] = value;
		if(isDefault){
			this._has_default_headers = true;
		}
		else{
			this._has_http_headers = true;
		}
	},


  /**
   * @description Accessor that sets the HTTP headers for each transaction.
   * @method setHeader
   * @private
   * @static
   * @param {object} o The connection object for the transaction.
   * @return {void}
   */
	setHeader:function(o)
	{
		var prop;
		if(this._has_default_headers){
			for(prop in this._default_headers){
				if(YAHOO.lang.hasOwnProperty(this._default_headers, prop)){
					o.conn.setRequestHeader(prop, this._default_headers[prop]);
				}
			}
		}

		if(this._has_http_headers){
			for(prop in this._http_headers){
				if(YAHOO.lang.hasOwnProperty(this._http_headers, prop)){
					o.conn.setRequestHeader(prop, this._http_headers[prop]);
				}
			}

			this._http_headers = {};
			this._has_http_headers = false;
		}
	},

  /**
   * @description Resets the default HTTP headers object
   * @method resetDefaultHeaders
   * @public
   * @static
   * @return {void}
   */
	resetDefaultHeaders:function(){
		this._default_headers = {};
		this._has_default_headers = false;
	},

  /**
   * @description Method to terminate a transaction, if it has not reached readyState 4.
   * @method abort
   * @public
   * @static
   * @param {object} o The connection object returned by asyncRequest.
   * @param {object} callback  User-defined callback object.
   * @param {string} isTimeout boolean to indicate if abort resulted from a callback timeout.
   * @return {boolean}
   */
	abort:function(o, callback, isTimeout)
	{
		var abortStatus,
			args = (callback && callback.argument)?callback.argument:null;
			o = o || {};

		if(o.conn){
			if(o.xhr){
				if(this.isCallInProgress(o)){
					// Issue abort request
					o.conn.abort();

					window.clearInterval(this._poll[o.tId]);
					delete this._poll[o.tId];

					if(isTimeout){
						window.clearTimeout(this._timeOut[o.tId]);
						delete this._timeOut[o.tId];
					}

					abortStatus = true;
				}
			}
			else if(o.xdr){
				o.conn.abort(o.tId);
				abortStatus = true;
			}
		}
		else if(o.upload){
			var frameId = 'yuiIO' + o.tId;
			var io = document.getElementById(frameId);

			if(io){
				// Remove all listeners on the iframe prior to
				// its destruction.
				YAHOO.util.Event.removeListener(io, "load");
				// Destroy the iframe facilitating the transaction.
				document.body.removeChild(io);

				if(isTimeout){
					window.clearTimeout(this._timeOut[o.tId]);
					delete this._timeOut[o.tId];
				}

				abortStatus = true;
			}
		}
		else{
			abortStatus = false;
		}

		if(abortStatus === true){
			// Fire global custom event -- abortEvent
			this.abortEvent.fire(o, args);

			if(o.abortEvent){
				// Fire transaction custom event -- abortEvent
				o.abortEvent.fire(o, args);
			}

			this.handleTransactionResponse(o, callback, true);
		}

		return abortStatus;
	},

  /**
   * @description Determines if the transaction is still being processed.
   * @method isCallInProgress
   * @public
   * @static
   * @param {object} o The connection object returned by asyncRequest
   * @return {boolean}
   */
	isCallInProgress:function(o)
	{
		o = o || {};
		// if the XHR object assigned to the transaction has not been dereferenced,
		// then check its readyState status.  Otherwise, return false.
		if(o.xhr && o.conn){
			return o.conn.readyState !== 4 && o.conn.readyState !== 0;
		}
		else if(o.xdr && o.conn){
			return o.conn.isCallInProgress(o.tId);
		}
		else if(o.upload === true){
			return document.getElementById('yuiIO' + o.tId)?true:false;
		}
		else{
			return false;
		}
	},

  /**
   * @description Dereference the XHR instance and the connection object after the transaction is completed.
   * @method releaseObject
   * @private
   * @static
   * @param {object} o The connection object
   * @return {void}
   */
	releaseObject:function(o)
	{
		if(o && o.conn){
			//dereference the XHR instance.
			o.conn = null;


			//dereference the connection object.
			o = null;
		}
	}
};

/**
  * @for Connect
  */
(function() {
	var YCM = YAHOO.util.Connect, _fn = {};

   /**
    * @description This method creates and instantiates the Flash transport.
    * @method _swf
    * @private
    * @static
    * @param {string} URI to connection.swf.
    * @return {void}
    */
	function _swf(uri) {
		var o = '<object id="YUIConnectionSwf" type="application/x-shockwave-flash" data="' +
		        uri + '" width="0" height="0">' +
		     	'<param name="movie" value="' + uri + '">' +
                '<param name="allowScriptAccess" value="always">' +
		    	'</object>',
		    c = document.createElement('div');

		document.body.appendChild(c);
		c.innerHTML = o;
	}

   /**
    * @description This method calls the public method on the
    * Flash transport to start the XDR transaction.  It is analogous
    * to Connection Manager's asyncRequest method.
    * @method xdr
    * @private
    * @static
    * @param {object} The transaction object.
    * @param {string} HTTP request method.
    * @param {string} URI for the transaction.
    * @param {object} The transaction's callback object.
    * @param {object} The JSON object used as HTTP POST data.
    * @return {void}
    */
	function _xdr(o, m, u, c, d) {
		_fn[parseInt(o.tId)] = { 'o':o, 'c':c };
		if (d) {
			c.method = m;
			c.data = d;
		}

		o.conn.send(u, c, o.tId);
	}

   /**
    * @description This method instantiates the Flash transport and
    * establishes a static reference to it, used for all XDR requests.
    * @method transport
    * @public
    * @static
    * @param {string} URI to connection.swf.
    * @return {void}
    */
	function _init(uri) {
		_swf(uri);
		YCM._transport = document.getElementById('YUIConnectionSwf');
	}

	function _xdrReady() {
		YCM.xdrReadyEvent.fire();
	}

   /**
    * @description This method fires the global and transaction start
    * events.
    * @method _xdrStart
    * @private
    * @static
    * @param {object} The transaction object.
    * @param {string} The transaction's callback object.
    * @return {void}
    */
	function _xdrStart(o, cb) {
		if (o) {
			// Fire global custom event -- startEvent
			YCM.startEvent.fire(o, cb.argument);

			if(o.startEvent){
				// Fire transaction custom event -- startEvent
				o.startEvent.fire(o, cb.argument);
			}
		}
	}

   /**
    * @description This method is the initial response handler
    * for XDR transactions.  The Flash transport calls this
    * function and sends the response payload.
    * @method handleXdrResponse
    * @private
    * @static
    * @param {object} The response object sent from the Flash transport.
    * @return {void}
    */
	function _handleXdrResponse(r) {
		var o = _fn[r.tId].o,
			cb = _fn[r.tId].c;

		if (r.statusText === 'xdr:start') {
			_xdrStart(o, cb);
			return;
		}

		r.responseText = decodeURI(r.responseText);
		o.r = r;
		if (cb.argument) {
			o.r.argument = cb.argument;
		}

		this.handleTransactionResponse(o, cb, r.statusText === 'xdr:abort' ? true : false);
		delete _fn[r.tId];
	}

	// Bind the functions to Connection Manager as static fields.
	YCM.xdr = _xdr;
	YCM.swf = _swf;
	YCM.transport = _init;
	YCM.xdrReadyEvent = new YAHOO.util.CustomEvent('xdrReady');
	YCM.xdrReady = _xdrReady;
	YCM.handleXdrResponse = _handleXdrResponse;
})();

/**
  * @for Connect
  */
(function(){
	var YCM = YAHOO.util.Connect,
		YE = YAHOO.util.Event;
   /**
	* @description Property modified by setForm() to determine if the data
	* should be submitted as an HTML form.
	* @property _isFormSubmit
	* @private
	* @static
	* @type boolean
	*/
	YCM._isFormSubmit = false;

   /**
	* @description Property modified by setForm() to determine if a file(s)
	* upload is expected.
	* @property _isFileUpload
	* @private
	* @static
	* @type boolean
	*/
	YCM._isFileUpload = false;

   /**
	* @description Property modified by setForm() to set a reference to the HTML
	* form node if the desired action is file upload.
	* @property _formNode
	* @private
	* @static
	* @type object
	*/
	YCM._formNode = null;

   /**
	* @description Property modified by setForm() to set the HTML form data
	* for each transaction.
	* @property _sFormData
	* @private
	* @static
	* @type string
	*/
	YCM._sFormData = null;

   /**
	* @description Tracks the name-value pair of the "clicked" submit button if multiple submit
	* buttons are present in an HTML form; and, if YAHOO.util.Event is available.
	* @property _submitElementValue
	* @private
	* @static
	* @type string
	*/
	YCM._submitElementValue = null;

   /**
    * @description Custom event that fires when handleTransactionResponse() determines a
    * response in the HTTP 4xx/5xx range.
    * @property failureEvent
    * @private
    * @static
    * @type CustomEvent
    */
	YCM.uploadEvent = new YAHOO.util.CustomEvent('upload'),

   /**
	* @description Determines whether YAHOO.util.Event is available and returns true or false.
	* If true, an event listener is bound at the document level to trap click events that
	* resolve to a target type of "Submit".  This listener will enable setForm() to determine
	* the clicked "Submit" value in a multi-Submit button, HTML form.
	* @property _hasSubmitListener
	* @private
	* @static
	*/
	YCM._hasSubmitListener = function() {
		if(YE){
			YE.addListener(
				document,
				'click',
				function(e){
					var obj = YE.getTarget(e),
						name = obj.nodeName.toLowerCase();

					if((name === 'input' || name === 'button') && (obj.type && obj.type.toLowerCase() == 'submit')){
						YCM._submitElementValue = encodeURIComponent(obj.name) + "=" + encodeURIComponent(obj.value);
					}
				});
			return true;
		}
		return false;
	}();

  /**
   * @description This method assembles the form label and value pairs and
   * constructs an encoded string.
   * asyncRequest() will automatically initialize the transaction with a
   * a HTTP header Content-Type of application/x-www-form-urlencoded.
   * @method setForm
   * @public
   * @static
   * @param {string || object} form id or name attribute, or form object.
   * @param {boolean} optional enable file upload.
   * @param {boolean} optional enable file upload over SSL in IE only.
   * @return {string} string of the HTML form field name and value pairs..
   */
	function _setForm(formId, isUpload, secureUri)
	{
		var oForm, oElement, oName, oValue, oDisabled,
			hasSubmit = false,
			data = [], item = 0,
			i,len,j,jlen,opt;

		this.resetFormState();

		if(typeof formId == 'string'){
			// Determine if the argument is a form id or a form name.
			// Note form name usage is deprecated by supported
			// here for legacy reasons.
			oForm = (document.getElementById(formId) || document.forms[formId]);
		}
		else if(typeof formId == 'object'){
			// Treat argument as an HTML form object.
			oForm = formId;
		}
		else{
			return;
		}

		// If the isUpload argument is true, setForm will call createFrame to initialize
		// an iframe as the form target.
		//
		// The argument secureURI is also required by IE in SSL environments
		// where the secureURI string is a fully qualified HTTP path, used to set the source
		// of the iframe, to a stub resource in the same domain.
		if(isUpload){

			// Create iframe in preparation for file upload.
			this.createFrame(secureUri?secureUri:null);

			// Set form reference and file upload properties to true.
			this._isFormSubmit = true;
			this._isFileUpload = true;
			this._formNode = oForm;

			return;
		}

		// Iterate over the form elements collection to construct the
		// label-value pairs.
		for (i=0,len=oForm.elements.length; i<len; ++i){
			oElement  = oForm.elements[i];
			oDisabled = oElement.disabled;
			oName     = oElement.name;

			// Do not submit fields that are disabled or
			// do not have a name attribute value.
			if(!oDisabled && oName)
			{
				oName  = encodeURIComponent(oName)+'=';
				oValue = encodeURIComponent(oElement.value);

				switch(oElement.type)
				{
					// Safari, Opera, FF all default opt.value from .text if
					// value attribute not specified in markup
					case 'select-one':
						if (oElement.selectedIndex > -1) {
							opt = oElement.options[oElement.selectedIndex];
							data[item++] = oName + encodeURIComponent(
								(opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text);
						}
						break;
					case 'select-multiple':
						if (oElement.selectedIndex > -1) {
							for(j=oElement.selectedIndex, jlen=oElement.options.length; j<jlen; ++j){
								opt = oElement.options[j];
								if (opt.selected) {
									data[item++] = oName + encodeURIComponent(
										(opt.attributes.value && opt.attributes.value.specified) ? opt.value : opt.text);
								}
							}
						}
						break;
					case 'radio':
					case 'checkbox':
						if(oElement.checked){
							data[item++] = oName + oValue;
						}
						break;
					case 'file':
						// stub case as XMLHttpRequest will only send the file path as a string.
					case undefined:
						// stub case for fieldset element which returns undefined.
					case 'reset':
						// stub case for input type reset button.
					case 'button':
						// stub case for input type button elements.
						break;
					case 'submit':
						if(hasSubmit === false){
							if(this._hasSubmitListener && this._submitElementValue){
								data[item++] = this._submitElementValue;
							}
							hasSubmit = true;
						}
						break;
					default:
						data[item++] = oName + oValue;
				}
			}
		}

		this._isFormSubmit = true;
		this._sFormData = data.join('&');


		this.initHeader('Content-Type', this._default_form_header);

		return this._sFormData;
	}

   /**
    * @description Resets HTML form properties when an HTML form or HTML form
    * with file upload transaction is sent.
    * @method resetFormState
    * @private
    * @static
    * @return {void}
    */
	function _resetFormState(){
		this._isFormSubmit = false;
		this._isFileUpload = false;
		this._formNode = null;
		this._sFormData = "";
	}


   /**
    * @description Creates an iframe to be used for form file uploads.  It is remove from the
    * document upon completion of the upload transaction.
    * @method createFrame
    * @private
    * @static
    * @param {string} optional qualified path of iframe resource for SSL in IE.
    * @return {void}
    */
	function _createFrame(secureUri){

		// IE does not allow the setting of id and name attributes as object
		// properties via createElement().  A different iframe creation
		// pattern is required for IE.
		var frameId = 'yuiIO' + this._transaction_id,
			io;
		if(YAHOO.env.ua.ie){
			io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');

			// IE will throw a security exception in an SSL environment if the
			// iframe source is undefined.
			if(typeof secureUri == 'boolean'){
				io.src = 'javascript:false';
			}
		}
		else{
			io = document.createElement('iframe');
			io.id = frameId;
			io.name = frameId;
		}

		io.style.position = 'absolute';
		io.style.top = '-1000px';
		io.style.left = '-1000px';

		document.body.appendChild(io);
	}

   /**
    * @description Parses the POST data and creates hidden form elements
    * for each key-value, and appends them to the HTML form object.
    * @method appendPostData
    * @private
    * @static
    * @param {string} postData The HTTP POST data
    * @return {array} formElements Collection of hidden fields.
    */
	function _appendPostData(postData){
		var formElements = [],
			postMessage = postData.split('&'),
			i, delimitPos;

		for(i=0; i < postMessage.length; i++){
			delimitPos = postMessage[i].indexOf('=');
			if(delimitPos != -1){
				formElements[i] = document.createElement('input');
				formElements[i].type = 'hidden';
				formElements[i].name = decodeURIComponent(postMessage[i].substring(0,delimitPos));
				formElements[i].value = decodeURIComponent(postMessage[i].substring(delimitPos+1));
				this._formNode.appendChild(formElements[i]);
			}
		}

		return formElements;
	}

   /**
    * @description Uploads HTML form, inclusive of files/attachments, using the
    * iframe created in createFrame to facilitate the transaction.
    * @method uploadFile
    * @private
    * @static
    * @param {int} id The transaction id.
    * @param {object} callback User-defined callback object.
    * @param {string} uri Fully qualified path of resource.
    * @param {string} postData POST data to be submitted in addition to HTML form.
    * @return {void}
    */
	function _uploadFile(o, callback, uri, postData){
		// Each iframe has an id prefix of "yuiIO" followed
		// by the unique transaction id.
		var frameId = 'yuiIO' + o.tId,
		    uploadEncoding = 'multipart/form-data',
		    io = document.getElementById(frameId),
		    ie8 = (document.documentMode && document.documentMode === 8) ? true : false,
		    oConn = this,
			args = (callback && callback.argument)?callback.argument:null,
            oElements,i,prop,obj, rawFormAttributes, uploadCallback;

		// Track original HTML form attribute values.
		rawFormAttributes = {
			action:this._formNode.getAttribute('action'),
			method:this._formNode.getAttribute('method'),
			target:this._formNode.getAttribute('target')
		};

		// Initialize the HTML form properties in case they are
		// not defined in the HTML form.
		this._formNode.setAttribute('action', uri);
		this._formNode.setAttribute('method', 'POST');
		this._formNode.setAttribute('target', frameId);

		if(YAHOO.env.ua.ie && !ie8){
			// IE does not respect property enctype for HTML forms.
			// Instead it uses the property - "encoding".
			this._formNode.setAttribute('encoding', uploadEncoding);
		}
		else{
			this._formNode.setAttribute('enctype', uploadEncoding);
		}

		if(postData){
			oElements = this.appendPostData(postData);
		}

		// Start file upload.
		this._formNode.submit();

		// Fire global custom event -- startEvent
		this.startEvent.fire(o, args);

		if(o.startEvent){
			// Fire transaction custom event -- startEvent
			o.startEvent.fire(o, args);
		}

		// Start polling if a callback is present and the timeout
		// property has been defined.
		if(callback && callback.timeout){
			this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
		}

		// Remove HTML elements created by appendPostData
		if(oElements && oElements.length > 0){
			for(i=0; i < oElements.length; i++){
				this._formNode.removeChild(oElements[i]);
			}
		}

		// Restore HTML form attributes to their original
		// values prior to file upload.
		for(prop in rawFormAttributes){
			if(YAHOO.lang.hasOwnProperty(rawFormAttributes, prop)){
				if(rawFormAttributes[prop]){
					this._formNode.setAttribute(prop, rawFormAttributes[prop]);
				}
				else{
					this._formNode.removeAttribute(prop);
				}
			}
		}

		// Reset HTML form state properties.
		this.resetFormState();

		// Create the upload callback handler that fires when the iframe
		// receives the load event.  Subsequently, the event handler is detached
		// and the iframe removed from the document.
		uploadCallback = function() {
			if(callback && callback.timeout){
				window.clearTimeout(oConn._timeOut[o.tId]);
				delete oConn._timeOut[o.tId];
			}

			// Fire global custom event -- completeEvent
			oConn.completeEvent.fire(o, args);

			if(o.completeEvent){
				// Fire transaction custom event -- completeEvent
				o.completeEvent.fire(o, args);
			}

			obj = {
			    tId : o.tId,
			    argument : callback.argument
            };

			try
			{
				// responseText and responseXML will be populated with the same data from the iframe.
				// Since the HTTP headers cannot be read from the iframe
				obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:io.contentWindow.document.documentElement.textContent;
				obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
			}
			catch(e){}

			if(callback && callback.upload){
				if(!callback.scope){
					callback.upload(obj);
				}
				else{
					callback.upload.apply(callback.scope, [obj]);
				}
			}

			// Fire global custom event -- uploadEvent
			oConn.uploadEvent.fire(obj);

			if(o.uploadEvent){
				// Fire transaction custom event -- uploadEvent
				o.uploadEvent.fire(obj);
			}

			YE.removeListener(io, "load", uploadCallback);

			setTimeout(
				function(){
					document.body.removeChild(io);
					oConn.releaseObject(o);
				}, 100);
		};

		// Bind the onload handler to the iframe to detect the file upload response.
		YE.addListener(io, "load", uploadCallback);
	}

	YCM.setForm = _setForm;
	YCM.resetFormState = _resetFormState;
	YCM.createFrame = _createFrame;
	YCM.appendPostData = _appendPostData;
	YCM.uploadFile = _uploadFile;
})();

YAHOO.register("connection", YAHOO.util.Connect, {version: "2.8.0r4", build: "2449"});
/*
Copyright (c) 2009, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.8.0r4
*/
(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,F,E){var D=this.getEl();if(this.patterns.noNegatives.test(C)){F=(F>0)?F:0;}if(C in D&&!("style" in D&&C in D.style)){D[C]=F;}else{B.Dom.setStyle(D,C,F+E);}},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("style" in E){if(F||(B.Dom.getStyle(E,"position")=="absolute"&&H)){G=E["offset"+D[0].charAt(0).toUpperCase()+D[0].substr(1)];}else{G=0;}}else{if(C in E){G=E[C];}}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;}};this._queue=B;this._getIndex=E;};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";A.DEFAULT_BGCOLOR="#fff";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 I=YAHOO.util.Dom.getStyle(G,E);var H=this;if(this.patterns.transparent.test(I)){var F=YAHOO.util.Dom.getAncestorBy(G,function(J){return !H.patterns.transparent.test(I);});if(F){I=C.Dom.getStyle(F,E);}else{I=A.DEFAULT_BGCOLOR;}}}else{I=D.getAttribute.call(this,E);}return I;};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.8.0r4",build:"2449"});function embedFlashObject(oeTags){
    document.write(oeTags);
}

/**
 * This method opens a popup window and fills it with the content provided to by the 'functionToGenerateHTML' function of 'subData' object
 * @param {Object} wWidth width of the popup window
 * @param {Object} wHeight height of the poput window
 * @param {Object} title title of the popup window
 * @param {Object} subData the object which requested the popup
 * @param {Object} functionToGenerateHTML the function in the the object 'subData' that will supply the content that goes into this popup
 */
function openPopup(wWidth, wHeight, title, subData, functionToGenerateHTML){
    var htmlContentStr = subData[functionToGenerateHTML](subData);
    // configure window options
    var options = "menubar=0,toolbar=0,location=0,directories=0,status=0,scrollbars=1,resizable=1,width=" + wWidth + ",height=" + wHeight;

    // open window and write HTML
    var win = window.open("", "", options);
    win.document.open();
    win.document.write(htmlContentStr);
    win.document.close();
    win.focus();
}
/**
 * This method opens a popup window with the given URL and given width and height.
 * @param {Object} URL url of the popup window
 * @param {Object} wWidth width of the popup window
 * @param {Object} wHeight height of the poput window
 */
function openPopupLink(url, wWidth, hHeight)
{
    var options = "menubar=0,toolbar=0,location=0,directories=0,status=0,scrollbars=1,resizable=1,width=" + wWidth +",height=" + hHeight;
    window.open(url, "_blank", options);
}
/**
 * This method opens a new window with the given URL and maximum width and height.
 * @param {Object} URL url of the popup window
 */
function openMaxWindowLink(url){
var sOptions;
sOptions = 'status=1,menubar=1,scrollbars=1,resizable=1,toolbar=1,menubar=1,location=1'; 
sOptions = sOptions + ',width=' + (screen.availWidth).toString(); 
sOptions = sOptions + ',height=' + (screen.availHeight).toString(); 
window.open( url, "_blank", sOptions );  
}
/**
 * Attaches a the baseDiv to the display-div in the doument and sets the
 * baseDiv innerHTML property to the html passed.
 * The method firs searches for the baseDiv under child elements of the
 * 'display-div'. If found, the htmlStr is set as inner HTML property of the
 * baseDiv. If baseDiv is not found, a new div is created and attached as the
 * baseDiv to the 'display-div'.
 * @params baseDiv The widget base div to be attached to the 'display-div'
 * @params htmlStr detempletized html string to be set as inner html of the baseDiv
 * @params widgetId id of the caller widget
 **/
function attachBaseDivToDisplayDiv(basediv, htmlStr, widgetId){
    log4javascript.getDefaultLogger().debug("attaching basediv for  -> " + widgetId + " " + basediv);

    var __displayDiv = document.getElementById("display-div");

    if (null != __displayDiv) {
        var childDivs = __displayDiv.getElementsByTagName("div");

        var isBaseDivPresent = false;
        //for( var i in childDivs ) {
        for (var i = 0; i < childDivs.length; i++) {
            try {
                if (basediv == childDivs[i].getAttribute("id")) {
                    log4javascript.getDefaultLogger().debug("Basediv already present. Quitting ... ");
                    childDivs[i].innerHTML = htmlStr;
                    isBaseDivPresent = true;
                    break;
                }

            }
            catch (e) {
            }
        }

        if (!isBaseDivPresent) {
            log4javascript.getDefaultLogger().debug("No " + basediv + " div in the DOM. Creating it dynamically.");
            var __baseDiv = document.createElement("div");
            __baseDiv.setAttribute("id", basediv);
            __displayDiv.appendChild(__baseDiv);
            __baseDiv.innerHTML = htmlStr;
        }
    }
    else {
        log4javascript.getDefaultLogger().debug("No displayDiv div in the DOM. Attaching " + basediv + " to body.");
        document.getElementById(basediv).innerHTML = wtk.loader.deParametrizeTemplate(htmlStr, widgetId);

    }
}


getChildDivDOM = function(parentDivId, divId){
    var _parentDiv = document.getElementById(parentDivId);
    var div = null;

    if (null != _parentDiv) {
        log4javascript.getDefaultLogger().debug("Parent Div present : "+parentDivId);
        var childDivs = _parentDiv.getElementsByTagName("div");

        for (var i = 0; i < childDivs.length; i++) {
            try {
                if (divId == childDivs[i].getAttribute("id")) {
                    log4javascript.getDefaultLogger().debug("Child Div present : "+childDivs[i].getAttribute("id"));
                    div = childDivs[i];
                    break;
                }
            }
            catch (e) {
            }
        }

        childDivs = _parentDiv.getElementsByTagName("tr");

        for (var i = 0; i < childDivs.length; i++) {
            try {
                if (divId == childDivs[i].getAttribute("id")) {
                    log4javascript.getDefaultLogger().debug("Child Div present : "+childDivs[i].getAttribute("id"));
                    div = childDivs[i];
                    break;
                }
            }
            catch (e) {
            }
        }

        childDivs = _parentDiv.getElementsByTagName("table");

        for (var i = 0; i < childDivs.length; i++) {
            try {
                if (divId == childDivs[i].getAttribute("id")) {
                    log4javascript.getDefaultLogger().debug("Child Div present : "+childDivs[i].getAttribute("id"));
                    div = childDivs[i];
                    break;
                }
            }
            catch (e) {
            }
        }

        childDivs = _parentDiv.getElementsByTagName("td");

        for (var i = 0; i < childDivs.length; i++) {
            try {
                if (divId == childDivs[i].getAttribute("id")) {
                    log4javascript.getDefaultLogger().debug("Child Div present : "+childDivs[i].getAttribute("id"));
                    div = childDivs[i];
                    break;
                }
            }
            catch (e) {
            }
        }

        childDivs = _parentDiv.getElementsByTagName("span");

        for (var i = 0; i < childDivs.length; i++) {
            try {
                if (divId == childDivs[i].getAttribute("id")) {
                    log4javascript.getDefaultLogger().debug("Child Div present : "+childDivs[i].getAttribute("id"));
                    div = childDivs[i];
                    break;
                }
            }
            catch (e) {
            }
        }

        childDivs = _parentDiv.getElementsByTagName("img");

        for (var i = 0; i < childDivs.length; i++) {
            try {
                if (divId == childDivs[i].getAttribute("id")) {
                    log4javascript.getDefaultLogger().debug("Child Div present : "+childDivs[i].getAttribute("id"));
                    div = childDivs[i];
                    break;
                }
            }
            catch (e) {
            }
        }
        
        childDivs = _parentDiv.getElementsByTagName("center");

        for (var i = 0; i < childDivs.length; i++) {
            try {
                if (divId == childDivs[i].getAttribute("id")) {
                    log4javascript.getDefaultLogger().debug("Child Div present : "+childDivs[i].getAttribute("id"));
                    div = childDivs[i];
                    break;
                }
            }
            catch (e) {
            }
        }
        
        childDivs = _parentDiv.getElementsByTagName("ul");

        for (var i = 0; i < childDivs.length; i++) {
            try {
                if (divId == childDivs[i].getAttribute("id")) {
                    log4javascript.getDefaultLogger().debug("Child Div present : "+childDivs[i].getAttribute("id"));
                    div = childDivs[i];
                    break;
                }
            } 
            catch (e) {
            }
        }
    }else{
        log4javascript.getDefaultLogger().debug("Parent Div NOT present : "+parentDivId);
        div = YAHOO.util.Dom.get(divId);
    }
    return div;
}

/**
 * This function returns the HTML element inside the parent div.
 * @param {Object} parentDivId The parent div ID
 * @param {Object} elementId The element ID
 * @param {Object} elementTagName The tag Name of the element, example: img
 */
getChildElement = function(parentDivId, elementId, elementTagName){
    var _parentDiv = document.getElementById(parentDivId);

    if (null != _parentDiv) {
        log4javascript.getDefaultLogger().debug("Parent Div present : " + parentDivId);
        var childDivs = _parentDiv.getElementsByTagName(elementTagName);

        for (var i = 0; i < childDivs.length; i++) {
            try {
                if (elementId == childDivs[i].getAttribute("id")) {
                    log4javascript.getDefaultLogger().debug("Child Div present : " + childDivs[i].getAttribute("id"));
                    return childDivs[i];
                }
            }
            catch (e) {
            }
        }
    }
    return null ;
}

BPTrim = function (str) {
    var str = str.replace(/^\s\s*/, ''),
        ws = /\s/,
        i = str.length;
    while (ws.test(str.charAt(--i)));
    return str.slice(0, i + 1);
}
/**
 * returns false if the value is undefined.
 * @param {Object} value
 */
isDefined = function( value ){
    if( typeof value == 'undefined' ){
            return false;
        }else{
           return true;
        }
}

/**
 * The following date time functions are taken from
 * Author: Matt Kruse <matt@mattkruse.com>
 * WWW: http://www.mattkruse.com/
 */
var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
function LZ(x) {return(x<0||x>9?"":"0")+x}

// ------------------------------------------------------------------
// formatDate (date_object, format)
// Returns a date in the output format specified.
// The format string uses the same abbreviations as in getDateFromFormat()
// ------------------------------------------------------------------
formatDate = function (date,format) {
    format=format+"";
    var result="";
    var i_format=0;
    var c="";
    var token="";
    var y=date.getYear()+"";
    var M=date.getMonth()+1;
    var d=date.getDate();
    var E=date.getDay();
    var H=date.getHours();
    var m=date.getMinutes();
    var s=date.getSeconds();
    var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
    // Convert real date parts into formatted versions
    var value=new Object();
    if (y.length < 4) {y=""+(y-0+1900);}
    value["y"]=""+y;
    value["yyyy"]=y;
    value["yy"]=y.substring(2,4);
    value["M"]=M;
    value["MM"]=LZ(M);
    value["MMM"]=MONTH_NAMES[M-1];
    value["NNN"]=MONTH_NAMES[M+11];
    value["d"]=d;
    value["dd"]=LZ(d);
    value["E"]=DAY_NAMES[E+7];
    value["EE"]=DAY_NAMES[E];
    value["H"]=H;
    value["HH"]=LZ(H);
    if (H==0){value["h"]=12;}
    else if (H>12){value["h"]=H-12;}
    else {value["h"]=H;}
    value["hh"]=LZ(value["h"]);
    if (H>11){value["K"]=H-12;} else {value["K"]=H;}
    value["k"]=H+1;
    value["KK"]=LZ(value["K"]);
    value["kk"]=LZ(value["k"]);
    if (H > 11) { value["a"]="PM"; }
    else { value["a"]="AM"; }
    value["m"]=m;
    value["mm"]=LZ(m);
    value["s"]=s;
    value["ss"]=LZ(s);
    while (i_format < format.length) {
        c=format.charAt(i_format);
        token="";
        while ((format.charAt(i_format)==c) && (i_format < format.length)) {
            token += format.charAt(i_format++);
            }
        if (value[token] != null) { result=result + value[token]; }
        else { result=result + token; }
        }
    return result;
    }
//END of date functions taken from www.mattkruse.com
isIE6Browser = function() {
    var msie = navigator.appVersion.split('MSIE');
    if (typeof msie != "undefined" && msie != null) {
        if (parseInt(msie[1]) <= 6) {
            return true;
        }
    }
    return false;
}




getFirstValue = function(valueMap)
{  
    if (typeof (valueMap) != "string") {
        if ( typeof(valueMap) == 'object' ) {
            if (valueMap.length)
                return valueMap[0];
            else
                return valueMap;
        }
    } 
    else { 
        return valueMap;
    }
}

/**
 * This function returns an array, if the passed value is NOT an array.
 * Returns the same object otherwise
 * @param {Object} value
 */
getValues = function(value) {
    if("undefined" == typeof(value.length)) {
        var array = new Array( ) ;
        array[0] = value ;
        return array ;
    }
    return value ;
}
/**
 * This class does all the loading and initialization of the widgets. It is also responsible
 * for loading page state information.
 *
 * @author janil
 */

/**
 * This function represents the com.forddirect.presentation.wtk.Loader class.
 */
getPackageForName( "com.forddirect.presentation.wtk" ).Loader = function( parentInstance )
{
    //The js, css, html classpath variables
    this.jsFileClassPath = "" ;
    this.cssFileClassPath = "" ;
    this.htmlFileClassPath = "" ;
    this.flashFileClassPath = "" ;

    this.parentInstance = parentInstance ;

    //these flags are needed to check whether the flash controller is already loaded or not
    this.flashControllerLoadEvent = new YAHOO.util.CustomEvent( "FlashControllerLoaded" ) ;

    //this widgets list stores the list of widgets for the reference of loading widgets from mainFlashAppInitialized
    this.widgetList = "";

    //this stores the group id of widgets for the reference of loading widgets from mainFlashAppInitialized
    this.groupId = "";

    /**
     * This function initializes the Loader object and returns the loadInit id.
     * @param {String} jsFileClassPath Classpath for the *.js files
     * @param {String} cssFileClassPath Classpath for the *.css files
     * @param {String} htmlFileClassPath Classpath for the *.html files
     * @param {String} flashFileClassPath Classpath for the *.swf files
     * @return An event which signals the successful initialization of the Loader module.
     * The calling function must subscribe to the event to perform logic on the Loader.
     */
    this.init = function( jsFileClassPath, cssFileClassPath, htmlFileClassPath, flashFileClassPath )
    {
        //log4javascript.getDefaultLogger( ).debug( "Loader::INIT" ) ;
        this.jsFileClassPath = jsFileClassPath ;
        this.cssFileClassPath = cssFileClassPath ;
        this.htmlFileClassPath = htmlFileClassPath ;
        this.flashFileClassPath = flashFileClassPath ;

        //This internal function is called when the BaseWidget *file* is loaded. The event
        //internalSuccessEvents(widgetId) is fired to signal the successful loading.
        var _onBaseWidgetDownloaded = function( event, firedData, subscribedData ) {
            //log4javascript.getDefaultLogger( ).info( "Loader::Loader class initialized" ) ;
            subscribedData['loaderInitEvent'].fire( ) ;
        } ;

        var successEvent = new YAHOO.util.CustomEvent( "successEvent", this ) ;
        var failureEvent = new YAHOO.util.CustomEvent( "failureEvent", this ) ;
        var loaderInitEvent = new YAHOO.util.CustomEvent( "loaderInit", this.parentInstance ) ;

        successEvent.subscribe( _onBaseWidgetDownloaded, {'loaderInitEvent':loaderInitEvent} ) ;

        var baseWidgetObject = {
                "widgetClass" : "com.forddirect.presentation.widgets.basewidget.BaseWidget",
                "initParams" : "param=1",
                "type" : "js",
                "widgetId" : "basewidget",
                "widgetLocation" : __baseClassPath+"static/com/forddirect/presentation/widgets/basewidget/BaseWidget.js"
            } ;

        this.load( baseWidgetObject, successEvent, failureEvent ) ;
        return loaderInitEvent ;
    }


    /**
     * This function downloads the list of components.
     * @param {Object} components List of the components to be loaded Each component should have
     * the following attributes -
     * 1) widgetClass: The class of the component. for example,
     *                                  com.forddirect.presentation.widgets.config.Config
     * 2) type: whether js, css, swf, html, widget
     * 3) baseDiv: The div in which the component is to be loaded
     * 4) parentWidgetId: [Only for HTML]The id of the widget to which the HTML template is to be
     *                                   applied.
     * 5) initParams: {Object} The parameters to be sent when loading the class
     * 6) widgetId: The unique ID of each component
     * This functions calls the load function on individual event and creates a group event for
     * the group. This groupEvent is fired when all the components are successfully loaded.
     *
     * @return widgetsDownloadedEvent The event which would be fired on successful downloading of
     * of the group of components.
     */
    this.loadComponents = function( components , shouldInit , clubWidgets )
    {
        log4javascript.getDefaultLogger( ).debug( "Loader::LoadComponents" ) ;

        var widgetsDownloadedEvent = new YAHOO.util.CustomEvent( "widgetsDownloadedEvent", this.parentInstance );
        var successEvent = "" ;
        var failureEvent = "" ;
        if ("undefined" == typeof(clubWidgets)  || null == clubWidgets || clubWidgets != true) {
            for (var widgetName in components) {
                for (var c in components[widgetName]) {
                    components[widgetName][c].isLoaded = false;
                    successEvent = new YAHOO.util.CustomEvent(components[widgetName][c].widgetId, this);
                    failureEvent = new YAHOO.util.CustomEvent(components[widgetName][c].widgetId, this);
                    successEvent.subscribe(this._onLoadComplete, {
                        'widgetsDownloadedEvent': widgetsDownloadedEvent,
                        'components': components
                    });
                    this.load(components[widgetName][c], successEvent, failureEvent);
                }
            }
        }
        else {
            this.loadClubbedWidgets(components, widgetsDownloadedEvent);
        }
        return widgetsDownloadedEvent ;
    }

    this.loadClubbedWidgets = function(components , widgetsDownloadedEvent) {
        var location = __baseClassPath + "localization/?";
        
        var widgetsParam = "";
        for( widgetName in components ){
            for (c in components[widgetName]) {
                log4javascript.getDefaultLogger().debug("Component Loading = " + components[widgetName][c].widgetName);
                components[widgetName][c].isLoaded = false;
            }
            if(widgetsParam != "") {
                widgetsParam = widgetsParam + "|";
            }
            widgetsParam = widgetsParam + widgetName;
        }
        
        var context = this ;
        var successEvent = new YAHOO.util.CustomEvent( widgetsParam, this ) ;
        var failureEvent = new YAHOO.util.CustomEvent( widgetsParam, this ) ;
        successEvent.subscribe( this.onLoadWidgetsComplete, {'widgetsDownloadedEvent': widgetsDownloadedEvent, 'components':components} ) 
        var callback = {
            success: function(o) { context._onClubbedWidgetFileDownloaded( eval('('+o.responseText+')'), successEvent, components ) ; },
            failure: function(o) { log4javascript.getDefaultLogger( ).debug(o) ; failureEvent.fire( o ) ; }
        } ;

        location = location + "widgets=" + widgetsParam;
        //Read the urlParamMap (defined in the [App layer] index.jsp) and adding all the parameters
        //to the localization URL query string
        for(var key in urlParamMap)
        {
            location = location + "&" + key + "=" + urlParamMap[key];
        }
        location = location + "&clubWidgets=true";
        log4javascript.getDefaultLogger( ).debug("Component Loading Location = " + location);
        YAHOO.util.Connect.asyncRequest( "GET", location, callback ) ;
    }

    this.onLoadWidgetsComplete = function(event, firedData , subscribedData) {
        log4javascript.getDefaultLogger( ).debug("widgetsDownloadedEvent firing");
        subscribedData['widgetsDownloadedEvent'].fire( ) ;
    }

    this._onClubbedWidgetFileDownloaded = function(responseObject, firedData, components) {
        for (var widgetName in responseObject) {
            log4javascript.getDefaultLogger( ).debug("Component Response = " + widgetName);
            if(commUtils.isDefinedAndNotNull(components[widgetName])) {
                log4javascript.getDefaultLogger( ).debug("Component Response = " + widgetName + " Assigning Values");
                for (var comp in components[widgetName]) {
                    component = components[widgetName][comp];
                    component["type"] = responseObject[widgetName]["type"];
                    component["js"] = responseObject[widgetName]["js"];
                    
                    if ("swf" == component["type"]) {
                        log4javascript.getDefaultLogger().debug("Component Response = " + widgetName + " Adding SWF Component");
                        component["swf"] = (typeof responseObject[widgetName]["swf"] == "undefined") ? responseObject[widgetName]["swf"] : responseObject[widgetName]["swf"][component.widgetName];
                    }
                    else {
                        log4javascript.getDefaultLogger().debug("Component Response = " + widgetName + " Adding CSS Component");
                        component["css"] = (typeof responseObject[widgetName]["css"] == "undefined") ? responseObject[widgetName]["css"] : responseObject[widgetName]["css"][component.widgetName];
                        if (typeof responseObject[widgetName]["html"] != "undefined" && responseObject[widgetName]["html"] != null) {
                            var temp = this.getCount(responseObject[widgetName]["html"]);
                            component["html"] = (temp > 1) ? responseObject[widgetName]["html"] : responseObject[widgetName]["html"][component.widgetName];
                        }
                        else {
                            component["html"] = responseObject[widgetName]["html"];
                        }
                        log4javascript.getDefaultLogger().debug("Component Response = " + widgetName + " Adding HTML Component");
                    }
                }
            }
        }
        firedData.fire();
    }

    /**
     * This function listens to the successEvent of each component, which signals the successful
     * downloading of the component.
     * @param {Object} event SuccessEvent signaling the download of the component
     * @param {Object} firedData {}
     * @param {Object} subscribedData {'widgetsDownloadedEvent', 'components'}
     */
    this._onLoadComplete = function( event, firedData, subscribedData )
    {
        //log4javascript.getDefaultLogger( ).info( "Loader::" + firedData[0] + " downloaded" ) ;
        var components = subscribedData['components'] ;
        var _flag = false ;
        for(var widgetName in components ) {
            for (comp in components[widgetName]) {
                //Check if the widget which fired the successEvent is same as the current component
                if (firedData[0] == components[widgetName][comp].widgetId) {
                    components[widgetName][comp].isLoaded = true;
                }
                //Check if the current component is loaded
                if (!components[widgetName][comp].isLoaded) {
                    _flag = true;
                }
            }
        }
        //Check if there is AT LEAST one component still NOT downloaded
        if( _flag )
            return ;
        log4javascript.getDefaultLogger( ).info( "Loader::_onLoadComplete All components loaded" ) ;
        subscribedData['widgetsDownloadedEvent'].fire( ) ;
    }

    /**
     * This function loads a single component
     * @param {Object} component This object has all the attributes necessary for loading the
     *                           component.
     * @param {Event} successEvent Event to be fired on successful download
     * @param {Event} failureEvent Event to be fired on failed download
     * Each component should have the following attributes -
     * 1) widgetClass: The class of the component.
     *                 for example, com.forddirect.presentation.widgets.config.Config
     * 2) type: whether js, css, swf, html, widget
     * 3) baseDiv: The div in which the component is to be loaded
     * 4) parentWidgetId: [Only for HTML]The id of the widget to which the HTML template is to be
     *                                   applied.
     * 5) initParams: {Object} The parameters to be sent when loading the class
     * 6) widgetId: The unique ID of each component
     * 7) widgetLocation: [For HTML, CSS, JS]The filePath of the component
     *
     * @return widgetId
     */
    this.load = function(component, successEvent, failureEvent)
    {
        //log4javascript.getDefaultLogger( ).debug( "Loader::Loading " + component.widgetId + "/" + component.type ) ;

        //A pointer to the loader instance
        var context = this ;

        if( "widget" == component.type ) {
            //The JSON response from the localization service is loaded and processed.
            return this.loadWidget( component, successEvent, failureEvent ) ;
        }
        else if( "html" == component.type ) {
            //the HTML file is downloaded and attached to the basediv after de-parametrizing
            var callback = {
                success : function(o) { context._onHtmlFileDownloaded( o.responseText, successEvent, component.baseDivId, component.widgetId, context ) },
                failure : function(o) { }
            } ;
            YAHOO.util.Connect.asyncRequest( "GET", component.widgetLocation, callback, component.initParams ) ;
            return component.widgetId ;
        }
        //For CSS/JS create and attach the tags to the document head.
        //Set the flag required for the IE script/link tags
        var ieFlag = this.getIeFlag( component.type ) ;
        //Create the tag for JS/CSS
        var componentTag = this.getComponentTag( this, component.widgetLocation, component.type, component.widgetId ) ;
        //Attach the JS/CSS tag
        if(BrowserDetect.browser == 'Safari'){
            this.attachComponentInSafari( successEvent, component.widgetId, component.widgetLocation ) ;
        }
        else{
            this.attachComponent( successEvent, component.widgetId, componentTag, ieFlag ) ;
        }
        return component.widgetId ;
    }


    this.attachComponentInSafari = function( event, widgetId, widgetLocation ) {

        //log4javascript.getDefaultLogger( ).debug( "Loader::Adding " + widgetId + " tag to the DOM:Safari" ) ;
        var componentTag = document.createElement( 'script' ) ;
        var callback = {
            success: function(o){
                componentTag.setAttribute( "type", "text/javascript" ) ;
                componentTag.setAttribute( "id", widgetId + "_js") ;
                componentTag.appendChild( document.createTextNode( o.responseText ) ) ;
                document.getElementsByTagName( "head" ).item( 0 ).appendChild( componentTag ) ;
                event.fire(widgetId);
                },
            failure: function(o){log4javascript.getDefaultLogger().debug( "Failure::attachComponentSafari" ) ;}
        } ;
        YAHOO.util.Connect.asyncRequest( 'GET', widgetLocation, callback) ;

    }

    /**
     * This function attaches the tag to the HEAD of the DOM. On successful attachment, the event
     * is fired.
     * @param {Object} event The successEvent to be fired when the tag is attached
     * @param {Object} widgetId The widgetId associated with the JS/CSS
     * @param {Object} tag The tag to be attached
     * @param {Object} ieFlag The flag to determine the IE attachment
     */
    this.attachComponent = function( event, widgetId, tag, ieFlag )
    {
        //log4javascript.getDefaultLogger( ).debug( "Loader::Adding " + widgetId + " tag to the DOM" ) ;
        //In Firefox, when a script is loaded, browser calls the onload function
        tag.onload = function( ) {
            event.fire( widgetId ) ;
        } ;
        //In IE, when a script is loaded, browser calls the onreadystatechange function. The ready states
        //of the script should be checked everytime. when the script is loaded for the first time, it's readystate
        //is 'loaded'. But when it is cached and loaded again, it calls the function for 2 readystates: 'loaded'
        //and 'complete'. Hence the ieFlag is used so that the logic in executed only once.
        tag.onreadystatechange = function( ) {
            if( "loaded" == tag.readyState || "complete" == tag.readyState && ieFlag ) {
                ieFlag = false ;
                event.fire( widgetId ) ;
            }
        } ;
        document.getElementsByTagName( "head" ).item( 0 ).appendChild( tag ) ;
    }

    /**
     * This function returns the component tag for the particular file and type
     *
     * @param {Object} context The scope of the function (this)
     * @param {String} filePath The file path to be added to the head tag
     * @param {String} type The type of the file to be added to the head tag
     * @return ComponentTag
     */
    this.getComponentTag = function( context, filePath, type , id )
    {
        if( "js" == type )
            return context._getJavascriptComponent( filePath, id ) ;
        else if( "css" == type )
            return context._getCssComponent( filePath, id ) ;
        else if( "alt css" == type )
            return context._getRelCssComponent( filePath, id ) ;
        return null ;
    }

    /**
     * This function sets the IE Flag to false for the css files.
     *
     * @param {String} type The type of the file (css/js/html)
     * @return Boolean
     */
    this.getIeFlag = function( type )
    {
        if( "css" == type || "alt css" == type)
            return false ;
        return true ;
    }

    /**
     * This function returns the classpath for the type specified
     *
     * @param {Object} context The scope of the function(this)
     * @param {String} type The type of the class
     * @return Classpath
     */
    this.getClassPath = function( context, type, componentLocation )
    {
        if( componentLocation != null )
            return componentLocation ;
        else if( "js" == type )
            return context.jsFileClassPath ;
        else if( "css" == type || "alt css" == type )
            return context.cssFileClassPath ;
        else if( "html" == type )
            return context.htmlFileClassPath ;
        else if( "swf" == type )
            return context.flashFileClassPath ;
        else
            return null ;
    }

    /**
     * This function copies the contents of one div to another. It accepts parameters as divId
     * of the div to be copied and parentDiv, to which content needs to be copied.
     * @param divId Id of the div, whose contents are to be copied
     * @param parentDiv id of the div to which contents need to be copied
     * @return success true if successful; false otherwise
     */
    this.copyDiv = function( currentDivID, currentAncestorDivID, targetDivID, targetAncestorDivID )
    {
        //TODO: update documentation
        log4javascript.getDefaultLogger( ).debug("Copying div  " +currentAncestorDivID+"."+ currentDivID + " to target div " +targetAncestorDivID+"."+ targetDivID);

        if(currentDivID !== targetDivID){//ideal scenario
            var contentDivNode = YAHOO.util.Dom.get(currentDivID);
            var targetDivNode = YAHOO.util.Dom.get(targetDivID);
            targetDivNode.innerHTML = contentDivNode.innerHTML;
            return true;
        }
        else if( null != currentAncestorDivID && null != targetAncestorDivID)
        {
            var currentDivNode = YAHOO.util.Dom.get(currentAncestorDivID);
            //search the specified div in parent div
            var srcDivElements = currentDivNode.getElementsByTagName("div");
            var sourceDivNode = null;
            for(i=0;i< srcDivElements.length;i++) {
                //check the div id
                if(srcDivElements[i].getAttribute("id") == currentDivID) {
                    //copy the contents of the div
                    sourceDivNode = srcDivElements[i];
                    break;
                }
            }
            if( null == sourceDivNode ){
                return false;
            }
            var targetAncestorDivNode = YAHOO.util.Dom.get(targetAncestorDivID);

            var targetDivElements = targetAncestorDivNode.getElementsByTagName("div");
            for(i=0; i<targetDivElements.length; i++) {
                //check the div id
                if(targetDivElements[i].getAttribute("id") == targetDivID) {
                    //copy the contents of the div
                    targetDivElements[i].innerHTML = sourceDivNode.innerHTML;
                    return true;
                }
            }
        }

        //div not found in parent div; return false
        return false;
    }

    /**
     * This function accepts widgetId and removes css link of that widget
     * @param widgetId
     * @return success flag
     */
    this.removeCSS = function ( widgetId )
    {
        var cssNode = document.getElementById(widgetId + "_css");
        if(cssNode != null) {
            //delete css from the document
            document.getElementsByTagName( "head" ).item( 0 ).removeChild( cssNode ) ;
            return true;
        } else {
            log4javascript.getDefaultLogger( ).error( "css link for " + widgetId + "_css not found") ;
            return false;
        }
    }

    /**
     * This function accepts widgetId and removes js script of that widget
     * @param widgetId
     * @return success flag
     */
    this.removeJS = function ( widgetId )
    {
        var jsNode = document.getElementById(widgetId + "_js");
        if(jsNode != null) {
            //delete css from the document
            document.getElementsByTagName( "head" ).item( 0 ).removeChild( jsNode ) ;
            return true;
        } else {
            log4javascript.getDefaultLogger( ).error( "js script for " + widgetId + "_js not found") ;
            return false;
        }
    }

    //This internal function is used to get a <script> tag for the js filePath
    this._getJavascriptComponent = function( filePath, id )
    {
        var scriptTag = document.createElement( "script" ) ;
        scriptTag.setAttribute( "type", "text/javascript" ) ;
        scriptTag.setAttribute( "src", filePath ) ;
        scriptTag.setAttribute( "id", id + "_js") ;
        return scriptTag ;
    }

    //This internal function is used to get a <link> tag for the css filePath
    this._getCssComponent = function( filePath, id )
    {
        var linkTag = document.createElement( "link" ) ;
        linkTag.setAttribute( "rel", "stylesheet") ;
        linkTag.setAttribute( "type", "text/css") ;
        linkTag.setAttribute( "href", filePath ) ;
        linkTag.setAttribute( "id", id ) ;
        return linkTag ;
    }

    //This internal function is used to get a <link> tag for the css filePath
    this._getRelCssComponent = function( filePath, id )
    {
        var linkTag = document.createElement( "link" ) ;
        linkTag.setAttribute( "rel", "alternate stylesheet") ;
        linkTag.setAttribute( "type", "text/css") ;
        linkTag.setAttribute( "href", filePath ) ;
        linkTag.setAttribute( "id", id ) ;
        linkTag.setAttribute( "title", id ) ;
        return linkTag ;
    }

    /**
     * This function unloads a widget. It basically unloads the js, css and html contents of the specified javascript widget
     * TODO: when should the js instance be made null??
     * @param divId
     * @param widgetId
     */
    this.unload = function (divId,widgetId)
    {
        log4javascript.getDefaultLogger( ).debug( "unloading widget " + widgetId) ;

        //get node for specified css file
        //var cssNode = document.getElementsByTagName( "head" ).item( 0 ).getElementById(widgetId + "_css");
        var cssNode = document.getElementById(widgetId + "_css");
        if(cssNode != null) {
            log4javascript.getDefaultLogger( ).debug( "found cssNode") ;
            //delete css from the document
            document.getElementsByTagName( "head" ).item( 0 ).removeChild( cssNode ) ;
        }
        
        if(null != divId){
            var __displayDiv = document.getElementById("display-div");
            //TODO: To be removed once page-level HTMLs are removed
            if (null != __displayDiv) {
                var childDivs = __displayDiv.getElementsByTagName("div");
                
                var isBaseDivPresent = false;
                //for( var i in childDivs ) {
                for (var i = 0; i < childDivs.length; i++) {
                    try {
                        if (divId == childDivs[i].getAttribute("id")) {
                            //log4javascript.getDefaultLogger().debug("Basediv already present. Quitting ... ");
                            childDivs[i].innerHTML = ""; 
                            break;
                        }
                    } 
                    catch (e) {
                    }
                }
            }
            //remove the html from the div
            //YAHOO.util.Dom.get(divId).innerHTML = ""; //ToDo --> should be done before css is removed.
            /*var divToDel = YAHOO.util.Dom.get(divId);
            var ancestorDiv = YAHOO.util.Dom.getAncestorByTagName(divToDel, 'div');
            ancestorDiv.removeChild(divToDel);*/
        }

        //get node for specified css file
        //var jsNode = document.getElementsByTagName( "head" ).item( 0 ).getElementById(widgetId + "_js");
        var jsNode = document.getElementById(widgetId + "_js");
        if(jsNode != null)
        {
            log4javascript.getDefaultLogger( ).debug( "found jsNode") ;
            //delete css from the document
            document.getElementsByTagName( "head" ).item( 0 ).removeChild( jsNode ) ; //ToDo --> head/baseDiv
        }
        /*//return the reference to the node specified in jsClass
        return (this.getDocumentNode("js", jsPath));*/
    }

    /**
     * This function returns the document node script/link depending upon the type of the file and file path.
     * It searched is document/header for the specified node and returns it
     * @param type Type of the file (js/css)
     * @param filePath path of the file
     * @return node reference to the specified file if exists; null otherwise
     */
    this.getDocumentNode = function( type, filePath )
    {
        var i;
        var typeVal;
        var pathVal;
        var linkNodes;

        //get the nodes of the type script/link depending upon the type js/css
        if("js" == type)
        {
            linkNodes = document.getElementsByTagName( "head" ).item( 0 ).getElementsByTagName("script");
        } else if("css" == type || "alt css" == type) {
            linkNodes = document.getElementsByTagName( "head" ).item( 0 ).getElementsByTagName("link");
        }

        if(linkNodes == null)
        {
            return null;
        }

        //loop through all the nodes to find the node having specified path
        var length = linkNodes.length;
        for(i=0;i<length;i++)
        {
            var linkNode = linkNodes[i];

            //check the type of the node
            typeVal = linkNode.getAttribute("type");
            if("js" == type) {
                if(typeVal == "text/javascript") {
                    pathVal = linkNode.getAttribute("src");
                    if(pathVal == filePath) {
                        return linkNode;
                    }
                }
            } else if("css" == type || "alt css" == type) {
                if(typeVal == "text/css") {
                    pathVal = linkNode.getAttribute("href");
                    if(pathVal == filePath) {
                        return linkNode;
                    }
                }
            }
        }

        //specified node not found; return null
        return null;
    }

   /**
    *
    */
    this.setActiveStyleSheet = function(title)
    {
        var i, a, main;
        for(i=0; (a = document.getElementsByTagName("link")[i]); i++) {
             if(a.getAttribute("rel").indexOf("alternate stylesheet") != -1
                && a.getAttribute("title")) {
                   a.disabled = true;
                   if(a.getAttribute("title") == title) a.disabled = false;
               }
         }
   }

   /**
    * This function downloads the widget JSON response from the Localization service and signals
    * the completion by the successEvent
    *
    * @param {Object} component The widget component
    * @param {Object} successEvent The event to be fired on success
    * @param {Object} failureEvent The event to be fired on failure
    *
    * This function
    */
    this.loadWidget = function( component, successEvent, failureEvent )
    {
        //log4javascript.getDefaultLogger( ).debug( "Loader::Loading widget " + component.widgetName ) ;
        var context = this ;
        var callback = {
            success: function(o) { context._onWidgetFileDownloaded( eval('('+o.responseText+')'), successEvent, component ) ; },
            failure: function(o) { log4javascript.getDefaultLogger( ).debug(o) ; failureEvent.fire( o ) ; }
        } ;
        var location = __baseClassPath + "localization/?widgetName=" + component.widgetName ;
        //Read the urlParamMap (defined in the [App layer] index.jsp) and adding all the parameters
        //to the localization URL query string
        for(var key in urlParamMap)
        {
            location = location + "&" + key + "=" + urlParamMap[key];
        }
        //log4javascript.getDefaultLogger( ).debug( "Loader ::: Adding Custom Localization Keys"  + component.localizationParams) ;
        if (typeof component.localizationParams != "undefined" && component.localizationParams != null) {
            for (var i = 0; i < component.localizationParams.length; i++) {
                //log4javascript.getDefaultLogger().debug("Loader ::: Adding Custom Localization Keys with " + component.localizationParams[i].name + " = " + component.localizationParams[i].value);
                location = location + "&" + component.localizationParams[i].name + "=" + component.localizationParams[i].value;
            }
        }
        //log4javascript.getDefaultLogger( ).debug( "Loader ::: Added Custom Localization Keys") ;
        //log4javascript.getDefaultLogger( ).debug( "Localization URL query for " + component.widgetId + " = " + location ) ;
        YAHOO.util.Connect.asyncRequest( "GET", location, callback ) ;
        return component.widgetId ;
    }

    /**
     * This function is called on the successful downloading of the JSON response of a widget.
     * The JSON object params are as follows -
     * {
     *     "type" : javascript/flash
     *     "js" : A name-value map of widgetId-JS code
     *     "css" : A name-value map of widgetId-CSS code
     *     "html" : A name-value map of widgetId-HTML code
     * }
     * @param {Object} responseObject The response JSON object
     * @param {Object} successEvent The event to be fired on success
     * @param {Object} component The event to be fired on failure
     */
    this._onWidgetFileDownloaded = function( responseObject, successEvent, component )
    {
        //log4javascript.getDefaultLogger( ).info( "Loader::Downloaded JSON object for " + component["widgetId"] ) ;

        component["type"] = responseObject["type"] ;
        component["js"] = responseObject["js"] ;

        if ("swf" == component["type"])
        {
            component["swf"] = (typeof responseObject["swf"] == "undefined") ? responseObject["swf"] : responseObject["swf"][component.widgetName] ;
        }
        else {
            component["css"] = (typeof responseObject["css"] == "undefined") ? responseObject["css"] : responseObject["css"][component.widgetName] ;
            if( typeof responseObject["html"] != "undefined" && responseObject["html"] != null )
            {
                var temp = this.getCount( responseObject["html"] ) ;
                component["html"] = (temp > 1)?responseObject["html"]:responseObject["html"][component.widgetName] ;
            }
            else{
                component["html"] = responseObject["html"] ;
            }
        }
        successEvent.fire( component["widgetId"] ) ;
    }

    this.getCount = function( responseObject ){

        var tempI = 0 ;
        for( var i in responseObject ) {
            tempI ++ ;
        }
        return tempI ;

    }
    /**
     * This function listens to the success event signaling the successful downloading of the HTML
     * template for the widget.
     *
     * @param {Object} responseText The HTML response file
     * @param {Object} successEvent The event to be fired on success
     * @param {Object} baseDivId The ID of the DIV to which the template is to be attached
     * @param {Object} widgetId The ID of the widget to which the template belongs to
     * @param {Object} context The required context
     */
    this._onHtmlFileDownloaded = function( responseText, successEvent, baseDivId, widgetId, context )
    {
        //log4javascript.getDefaultLogger( ).info( "Loader::Downloaded template for " + widgetId );

        YAHOO.util.Dom.get( baseDivId ).innerHTML = context.deParametrizeTemplate( responseText, widgetId ) ;

        successEvent.fire( widgetId ) ;
    }

    /**
     * This function de-parametrizes the text by removing all the '&MYSELF;' with the parent
     * widget references.
     *
     * @param {Object} templateText The text to be de-parametrized
     * @param {Object} parentWidgetId The ID of the parent widget
     */
    this.deParametrizeTemplate = function( templateText, parentWidgetId )
    {
        //log4javascript.getDefaultLogger( ).debug( "Loader::De-parametrizing template for " + parentWidgetId ) ;

        while (templateText.indexOf("&MYSELF;") != -1){
            templateText = templateText.replace("&MYSELF;", 'wtk.widgetInstances["' + parentWidgetId + '"]' ) ;
        }

        return templateText ;
    }

}
// END OF CLASS DEFINITION


/**
 * This function returns the package object for the name that has been passed. This method should be
 * called before adding a class to the package to ensure that the package exists; if not, the method
 * instantiates the package.
 * @param {String} packageName
 */
function getPackageForName( packageName )
{
    var arr = packageName.split('.');
    //log4javascript.getDefaultLogger().debug( packageName ) ;
    var obj = window;
    for(var i=0; i<arr.length; i++)
    {
      if(typeof obj[arr[i]] == 'undefined')
        obj[arr[i]] = {};
      obj = obj[arr[i]];
    }
    return obj;
}

/**
 * This function represents the com.forddirect.presentation.wtk.CommonUtils class.
 */
getPackageForName("com.forddirect.presentation.wtk").CommonUtils = function(){

    /**
     * Fixes PNG 8-bit opacity for IE6 and lower
     * @deprecated use PNGLoader instead
     * @param none
     */
    this.fixPngOpacity = function(){

        log4javascript.getDefaultLogger().debug("** " + wtk.path);
        this.fixPNGImg(YAHOO.util.Dom.get("preferencesPunchLine"));
        this.fixPNGImg(YAHOO.util.Dom.get("preferencesPart1Image"));
        this.fixPNGImg(YAHOO.util.Dom.get("preferencesPart2Image"));
        this.fixPNGBg(YAHOO.util.Dom.get("preferencesSelectorBg"), wtk.path, 'images/bg.png');


    }


    /**
     * Swithes background on selected part.
     * IE6 PNG 8-bit alpha opacity fix.
     * @deprecated use PNGLoader instead
     * @param none
     */
    this.switchPNGBg = function(selectedDivId){

        var parts = YAHOO.util.Dom.getElementsByClassName("preferences-part-bg");
        if (selectedDivId == "preferencesPart1") {
            this.fixPNGBg(parts[0], wtk.path, 'images/bg_selected.png');
            parts[1].style.filter = '';
            parts[1].style.backgroundColor = '#ffffff';
        }
        else {
            this.fixPNGBg(parts[1], wtk.path, 'images/bg_selected.png');
            parts[0].style.filter = '';
            parts[0].style.backgroundColor = '#ffffff';
        }

    }

    /**
     * Fixes IMG element PNG 8-bit alpha opacity in IE6
     * @deprecated use PNGLoader instead
     * @param {Object} img
     */
    this.fixPNGImg = function(img){

        var imgName = img.src.toUpperCase();
        if (imgName.substring(imgName.length - 3, imgName.length) == "PNG") {
            var temp = "id='" + img.id + "' ";
            var imgID = (img.id) ? temp : "";
            temp = "class='" + img.className + "' ";
            var imgClass = (img.className) ? temp : "";
            temp = "title='" + img.title + "' ";
            var _temp = "title='" + img.alt + "' ";
            var imgTitle = (img.title) ? temp : _temp;
            var imgStyle = "display:inline-block;" + img.style.cssText;
            if (img.align == "left")
                imgStyle = "float:left;" + imgStyle;
            if (img.align == "right")
                imgStyle = "float:right;" + imgStyle;
            if (img.parentElement.href)
                imgStyle = "cursor:hand;" + imgStyle;
            var strNewHTML = "<span " + imgID + imgClass + imgTitle +
            " style=\"" +
            "width:" +
            img.offsetWidth +
            "px; height:" +
            img.offsetHeight +
            "px;" +
            imgStyle +
            ";" +
            "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader" +
            "(src=\'" +
            img.src +
            "\', sizingMethod='scale');\"></span>";
            img.outerHTML = strNewHTML;
        }
    }

    /**
     * Fixes background with PNG 8-bit alpha opacity in IE6
     * @deprecated use PNGLoader instead
     * @param {Object} el
     * @param {Object} basePath
     * @param {Object} imagePath
     */
    this.fixPNGBg = function(el, basePath, imagePath){

        el.style.backgroundImage = "";
        el.style.background = "";
        var widgetPath = 'static/com/forddirect/presentation/widgets/ui/preferences/';
        log4javascript.getDefaultLogger().debug("--->" + basePath + " " + widgetPath + " " + imagePath + " " + wtk.path);
        var __temp = ';filter:progid:DXImageTransform.Microsoft.AlphaImageLoader' + '(src=\'' + basePath + widgetPath + imagePath + '\', sizingMethod=\'scale\');';
        el.style.cssText += __temp;

    }

    /**
     * Constructor for a custom locale object.
     *
     * @param {String} decimalPoint    String containing the symbol used as the decimal delimiter.
     * @param {String} thousandSep     String containing the symbol used as a separator for groups
     *                                 of digits to the left of the decimal delimiter.
     *
     * @param {Number} fracDigits      Number representing the number of fractional digits to be written
     *                                 to the right of the decimal delimiter.
     */
    this.locale = function(decimalPoint, thousandSep, fracDigits){
        this.decimalPoint = new String(decimalPoint);
        this.thousandSep = new String(thousandSep);
        this.fracDigits = fracDigits;
    }

    /**
     * Returns number num rounded to the fracDigits'th decimal.
     *
     * @param {Number} num
     * @param {Number} fracDigits
     */
    this.roundFloat = function(num, fracDigits){
        var factor = Math.pow(10, fracDigits);
        return (Math.round(num * factor) / factor);
    }

    /**
     * Returns a string representing num formatted with lc.decimalPoint as decimal separator.
     *
     * @param {Number} num
     * @param {Object} lc
     */
    this.toLcString = function(num, lc){
        var str = new String(num);
        var aParts = str.split(".");
        return (aParts.join(lc.decimalPoint));
    }

    /**
     * Returns a string representing num rounded to lc.fracDigits'th decimal
     * and formatted with lc.decimalPoint as decimal separator.
     *
     * @param {Number} num
     * @param {Object} lc
     */
    this.formatNum = function(num, lc){
        //Use the default locale, if NO locale provided
        if ("undefined" == typeof(lc) || null == lc || "" == lc) {
            lc = g_numLocale;
        }
        var sNum = new String(commUtils.roundFloat(num, lc.fracDigits));
        var aParts = sNum.split(".");
        var intPart = aParts[0];
        var t = [];
        var n = ((new String(intPart.length / 3)).split('.'))[0];


        intPart = intPart.split('');
        for (var i = 0; i < n; i++) {
            t.push((intPart.splice(intPart.length - 3, 3)).join(''));
        }
        if (intPart.length > 0) {
            t.push(intPart.join(''));
        }
        t.reverse();
        intPart = t.join(lc.thousandSep);

        aParts[0] = intPart;
        sNum = aParts.join('.');

        if (lc.fracDigits > 0) {
            if (sNum.indexOf(".") < 0) {
                sNum = sNum + ".";
                while (sNum.length < 1 + sNum.indexOf(".") + lc.fracDigits) {
                    sNum = sNum + "0";
                }
            }
        }
        return (commUtils.toLcString(sNum, lc));
    }

    /**
     * Returns the numerical value of the number contained in str
     * and formatted according to lc.thousandSep and lc.decimalPoint properties.
     *
     * @param {String} str
     * @param {Object} lc
     */
    this.parseLcNum = function(str, lc){
        var sNum = new String(str);
        var aParts = sNum.split(lc.thousandSep);
        sNum = aParts.join("");
        aParts = sNum.split(lc.decimalPoint);
        return (parseFloat(aParts.join(".")));
    }

    /**
     * Returns the URL to a stylized text string containing the requested text
     * and formatted according to the Themes defined in the servlet.
     * NOTE: It is the caller's responsibility to ensure the image is 'fixed' for IE6.
     * @param {String} text
     * @param {String} substyle
     * @param {int} height
     * @param {int} width
     */
    this.getURLforTextImage = function(text, substyle, height, width){
        // TODO: Get the theme from something like wtk.loader.deParametrizeTemplate( "theme", widgetId ) ;
        // (or should each widget need to query for the skin/theme being used?  that seems odd.)
        var skin = urlParamMap["Skin"].toLowerCase();
        log4javascript.getDefaultLogger().debug( "CommUtils: skin = " + skin );
        return __baseClassPath + "text/img.png?theme=" + skin + "." + substyle +
        (height > 0 ? ("&height=" + height) : "") +
        (width > 0 ? ("&width=" + width) : "") +
        "&text=" +
        escape(text).replace("+", "%2B");
    }

    /**
     * Returns an HTML IMG tag &lt;IMG SRC=...&gt; containing the requested text.
     * NOTE: It is the caller's responsibility to ensure the image is 'fixed' for IE6.
     * @param {String} text
     * @param {String} substyle
     * @param {int} height
     * @param {int} width
     */
    this.getHTMLImgForText = function(text, substyle, height, width){
        log4javascript.getDefaultLogger().debug("CommonUtils::getHTMLImgForText(" + text + ",...)");
        return "<IMG SRC=\"" + this.getURLforTextImage(text, substyle, height, width) + "\" " +
        (height > 0 ? (" HEIGHT=\"" + height + "\" ") : "") +
        (width > 0 ? (" WIDTH=\"" + width + "\" ") : "") +
        " ALT=\"" +
        text.replace("\"", "&quot;") +
        "\"/>";
    }

    this.isIE6 = (parseInt(navigator.appVersion.split('MSIE')[1]) <= 6);

    // id property is required
    this.getImgObjectForText = function(text, substyle, height, width){
        log4javascript.getDefaultLogger().debug("CommonUtils::getImgObjectForText(" + text + ",...)");
        var ret = new Image();
        var theurl = this.getURLforTextImage(text, substyle, height, width);
        ret.src = theurl;
        ret.alt = text;
        if (height > 0) {
            ret.height = height;
        }
        if (width > 0) {
            ret.width = width;
        }
        if (this.isIE6) {
            log4javascript.getDefaultLogger().debug("CommonUtils::getImgObjectForText fixing image for IE6");
            // trying to fix - there appears to be some kind of race condition on this one though.
            PNGLoader.attachPNG(ret, theurl, {
                isBackground: false,
                overrideDimensions: false,
                sizingMethod : "crop"
            });
        }
        return ret;
    }

    /**
     * Returns true if the object is defined and NOT null, else false
     * @param {Object} value to be checked
     */
    this.isDefinedAndNotNull = function(value){
        if (typeof value != "undefined" && null != value && 'null' != value) {
            return true;
        }
        else {
            return false;
        }
    }
	
    /**
     * Formats the value passed for display
     * @param value 
     * @param prefix
     * @param suffix
     * @return If the value argument represents a number, then the prefix and suffix are added to it and returned. Otherwise, the
     *         value field is returned as it is.
     */
    this.formatValue = function( /*String or Number*/value, /*String*/prefix, /*String*/suffix ){
        // If it is not an integer, return as it is
        var intVal = parseInt( value );
        if (value != intVal) {
            return value;
        }
        
        // Check if value is not available
        if (intVal < 0) {
            return "NA";
        }
        
        // Get the comma-separated format
        var strVal = new String( intVal );
        var resultStr = "";
        while (strVal.length > 3) {
            var substr = strVal.substr( strVal.length - 3 );
            strVal = strVal.substr( 0, strVal.length - 3 );
            resultStr = "," + substr + resultStr;
        }
        resultStr = strVal + resultStr;
        
        return prefix + resultStr + suffix;
    }

}

var commUtils = new com.forddirect.presentation.wtk.CommonUtils();
//Defining a global locale for the formatted number. This is the default locale used,
//if NO locale is specifically passed to the function
var g_numLocale = new commUtils.locale('.', ',', 0);
/**
 * This file contains the constants to be used in BP2 application widgets.
 */
var Constants = {
    "VehicleName": {
        "Default": "BP2_Pages_VehicleName_Regular",
        "Expanded": "BP2_Pages_VehicleName_Expanded",
        "PowerBar": "BP2_Pages_VehicleName_PowerBar",
        "PrintPage": "BP2_Pages_VehicleName_PrintPage",
        "PreconfigTitle": "BP2_Pages_VehicleName_PreconfigTitle",
        "Short": "BP2_Pages_VehicleName_Short",
        "Compare": "BP2_Pages_VehicleName_Compare",
        "FlipTitle": "BP2_Pages_VehicleName_FlipTitle"
    },
    
    "PaymentEstimator": {
        "Buy": "buy",
        "Lease": "lease"
    },
    
    "PaymentEstimatorFlips": {
        "Buy": "F4.1",
        "Lease": "F4.2"
    },
    
    "Config": {
        "ExteriorBodyColorAttribute": "EXTERIOR_BODY_COLOR",
        "InteriorBodyColorAttribute": "INTERIOR_BODY_COLOR",
        "DEFINER_PAGES": 0,
        "CONFIG_PAGES": 1,
        "PRECONFIG_MISC_PAGES": 2,
        "MISC_PAGES": 3,
        "PRECONFIG_SPLIT_PAGE": 4,
        "PRECONFIG_CONFIG_PAGE": 5
    },
    
    "PartState": {
        "SELECTED": "SELECTED",
        "INCLUDED": "INCLUDED",
        "STANDARD": "STANDARD_PRODUCT",
        "SELECTABLE": "SELECTABLE",
        "EXCLUDED": "EXCLUDED",
        "PRODUCT_EXCLUDED": "PRODUCT_EXCLUDED"
    },
    
    "Inventory": {
        "VehicleImagesSmallAttribute": "BP2_VehicleImages_Inventory_Small",
        "ComingSoonTitleAttribute": "BP2_Copy_Inventory_ComingSoonTitle",
        "ComingSoonSorryTextAttribute": "BP2_Copy_Inventory_ComingSoonSorryText",
        "ComingSoonDealerCanHelpAttribute": "BP2_Copy_Inventory_ComingSoonDealerCanHelp",
        "EmptyEnabledAttribute": "InventoryEmptyEnabled",
        "ComingSoonEnabledAttribute": "InventoryComingSoonEnabled",
        "VehicleNameAttribute": "BP2_Pages_VehicleName_Inventory",
        "EmptyMessageAttribute": "InventoryEmptyMessage",
        "TransmissionsAttribute": "Transmissions",
        "SpecialPackageAttribute": "Special Package",
        "EngineAttribute": "Engine",
        "DefinersClass": "BP2_Pages_Inventory_DefinersClass",
        "SelectedDefiners": "BP2_Pages_Inventory_SelectedDefiners",
        "TruckVehicleType" : "truck"
    },
    
    "Client": {
        "SpeedHighAttribute": "SPEED_HIGH",
        "SpeedLowAttribute": "SPEED_LOW",
        "BWHighAttribute": "BW_HIGH",
        "BWLowAttribute": "BW_LOW",
        "HighAttribute": "HIGH",
        "MediumAttribute": "MEDIUM",
        "LowAttribute": "LOW"
    },
    "PlanDisplayName" : {
        "AZPLAN" : "A/Z Plan",
        "XPLAN" :"X Plan",
        "MSRP" : "MSRP"
    },
    "Pricing": {
        "PriceMSRPAttribute": "PRICE_MSRP",
        "PriceNetMSRPAttribute": "PRICE_NET_MSRP",
        "PriceInvoiceAttribute": "PRICE_INVOICE",
        "AZ_PLAN_LABEL": "A/Z-Plan",
        "X_PLAN_LABEL": "X-Plan",
        "AZ_PLAN_STR": "AZ",
        "X_PLAN_STR": "X"
    },
    
    "Leads": {
        "OVMTCAttributeAttribute": "OVMTC",
        "ReferrerAttribute": "REFERRER",
        "ReferrerUrlAttribute": "REFERRER_URL",
        "ReferingSiteAttribute": "REFERRING_SITE",
        "CampaignIdAttribute": "CAMPAIGN_ID",
        "ReferredOnDateAttribute": "REFERRED_ON_DATE",
        "LeadSourceLinkshareAttribute": "LEAD_SOURCE_LINKSHARE",
        "LeadSourceMyFolderAttribute": "LEAD_SOURCE_MY_FOLDER",
        "LeadSourceFordVehiclesAttribute": "LEAD_SOURCE_FORDVEHICLES",
        "LeadSourceFordComAttribute": "LEAD_SOURCE_FORD_COM",
        "LeadSourceSearchEngineAttribute": "LEAD_SOURCE_SEARCHENGINE",
        "LeadSourceDealerDirectAttribute": "LEAD_SOURCE_DEALERDIRECT",
        "LeadSourceAXZPlanAttribute": "LEAD_SOURCE_AXZPLAN",
        "LeadSourceUnknownAttribute": "LEAD_SOURCE_UNKNOWN",
        "LeadSourceMarketingPartnerAttribute": "LEAD_SOURCE_MARKETINGPARTNER",
        "LeadSourceDealerConnectionAttribute": "LEAD_SOURCE_DEALERCONNECTION",
        "LeadSourceDealerConnectionDirectUrlAttribute": "LEAD_SOURCE_DEALERCONNECTION_DIRECT_URL",
        "LeadSourceFordVehiclesPkgAttribute": "LEAD_SOURCE_FORDVEHICLES_PKG",
        "LinkshareAttribute": "LINKSHARE",
        "FordDotComAttribute": "FORD_DOT_COM",
        "FordVehiclesAttribute": "FORD_VEHICLES",
        "SearchEngineSiteAttribute": "SEARCH_ENGINE_SITE",
        "UnknwonMarketingAffiliateAttribute": "UNKNOWN_MARKETING_AFFILIATE",
        "FordDirectAttribute": "FORDDIRECT",
        "DCSubsourceFordAttribute": "DC_SUBSOURCE_FORD",
        "UnknownSourceAttribute": "UNKNOWN_SOURCE",
        "SkipDealerQuoteType": "FDAF",
        "CommercialTruckVehicleType" : "commercial-truck"
    },
    
    "PreConfig": {
        "ChooseYourPathPreConfigButtonTextAttribute": "BP2_Copy_Pages_ChooseYourPath_PreConfigButtonText",
        "ChooseYourPathPreConfigAssetAttribute": "BP2_Pages_ChooseYourPath_PreConfigAsset",
        "ChooseYourPathPreConfigDescTextAttribute": "BP2_Copy_Pages_ChooseYourPath_PreConfigDescText",
        "ChooseYourPathBuildButtonTextAttribute": "BP2_Copy_Pages_ChooseYourPath_BuildButtonText",
        "ChooseYourPathBuildAssetAttribute": "BP2_Pages_ChooseYourPath_BuildAsset",
        "ChooseYourPathBuildDescTextAttribute": "BP2_Copy_Pages_ChooseYourPath_BuildDescText",
        "PreConfigSelectSubTitleTextAttribute": "BP2_Copy_Pages_PreConfigSelect_SubTitleText",
        "PreConfigSelectPriceTextAttribute": "BP2_Copy_Pages_PreConfigSelect_PriceText",
        "PreConfigSelectNextStepsAttribute": "BP2_Copy_Pages_PreConfigSelect_NextSteps",
        "PreConfigSelectBuildDescTextAttribute": "BP2_Copy_Pages_PreConfigSelect_BuildDescText",
        "PreConfigSelectTitleTextAttribute": "BP2_Copy_Pages_PreConfigSelect_TitleText",
        "PreConfigSelectSearchInventoryAttribute": "BP2_Copy_Pages_PreConfigSelect_SearchInventory",
        "PreConfigSelectBuildButtonTextAttribute": "BP2_Copy_Pages_PreConfigSelect_BuildButtonText",
        "PreConfigSelectWhyBuyCategoriesAttribute": "BP2_Copy_Pages_PreConfigSelect_WhyBuyCategories",
        "PreConfigDetailsTotalInvoiceAttribute": "BP2_Copy_Pages_PreConfigDetails_TotalInvoice",
        "PreConfigDetailsDetailsAttribute": "BP2_Copy_Pages_PreConfigDetails_Details",
        "PreConfigDetailsDestDelAttribute": "BP2_Copy_Pages_PreConfigDetails_DestDel",
        "PreConfigDetailsBasePriceAttribute": "BP2_Copy_Pages_PreConfigDetails_BasePrice",
        "PreConfigDetailsExteriorAttribute": "BP2_Copy_Pages_PreConfigDetails_Exterior",
        "PreConfigDetailsTotalOptionsAttribute": "BP2_Copy_Pages_PreConfigDetails_TotalOptions",
        "PreConfigDetailsSeeWhatsStandardAttribute": "BP2_Copy_Pages_PreConfigDetails_SeeWhatsStandard",
        "PreConfigDetailsMSRPAttribute": "BP2_Copy_Pages_PreConfigDetails_MSRP",
        "PreConfigDetailsSelectYourColorAttribute": "BP2_Copy_Pages_PreConfigDetails_SelectYourColor",
        "PreConfigDetailsPrintSummaryAttribute": "BP2_Copy_Pages_PreConfigDetails_PrintSummary",
        "PreConfigDetailsInteriorAttribute": "BP2_Copy_Pages_PreConfigDetails_Interior",
        "PreConfigDetailsSearchInventoryAttribute": "BP2_Copy_Pages_PreConfigDetails_SearchInventory",
        "PreConfigDetailsExterior_AssetAttribute": "BP2_Pages_PreConfigDetails_Exterior_Asset",
        "PreConfigDetailsInterior_AssetAttribute": "BP2_Pages_PreConfigDetails_Interior_Asset"
    },
    
    "quoteForm_GIP": {
        "SUBMIT_BUTTON_THEME": "QUOTE_MEDIUM_ARROW",
        "SUBMIT_BUTTON_TEXT": "GET AN INTERNET PRICE",
        "SUBMIT_BUTTON_WIDTH": 155
    },
    
    "quoteForm": {
        "SUBMIT_BUTTON_THEME": "LARGE",
        "SUBMIT_BUTTON_TEXT": "SUBMIT",
        "SUBMIT_BUTTON_WIDTH": 132
    },
    
    
    "Common": {
        "DISABLED": "DISABLED",
        "ERROR": "ERROR",
        "UPDATED": "UPDATED",
        "UPDATING": "UPDATING",
        "SELECTED": "SELECTED",
        "INCLUDED": "INCLUDED",
        "COMPLETED": "COMPLETED",
        "TPOLevelAttribute": "TPOLevel",
        "ModelGroupAttribute": "ModelGroup",
        "BodyStyleAttribute": "BodyStyle",
        "ExteriorPartClassPaintTypeAttribute": "Paint Type",
        "InteriorPartClassTrimColourAttribute": "Interior Trim Colour",
        "MultimapURL": "BP2_Settings_MultiMapURL"
    },
    "Compare": {
        "VehicleImagesCompare": "BP2_VehicleImages_Compare",
        "ComparePartClassAttribute": "BP2_Pages_Compare_PartClasses"
    },
    "User": {
        "RegionalOfferImage": "BP2_Pages_Regional_Offers_Asset"
    },
    "LinkinsPageMap" : {
        "QQ2_PAGE_NAME" : "InteractiveQuickQuote",
        "BP2_PAGE_NAME" : "Models",
        "SI2_PAGE_NAME" : "SearchDealerLot",
        "SHOWROOM2_PAGE_NAME_forddirect" : "FDShowroom.jsp",
        "SHOWROOM2_PAGE_NAME" : "Showroom.jsp",
        "FAD2_PAGE_NAME" : "FindADealer",
        "INCENTIVES2_PAGE_NAME" : "IncentivesGrid",
        "USED_VEHICLES_PAGE_NAME" : "dealerdirect/index.jsp",
        "SHOWROOM" : "Showroom.jsp"
    },
    "LinkinsDomainMap" : {
        "BP2_DOMAIN_NAME" : ".ford.com",
        "QQ2_DOMAIN_NAME" : ".quickquote.ford.com",
        "SI2_DOMAIN_NAME" : ".inventory.ford.com",
        "SHOWROOM2_DOMAIN_NAME" : ".showroom.ford.com",
        "FAD2_DOMAIN_NAME" : ".shoppingtools.ford.com",
        
        "INCENTIVES2_DOMAIN_NAME" : ".shoppingtools.ford.com",
        "USED_VEHICLES_DOMAIN_NAME" : ".forddirect.autotrader.com",
        "FAD2_DOMAIN_NAME" : ".shoppingtools.ford.com"    
    },
    "ShoppingTools" : {
        "CONFIG_TARGET" : "config",
        "INVENTORY_TARGET" : "inventory",
        "QUOTE_TARGET" : "quote"
    },
    
    "ContextMap" : {
        "Page ID:M0.0" : ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:M0.1" : ["#1", "#2", "#3", "#4", "#5", "#6"], 
        "Page ID:M0.2" : ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:M1.0" : ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:M2.0" : ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:M3.0" : ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:M4.0" : ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:M5.0" : ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:M6.0" : ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:M7.0" : ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:F1.0" : ["#1", "#2", "#3"],
        "Page ID:F2.1" : ["#1", "#2", "#3"],
        "Page ID:F2.2" : ["#1", "#2", "#3"],
        "Page ID:F2.3" : ["#1", "#2", "#3"],
        "Page ID:F3.1" : ["#1", "#2", "#3"],
        "Page ID:F3.2" : ["#1", "#2", "#3"],
        "Page ID:F3.3" : ["#1", "#2", "#3"],
        "Page ID:F4.1" : ["#1", "#2", "#3", "#8"],
        "Page ID:F4.2" : ["#1", "#2", "#3", "#9", "#11"],
        "Page ID:F4.3" : ["#1", "#2", "#3", "#8"],
        "Page ID:F5.1" : ["#1", "#2", "#3"],
        "Page ID:F5.2" : ["#1", "#2", "#3"],
        "Page ID:F6.0" : ["#1", "#2", "#3"],
        "Page ID:F7.1A": ["#1", "#2", "#3", "#7"],
        "Page ID:F7.1B": ["#1", "#2", "#3", "#7"],
        "Page ID:F7.2": ["#1", "#2", "#3", "#7"],
        "Page ID:F7.3": ["#1", "#2", "#3", "#7"],
        "Page ID:F7.4": ["#1", "#2", "#3", "#7"],
        "Page ID:F7.5": ["#1", "#2", "#3", "#7"],
        "Page ID:F7.6": ["#1", "#2", "#3", "#7"],
        "Page ID:F7.7": ["#1", "#2", "#3", "#7"],
        "Page ID:F8.1": ["#1", "#2", "#3"],
        "Page ID:F8.1.1": ["#1", "#2", "#3"],
        "Page ID:F8.2": ["#1", "#2", "#3"],
        "Page ID:F8.2.1": ["#1", "#2", "#3"],
        "Page ID:F9.1": ["#1", "#2", "#3"],
        "Page ID:F9.2": ["#1", "#2", "#3"],
        "Page ID:F9.3": ["#1", "#2", "#3"],
        "Page ID:F10.1": ["#1", "#2", "#3"],
        "Page ID:F11.1": ["#1", "#2", "#3"],
        "Page ID:F11.3": ["#1", "#2", "#3"],
        "Page ID:F12.0": ["#1", "#2", "#3"],
        "Page ID:F13.0": ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:F13.1": ["#1", "#2", "#3"],
        "Page ID:P1.0": ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:P2.0": ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:P2.1": ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Page ID:P3:0": ["#1", "#2", "#3", "#4", "#5", "#6"],
        "Payment Estimator:Retail/Buy": [],
        "Payment Estimator:Lease Only": [],
        "Payment Estimator:Both": []
    },
    "DisclaimerMap": {
        "#1": {
            "text": 'The \'Net Price\' is the Manufacturer\'s Suggested Retail Price minus any available incentives.',
            "type": ''
        },
        "#2": {
            "text": 'The \'Starting\' price is the Manufacturer\'s Suggested Retail Price (MSRP) of the vehicle. It does <b>not</b> include any taxes, fees or other charges. Pricing and availability may vary based on a variety of factors, including, but not limited to closing fees, document fees, processing fees or any other dealer fees, options, specials and financing qualifications. Consult your dealer for actual price, payments and complete details. Vehicles shown may have optional equipment at additional cost.',
            "type": ''
        },
        "#3": {
            "text": 'Not all buyers will qualify for Ford Credit financing or other offers. Incentives lists are examples of offers available at the time of posting and are subject to change and expiration. Not all incentives can be redeemed together. To take advantage of rebates and/or financing take new retail delivery from dealer stock by the expiration date noted. See dealer for details.',
            "type": ''
        },
        "#4": {
            "text": 'Price and payment shown are mutually exclusive.',
            "type": ''
        },
        "#5": {
            "text": 'Images shown may not necessarily represent the configuarable options selected or available on the vehicle. The manufacturer reserves the right to change product specification, options or prices at any time.',
            "type": ''
        },
        "#6": {
            "text": 'We cannot be responsible for typographical and other errors, including data transmissions or software errors, that may appear on the site. If the posted price, incentive, offer or other service is incorrect due to typographical or other error your local dealer is only responsible for the correct price, incentive or offer. We make every effort to provide you the most accurate, up-to-the-minute information, however it is your responsibility to verify with your local dealer that all details listed are accurate.',
            "type": ''
        },
        "#7": {
            "text": 'While dealer inventory is generally updated on a daily basis, there are no guarantees that the inventory shown will be available at the dealership. Mid-model-year manufacturing changes, as well as dealer-added accessories on the actual vehicle may differ from the options and features listed. Vehicles that are identified as \'Exact Matches\' may have a different price or different features not represented on the site.',
            "type": ''
        },
        "#9": {
            "text": 'The total amount to be paid by the lessee prior to or at signing of the lease or by delivery of the vehicle. The Estimated Amount Due at Lease Signing is after application of all qualifying incentives and rebates. It does not include taxes, title, and/or registration fees. It does include the first month\'s payment, a $595 acquisition fee and any down payment. Security Deposit is waived.',
            "type": ''
        },
        "#10": {
            "text": 'Passenger and load capacity limited by weight and weight distribution.',
            "type": 'dynamic'
        },
        "#11": {
            "text": 'NOT ALL LESSEES WILL QUALIFY FOR THE LOWEST RED CARPET LEASE PAYMENT<p>Lease payment based on Ford Credit Red Carpet Lease. Price and Payments are ESTIMATES ONLY and include Destination and Delivery charges.</p><p>Lease payments will be higher than estimated in Arkansas, Connecticut, Kentucky, Massachusetts, Missouri, North Carolina, Rhode Island,Texas, Virginia, West Virginia.</p><p>The Estimated Amount Due at Lease Signing is after application of incentives and rebates. It does not include taxes, title, and/or registration fees. It does include the first month\'s payment, a $595 acquisition fee and Down Payment. Security Deposit is waived.</p><p>Lessee has the option to purchase vehicle upon lease termination at price negotiated with dealer at lease signing or inception. Lessee is responsible for excess Wear and Use and for Mileage over the \"miles per term allowance\" as stated below:</p><p>$0.15 per mile for vehicles with MSRPs up to $30,000</p><p>$0.20 per mile for vehicles with MSRPs from $30,001 to $49,999</p><p>$0.25 per mile for vehicles with MSRPs over $50,000</p><p>Please Note: ACTUAL PRICE AND PAYMENTS may be different due to local rebates, specials, fees, and credit qualifications.Consult your dealer for actual price, payments and complete details.</p><p>Ford Credit financing may be required for bonus cash offers. Not all buyers will qualify for Ford Credit financing. See dealer for qualifications and complete details. Bonus cash offers displayed on the Payment Estimator are compatible with stand-alone APR, stand-alone customer cash and cash plus APR incentive offers.</p>',
            "type": ''
        }
    },
    "APR_Percentages": [0.0, 0.9, 1.9, 2.9, 3.9, 4.9, 5.9, 6.9, 7.9, 8.9],
    "APR_Months": [36, 48, 60, 72],
    "APR_Rates": [[27.28, 28.16, 28.60, 29.04, 29.48, 29.93, 30.38, 30.83, 31.29, 31.75], [20.83, 21.22, 21.65, 22.09, 22.53, 22.98, 23.44, 23.90, 24.37, 24.84], [16.67, 17.05, 17.48, 17.92, 18.37, 18.83, 19.29, 19.75, 20.23, 20.71], [13.89, 14.27, 14.71, 15.15, 15.60, 16.06, 16.53, 17.00, 17.48, 17.98]],
    "HOMEPAGE_DEFAULT_MODEL": {
        "model": "F-150",
        "year": "2009",
        "make": "Ford"
    },
     "FLOW_LINK": {
        "SHOPPINGTOOLIQQ": "SHOPPINGTOOLIQQ",
        "SHOPPINGTOOLSI": "SHOPPINGTOOLSI",
        "SHOPPINGTOOLBP2": "SHOPPINGTOOLBP2",
        "SHOWROOM2LINK": "SHOWROOM2LINK",
        "FAD2LINK": "FAD2LINK",
        "USEDVEHICLELINK":"USEDVEHICLELINK",
        "INCENTIVELINK":"INCENTIVELINK"
    },
    "PAGE_NAME": {
        "SHOPPINGTOOLIQQ": "InteractiveQuickQuote",
        "SHOPPINGTOOLSI": "ChooseYourPath",
        "SHOPPINGTOOLSI2": "SearchDealerLot",
        "SHOPPINGTOOLBP2": "ChooseYourPath",
        "SHOWROOM2LINK": "FDShowroom.jsp",
        "FAD2LINK" : "FindADealer",
        "USEDVEHICLELINK" : "dealerdirect/index.jsp",
        "INCENTIVELINK" : "IncentivesGrid"
    },
    "SHOWROOM2_FLOW": {
        "SHOPPINGTOOLIQQ": "quote",
        "SHOPPINGTOOLSI": "inventory",
        "SHOPPINGTOOLBP2": "config"
    },
    "HOMEPAGE_IMAGESERVER": {
        "IMAGESERVER": "http://assets.forddirect.fordvehicles.com/assets/"
    },
    "ZIP_CODE_FLOW": {
        "FindADealer": "Search:Dealer",
        "UsedVehicle": "Search:Used:Vehicle"
    },
  
   "SplitModels" : {
      "superduty" : ["F-250","F-350","F-450"],
      "focus" :["sedan","coupe"],
      "eseriesvan" : ["E-150","E-250","E-350"],
      "eseriescutaway" :["E-250","E-350","E-450"],
      "chassiscab" : ["F-350 CC","F-450 CC","F-550"]
   },
   "ShoppingTools" : {
        "CONFIG_TARGET" : "config",
        "INVENTORY_TARGET" : "inventory",
        "QUOTE_TARGET" : "quote"
    },
   "FindADealerContext":{
        "MAX_DEALERS":5,
        "MIN_DEALERS":5
    },
   "SharedDisclaimers":{
        "year" : "2012",
        "model" : "Focus"
    },
   "SI2_URL_FindADealerURL": "http://www.forddirect.com/IncomingPage.jsp?processModel=silent&processZipCode=ToDealerSearch&makeTransition=ToVLSDealerSearch",
   
   "Default_SplitKey" : {
      "superduty" : ["F-250","F-350","F-450"]
      },
//This stores the map of the stateToken to the NGBS Header Enabled or not.
    "NGBS_HEADER_ENABLED_MAP":{
        '/SuperDuty/' : true,
        '/ESeriesVan/' : true,
        '/ESeriesCutaway/' : true,
        '/ChassisCab/' : true,
        '/FindADealer/' :true
   },
    "ModelSplitPageBaseTitle": {
        "superduty": "SELECT YOUR SUPER DUTY",
        "eseriesvan": "BUILD YOUR E-SERIES VAN",
        "eseriescutaway": "BUILD YOUR E-SERIES CUTAWAY",
        "chassiscab": "BUILD YOUR CHASSIS CAB",
        "SUB_TITLE": "CHOOSE YOUR STYLE"
    },
    "ModelSplitPageVehicleLayout":{
        "HEADLIGHT_WIDTH" : 87,
        "HEADLIGHT_HEIGHT" : 87
    }
};
// Generated Code. Please don't edit
getPackageForName( 'com.forddirect.application.bp20.metrics' ).MetricsTracker = function(){
this.trackMacroData = function(pageName){
switch(pageName){
case 'FVDealerships':
   this.FVDealerships();
   break;
case 'VLSFilterAndBrowse':
   this.VLSFilterAndBrowse();
   break;
case 'LastChance':
   this.LastChance();
   break;
case 'VLSCustomerInfo':
   this.VLSCustomerInfo();
   break;
case 'VLSCustomerInfoNonVin':
   this.VLSCustomerInfoNonVin();
   break;
case 'VLSThankYou':
   this.VLSThankYou();
   break;
case 'VLSThankYouNonVin':
   this.VLSThankYouNonVin();
   break;
case 'VLSWindowSticker':
   this.VLSWindowSticker();
   break;
case 'VLSSplitPage':
   this.VLSSplitPage();
   break;
case 'Home':
   this.Home();
   break;
case 'HomeDisclosure':
   this.HomeDisclosure();
   break;
case 'VehicleChangeDealer':
   this.VehicleChangeDealer();
   break;
case 'DealershipsResults':
   this.DealershipsResults();
   break;
case 'ShowroomSelect':
   this.ShowroomSelect();
   break;
default: 
}
}
this.trackMicroData = function(onClickName){
switch(onClickName){
case 'FindDealerMap':
   this.FindDealerMap();
   break;
case 'FindDealerDrivingDirections':
   this.FindDealerDrivingDirections();
   break;
case 'VLSVehicleDetails':
   this.VLSVehicleDetails();
   break;
case 'ReferralExitsFV':
   this.ReferralExitsFV();
   break;
case 'ReferralExitsFMCC':
   this.ReferralExitsFMCC();
   break;
case 'ReferralExitsFR':
   this.ReferralExitsFR();
   break;
case 'ReferralExitsSYNC':
   this.ReferralExitsSYNC();
   break;
case 'ReferralExitsCPO':
   this.ReferralExitsCPO();
   break;
case 'ReferralExitsFLMO':
   this.ReferralExitsFLMO();
   break;
case 'ReferralExitsGENS':
   this.ReferralExitsGENS();
   break;
case 'ReferralExitsGFA':
   this.ReferralExitsGFA();
   break;
case 'ReferralExitsMerchandise':
   this.ReferralExitsMerchandise();
   break;
default: 
}
}
//Start of onPageLoad function calls
this.FVDealerships = function(){
s.pageName = this.getCodeForModel() + 'fv: dealerships: results '+this.namePlate();
//Variables for - Omniture

s.eVar16= this.namePlate();
s.prop16= this.namePlate();
s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.eVar3= this.dealerFDAF();
s.eVar15= this.site();
s.prop15= this.site();
s.campaign= this.bannerID();
s.eVar11='fv: dealerships: results';
s.prop11='fv: dealerships: results';
s.eVar2= this.userFordRegion();
s.eVar1= this.paCode();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar14= this.client();
s.prop14= this.client();

void(s.t());
this.clearVars();
}
this.VLSFilterAndBrowse = function(){
s.pageName = this.getCodeForModel() + 'fv: si: vls: '+this.namePlate();
//Variables for - Omniture

s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.campaign= this.bannerID();
s.eVar2= this.userFordRegion();
s.eVar11='fv: si: vls';
s.prop11='fv: si: vls';
s.eVar35= this.searchDepth();
s.prop21= this.searchDepth();
s.eVar14= this.client();
s.prop14= this.client();
s.eVar16= this.namePlate();
s.prop16= this.namePlate();
s.hier1= this.hierarchy_SI();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar3= this.dealerFDAF();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar1= this.paCode();
s.prop30= this.noOfSearchResult();
s.channel='search inventory';

void(s.t());
this.clearVars();
}
this.LastChance = function(){
s.pageName = this.getCodeForModel() + 'dd: last chance  '+this.namePlate();
//Variables for - Omniture

s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.campaign= this.bannerID();
s.eVar2= this.userFordRegion();
s.eVar11='dd: last chance';
s.prop11='dd: last chance';
s.eVar14= this.client();
s.prop14= this.client();
s.eVar16= this.namePlate();
s.prop16= this.namePlate();
s.hier1='home';
s.eVar15= this.site();
s.prop15= this.site();
s.eVar3= this.dealerFDAF();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar1= this.paCode();
s.prop5='dd: last chance';
s.channel='home';

void(s.t());
this.clearVars();
}
this.VLSCustomerInfo = function(){
s.pageName = this.getCodeForModel() + 'fv: si: vrfq: vls: vin: '+this.namePlate();
//Variables for - Omniture

s.eVar16= this.namePlate();
s.prop16= this.namePlate();
s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.eVar3= this.dealerFDAF();
s.eVar15= this.site();
s.prop15= this.site();
s.campaign= this.bannerID();
s.eVar11='fv: si: vrfq: vls: vin';
s.prop11='fv: si: vrfq: vls: vin';
s.eVar2= this.userFordRegion();
s.eVar1= this.paCode();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar14= this.client();
s.prop14= this.client();
s.hier1= this.hierarchy_GQ();
s.channel='get quote';

void(s.t());
this.clearVars();
}
this.VLSCustomerInfoNonVin = function(){
s.pageName = this.getCodeForModel() + 'fv: si: vrfq: vls: as-built: '+this.namePlate();
//Variables for - Omniture

s.eVar16= this.namePlate();
s.prop16= this.namePlate();
s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.eVar3= this.dealerFDAF();
s.eVar15= this.site();
s.prop15= this.site();
s.campaign= this.bannerID();
s.eVar11='fv: si: vrfq: vls: as-built';
s.prop11='fv: si: vrfq: vls: as-built';
s.eVar2= this.userFordRegion();
s.eVar1= this.paCode();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar14= this.client();
s.prop14= this.client();
s.hier1= this.hierarchy_GQ();
s.channel='get quote';

void(s.t());
this.clearVars();
}
this.VLSThankYou = function(){
s.pageName = this.getCodeForModel() + 'fv: si: vrfq: vls: vin: thank you: '+this.namePlate();
//Variables for - Omniture

s.eVar21= this.vehOptionsPicked();
s.eVar17= this.cksVisitID();
s.eVar24= this.engineTrans();
s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.campaign= this.bannerID();
s.eVar11='fv: si: vrfq: vls: vin: thank you';
s.prop11='fv: si: vrfq: vls: vin: thank you';
s.eVar2= this.userFordRegion();
s.eVar14= this.client();
s.prop14= this.client();
s.eVar28='vrfq: vls: vin';
s.prop18='vrfq: vls: vin';
s.eVar23= this.optionsPkgsPicked();
s.eVar20= this.accessoriesPicked();
s.eVar16= this.namePlate();
s.prop16= this.namePlate();
s.eVar19= this.exteriorInteriorColorCode();
s.prop20='email opt-in full';
s.eVar15= this.site();
s.prop15= this.site();
s.eVar3= this.dealerFDAF();
s.eVar25= this.price();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar1= this.paCode();
s.eVar18= this.bodyModelTrim();
s.hier1= this.hierarchy_GQ();
s.channel='get quote';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.events='event3,event5,event10,event13,'+conditionalEvents;
}else{
s.events='event3,event5,event10,event13';

}void(s.t());
//Events for - DART
dartTracker.trackEvent('gq', this.namePlate());
dartTracker.trackEvent('eopt', this.namePlate());


this.clearVars();
}
this.VLSThankYouNonVin = function(){
s.pageName = this.getCodeForModel() + 'fv: si: vrfq: vls: as-built: thank you: '+this.namePlate();
//Variables for - Omniture

s.eVar21= this.vehOptionsPicked();
s.eVar17= this.cksVisitID();
s.eVar24= this.engineTrans();
s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.campaign= this.bannerID();
s.eVar11='fv: si: vrfq: vls: as-built: thank you';
s.prop11='fv: si: vrfq: vls: as-built: thank you';
s.eVar2= this.userFordRegion();
s.eVar14= this.client();
s.prop14= this.client();
s.eVar28='vrfq: vls: as-built';
s.prop18='vrfq: vls: as-built';
s.eVar23= this.optionsPkgsPicked();
s.eVar20= this.accessoriesPicked();
s.eVar16= this.namePlate();
s.prop16= this.namePlate();
s.eVar19= this.exteriorInteriorColorCode();
s.prop20='email opt-in full';
s.eVar15= this.site();
s.prop15= this.site();
s.eVar3= this.dealerFDAF();
s.eVar25= this.price();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar1= this.paCode();
s.eVar18= this.bodyModelTrim();
s.hier1= this.hierarchy_GQ();
s.channel='quick quote';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.events='event10,event13,event3,'+conditionalEvents;
}else{
s.events='event10,event13,event3';

}void(s.t());
//Events for - DART
dartTracker.trackEvent('eopt', this.namePlate());
dartTracker.trackEvent('gq', this.namePlate());


this.clearVars();
}
this.VLSWindowSticker = function(){
s.pageName = this.getCodeForModel() + 'fv: si: vls: window sticker '+this.namePlate();
//Variables for - Omniture

s.eVar16= this.namePlate();
s.prop16= this.namePlate();
s.hier1= this.hierarchy_SI();
s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.eVar3= this.dealerFDAF();
s.eVar15= this.site();
s.prop15= this.site();
s.campaign= this.bannerID();
s.eVar11='fv: si: vls: window sticker';
s.prop11='fv: si: vls: window sticker';
s.eVar2= this.userFordRegion();
s.eVar1= this.paCode();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar14= this.client();
s.prop14= this.client();
s.channel='search inventory';

void(s.t());
this.clearVars();
}
this.VLSSplitPage = function(){
s.pageName = this.getCodeForModel() + 'fv: si: vls-qq: '+this.namePlate();
//Variables for - Omniture

s.eVar16= this.namePlate();
s.prop16= this.namePlate();
s.hier1= this.hierarchy_SI();
s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.eVar3= this.dealerFDAF();
s.eVar15= this.site();
s.prop15= this.site();
s.campaign= this.bannerID();
s.eVar11='fv: si: vls-qq';
s.prop11='fv: si: vls-qq';
s.eVar2= this.userFordRegion();
s.eVar1= this.paCode();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar14= this.client();
s.prop14= this.client();
s.channel='search inventory';

void(s.t());
this.clearVars();
}
this.Home = function(){
s.pageName = this.getCodeForModel() + 'dd: home '+this.namePlate();
//Variables for - Omniture

s.hier1='home';
s.eVar15= this.site();
s.prop15= this.site();
s.eVar11='dd: home';
s.prop11='dd: home';
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';

void(s.t());
this.clearVars();
}
this.HomeDisclosure = function(){
s.pageName = this.getCodeForModel() + 'dd: home: disclosures '+this.namePlate();
//Variables for - Omniture

s.hier1='home';
s.eVar15= this.site();
s.prop15= this.site();
s.eVar11='dd: home: disclosures';
s.prop11='dd: home: disclosures';
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';

void(s.t());
this.clearVars();
}
this.VehicleChangeDealer = function(){
s.pageName = this.getCodeForModel() + 'fv: vehicle: change dealer '+this.namePlate();
//Variables for - Omniture

s.hier1='shopping tools:locate dealer';
s.eVar15= this.site();
s.prop15= this.site();
s.eVar11='fv: vehicle: change dealer';
s.prop11='fv: vehicle: change dealer';
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar14= this.client();
s.prop14= this.client();
s.channel='dealerships';

void(s.t());
this.clearVars();
}
this.DealershipsResults = function(){
s.pageName = this.getCodeForModel() + 'dd: find dealer: results '+this.namePlate();
//Variables for - Omniture

s.hier1='shopping tools:locate dealer';
s.eVar15= this.site();
s.prop15= this.site();
s.eVar11='dd: find dealer: results';
s.prop11='dd: find dealer: results';
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.pageName='dd: find dealer: results';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='dealerships';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.events='event1,'+conditionalEvents;
}else{
s.events='event1';

}void(s.t());
//Events for - DART
dartTracker.trackEvent('fd', this.namePlate());


this.clearVars();
}
this.ShowroomSelect = function(){
s.pageName = this.getCodeForModel() + 'fv: showroom: vehicle: choose style:  '+this.namePlate();
//Variables for - Omniture

s.eVar16='ford super duty';
s.prop16='ford super duty';
s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar11='fv: showroom: vehicle: choose style';
s.prop11='fv: showroom: vehicle: choose style';
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.pageName='fv: showroom: vehicle: choose style: ford super duty';
s.eVar14= this.client();
s.prop14= this.client();
s.hier1= this.hierarchy_SSP();
s.channel='showroom';

void(s.t());
this.clearVars();
}

//End of onPageLoad function calls
//Start of onClick event function calls
this.FindDealerMap = function(){

//Variables for - Omniture
s.linkTrackVars='hier1,eVar15,prop15,eVar4,prop4,prop5,eVar14,prop14,channel';

s.hier1='shopping tools:locate dealer';
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='fv: find dealer: map';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='dealerships';

s.tl(this,'o','fv: find dealer: map');
this.clearVars();
}
this.FindDealerDrivingDirections = function(){

//Variables for - Omniture
s.linkTrackVars='hier1,eVar15,prop15,eVar4,prop4,prop5,eVar14,prop14,channel';

s.hier1='shopping tools:locate dealer';
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='fv: find dealer: driving directions';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='dealerships';

s.tl(this,'o','fv: find dealer: driving directions');
this.clearVars();
}
this.VLSVehicleDetails = function(){

//Variables for - Omniture
s.linkTrackVars='eVar28,prop18,eVar12,prop12,campaign,eVar2,eVar35,prop21,eVar14,prop14,eVar16,prop16,hier1,eVar15,prop15,eVar3,eVar4,prop4,eVar1,prop30,prop5,channel,events';

s.eVar28= this.leadType_VehicleDetails();
s.prop18= this.leadType_VehicleDetails();
s.eVar12= this.modelYear();
s.prop12= this.modelYear();
s.campaign= this.bannerID();
s.eVar2= this.userFordRegion();
s.eVar35= this.searchDepth();
s.prop21= this.searchDepth();
s.eVar14= this.client();
s.prop14= this.client();
s.eVar16= this.namePlate();
s.prop16= this.namePlate();
s.hier1= this.hierarchy_SI();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar3= this.dealerFDAF();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.eVar1= this.paCode();
s.prop30= this.noOfSearchResult();
s.prop5='vls: vehicle details popup';
s.channel='search inventory';

//Events for - Omniture
var conditionalEvents = '';
var issearchInventory = this.isVehicleUpdated();
if( issearchInventory){
conditionalEvents +='event19,';
}
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.linkTrackEvents=''+conditionalEvents;
s.events=''+conditionalEvents;
}else{
}s.tl(this,'o','fv: vls: vehicle details:');
//Events for - DART
if( issearchInventory){
dartTracker.trackEvent('si', this.namePlate());
}



this.clearVars();
}
this.ReferralExitsFV = function(){

//Variables for - Omniture
s.linkTrackVars='eVar3,prop3,hier1,prop6,eVar6,campaign,eVar15,prop15,eVar4,prop4,prop5,eVar1,prop1,eVar14,prop14,channel,eVar2,prop2,events';

s.eVar3=''+this.dealerFDAF()+'';
s.prop3=''+this.dealerFDAF()+'';
s.hier1='home';
s.prop6='fv: home';
s.eVar6='fv: home';
s.campaign= this.bannerID();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='referral: fv: home';
s.eVar1=''+this.paCode()+'';
s.prop1=''+this.paCode()+'';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';
s.eVar2=''+this.userFordRegion()+'';
s.prop2=''+this.userFordRegion()+'';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.linkTrackEvents='event4,'+conditionalEvents;
s.events='event4,'+conditionalEvents;
}else{
s.linkTrackEvents='event4';
s.events='event4';

}s.tl(this,'o','referral: exit');
//Events for - DART


this.clearVars();
}
this.ReferralExitsFMCC = function(){

//Variables for - Omniture
s.linkTrackVars='eVar3,prop3,hier1,prop6,eVar6,campaign,eVar15,prop15,eVar4,prop4,prop5,eVar1,prop1,eVar14,prop14,channel,eVar2,prop2,events';

s.eVar3=''+this.dealerFDAF()+'';
s.prop3=''+this.dealerFDAF()+'';
s.hier1='home';
s.prop6='fmcc: home';
s.eVar6='fmcc: home';
s.campaign= this.bannerID();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='referral: fmcc: home';
s.eVar1=''+this.paCode()+'';
s.prop1=''+this.paCode()+'';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';
s.eVar2=''+this.userFordRegion()+'';
s.prop2=''+this.userFordRegion()+'';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.linkTrackEvents='event4,'+conditionalEvents;
s.events='event4,'+conditionalEvents;
}else{
s.linkTrackEvents='event4';
s.events='event4';

}s.tl(this,'o','referral: exit');
//Events for - DART


this.clearVars();
}
this.ReferralExitsFR = function(){

//Variables for - Omniture
s.linkTrackVars='eVar3,prop3,hier1,prop6,eVar6,campaign,eVar15,prop15,eVar4,prop4,prop5,eVar1,prop1,eVar14,prop14,channel,eVar2,prop2,events';

s.eVar3=''+this.dealerFDAF()+'';
s.prop3=''+this.dealerFDAF()+'';
s.hier1='home';
s.prop6='ford racing: home';
s.eVar6='ford racing: home';
s.campaign= this.bannerID();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='referral: ford racing: home';
s.eVar1=''+this.paCode()+'';
s.prop1=''+this.paCode()+'';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';
s.eVar2=''+this.userFordRegion()+'';
s.prop2=''+this.userFordRegion()+'';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.linkTrackEvents='event4,'+conditionalEvents;
s.events='event4,'+conditionalEvents;
}else{
s.linkTrackEvents='event4';
s.events='event4';

}s.tl(this,'o','referral: exit');
//Events for - DART


this.clearVars();
}
this.ReferralExitsSYNC = function(){

//Variables for - Omniture
s.linkTrackVars='eVar3,prop3,hier1,prop6,eVar6,campaign,eVar15,prop15,eVar4,prop4,prop5,eVar1,prop1,eVar14,prop14,channel,eVar2,prop2,events';

s.eVar3=''+this.dealerFDAF()+'';
s.prop3=''+this.dealerFDAF()+'';
s.hier1='home';
s.prop6='sync: home';
s.eVar6='sync: home';
s.campaign= this.bannerID();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='referral: sync: home';
s.eVar1=''+this.paCode()+'';
s.prop1=''+this.paCode()+'';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';
s.eVar2=''+this.userFordRegion()+'';
s.prop2=''+this.userFordRegion()+'';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.linkTrackEvents='event4,'+conditionalEvents;
s.events='event4,'+conditionalEvents;
}else{
s.linkTrackEvents='event4';
s.events='event4';

}s.tl(this,'o','referral: exit');
//Events for - DART


this.clearVars();
}
this.ReferralExitsCPO = function(){

//Variables for - Omniture
s.linkTrackVars='eVar3,prop3,hier1,prop6,eVar6,campaign,eVar15,prop15,eVar4,prop4,prop5,eVar1,prop1,eVar14,prop14,channel,eVar2,prop2,events';

s.eVar3=''+this.dealerFDAF()+'';
s.prop3=''+this.dealerFDAF()+'';
s.hier1='home';
s.prop6='cpo: home';
s.eVar6='cpo: home';
s.campaign= this.bannerID();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='referral: cpo: home';
s.eVar1=''+this.paCode()+'';
s.prop1=''+this.paCode()+'';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';
s.eVar2=''+this.userFordRegion()+'';
s.prop2=''+this.userFordRegion()+'';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.linkTrackEvents='event4,'+conditionalEvents;
s.events='event4,'+conditionalEvents;
}else{
s.linkTrackEvents='event4';
s.events='event4';

}s.tl(this,'o','referral: exit');
//Events for - DART


this.clearVars();
}
this.ReferralExitsFLMO = function(){

//Variables for - Omniture
s.linkTrackVars='eVar3,prop3,hier1,prop6,eVar6,campaign,eVar15,prop15,eVar4,prop4,prop5,eVar1,prop1,eVar14,prop14,channel,eVar2,prop2,events';

s.eVar3=''+this.dealerFDAF()+'';
s.prop3=''+this.dealerFDAF()+'';
s.hier1='home';
s.prop6='flmo: home';
s.eVar6='flmo: home';
s.campaign= this.bannerID();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='referral: flmo: home';
s.eVar1=''+this.paCode()+'';
s.prop1=''+this.paCode()+'';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';
s.eVar2=''+this.userFordRegion()+'';
s.prop2=''+this.userFordRegion()+'';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.linkTrackEvents='event4,'+conditionalEvents;
s.events='event4,'+conditionalEvents;
}else{
s.linkTrackEvents='event4';
s.events='event4';

}s.tl(this,'o','referral: exit');
//Events for - DART


this.clearVars();
}
this.ReferralExitsGENS = function(){

//Variables for - Omniture
s.linkTrackVars='eVar3,prop3,hier1,prop6,eVar6,campaign,eVar15,prop15,eVar4,prop4,prop5,eVar1,prop1,eVar14,prop14,channel,eVar2,prop2,events';

s.eVar3=''+this.dealerFDAF()+'';
s.prop3=''+this.dealerFDAF()+'';
s.hier1='home';
s.prop6='gens: home';
s.eVar6='gens: home';
s.campaign= this.bannerID();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='referral: gens: home';
s.eVar1=''+this.paCode()+'';
s.prop1=''+this.paCode()+'';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';
s.eVar2=''+this.userFordRegion()+'';
s.prop2=''+this.userFordRegion()+'';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.linkTrackEvents='event4,'+conditionalEvents;
s.events='event4,'+conditionalEvents;
}else{
s.linkTrackEvents='event4';
s.events='event4';

}s.tl(this,'o','referral: exit');
//Events for - DART


this.clearVars();
}
this.ReferralExitsGFA = function(){

//Variables for - Omniture
s.linkTrackVars='eVar3,prop3,hier1,prop6,eVar6,campaign,eVar15,prop15,eVar4,prop4,prop5,eVar1,prop1,eVar14,prop14,channel,eVar2,prop2,events';

s.eVar3=''+this.dealerFDAF()+'';
s.prop3=''+this.dealerFDAF()+'';
s.hier1='home';
s.prop6='gfa: home';
s.eVar6='gfa: home';
s.campaign= this.bannerID();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='referral: gfa: home';
s.eVar1=''+this.paCode()+'';
s.prop1=''+this.paCode()+'';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';
s.eVar2=''+this.userFordRegion()+'';
s.prop2=''+this.userFordRegion()+'';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.linkTrackEvents='event4,'+conditionalEvents;
s.events='event4,'+conditionalEvents;
}else{
s.linkTrackEvents='event4';
s.events='event4';

}s.tl(this,'o','referral: exit');
//Events for - DART


this.clearVars();
}
this.ReferralExitsMerchandise = function(){

//Variables for - Omniture
s.linkTrackVars='eVar3,prop3,hier1,prop6,eVar6,campaign,eVar15,prop15,eVar4,prop4,prop5,eVar1,prop1,eVar14,prop14,channel,eVar2,prop2,events';

s.eVar3=''+this.dealerFDAF()+'';
s.prop3=''+this.dealerFDAF()+'';
s.hier1='home';
s.prop6='merchandise: home';
s.eVar6='merchandise: home';
s.campaign= this.bannerID();
s.eVar15= this.site();
s.prop15= this.site();
s.eVar4= this.userLanguage();
s.prop4= this.userLanguage();
s.prop5='referral: merchandise: home';
s.eVar1=''+this.paCode()+'';
s.prop1=''+this.paCode()+'';
s.eVar14= this.client();
s.prop14= this.client();
s.channel='home';
s.eVar2=''+this.userFordRegion()+'';
s.prop2=''+this.userFordRegion()+'';

//Events for - Omniture
var conditionalEvents = '';
if( conditionalEvents.length > 0 ){
conditionalEvents = conditionalEvents.substring(0, conditionalEvents.length - 1);

s.linkTrackEvents='event4,'+conditionalEvents;
s.events='event4,'+conditionalEvents;
}else{
s.linkTrackEvents='event4';
s.events='event4';

}s.tl(this,'o','referral: exit');
//Events for - DART


this.clearVars();
}

//End of onClick event function calls
//Start of getters
this.vehOptionsPicked = function(){ 

            
}
this.cksVisitID = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["leadsHandler"])){
                return "";
                }
                var value = wtk.widgetInstances["leadsHandler"].getCKSVisitID();
                if(null != value){
                return value;
                }else{
                return "";
                }
            
}
this.engineTrans = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["searchInventoryContext"])){
                return "";
                }
                var engine = wtk.widgetInstances["searchInventoryContext"].getSelectedEngine();
                var transmission = wtk.widgetInstances["searchInventoryContext"].getSelectedTransmissions();
                if(null != engine && null != transmission){
                return engine + ":" + transmission;
                }else{
                return "";
                }
            
}
this.leadType_VehicleDetails = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["modelContext"])){
                return "";
                }
                var isUpdated = wtk.widgetInstances["modelContext"].isModelUpdated();
                if( isUpdated ){
                return  "si: vls";
                }else{
                return "";
                }
            
}
this.userFordRegion = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["userContext"])){
                return "";
                }
                var value = wtk.widgetInstances["userContext"].getUserMarketingRegion();
                if(null != value){
                return value;
                }else{
                return "";
                }
            
}
this.isVehicleUpdated = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["modelContext"])){
                return "";
                }
                var isUpdated = wtk.widgetInstances["modelContext"].resetModelUpdated();
                if( isUpdated ){
                return  true;
                }else{
                return false;
                }
            
}
this.searchDepth = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["vehiclesGrid"])){
                return "";
                }
                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["searchInventoryContext"])){
                return "";
                }
                var vehicleIndex = wtk.widgetInstances["vehiclesGrid"].getSelectedVehicleNo();
                var vehicleCount = wtk.widgetInstances["searchInventoryContext"].getMatchingVehicleCount();
                if(null != vehicleIndex  && null != vehicleCount){
                return vehicleIndex + ":" + vehicleCount;
                }else{
                return "";
                }
            
}
this.namePlate = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["modelContext"])){
                return "";
                }
                var selectedModel=wtk.widgetInstances["modelContext"].getSelectedModel();
                if(selectedModel){
                var commString = "";
                var isCommVehicle = wtk.widgetInstances["modelContext"].isCommercialMode();
                if (isCommVehicle){
                    commString = "-comm";
                }
                var make = selectedModel.Make;
                var model = selectedModel.ModelName.match(/[A-Z][a-z]*/g).join(" ");
                return (make+" "+model+commString).toLowerCase();
                }else{
                return "";
                }
            
}
this.hierarchy_SI = function(){ 

                return "shopping tools:search inventory - vls:"+this.getVehicleNameCategory()+":"+this.namePlate();
            
}
this.dealerFDAF = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["userContext"])){
                return "";
                }
                var value = wtk.widgetInstances["userContext"].getFDAFRegion();
                if(null != value){
                return value;
                }else{
                return "";
                }
            
}
this.userLanguage = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["userContext"])){
                return "";
                }
                return wtk.widgetInstances["userContext"].getUserLanguage();
            
}
this.paCode = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["DealerContext"])){
                return "";
                }
                /**/
                var selectedDealer = wtk.widgetInstances["DealerContext"].getSelectedDealer();
                var value = "";
                if(null != selectedDealer && typeof selectedDealer != "undefined"){
                if( null != selectedDealer.paCode && typeof selectedDealer.paCode != "undefined"){
                value = selectedDealer.paCode;
                }
                }
                return value;
            
}
this.price = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["searchInventoryContext"])){
                return "";
                }
                var vehicle = wtk.widgetInstances["searchInventoryContext"].getSelectedVehicle();
                if( null != vehicle ){
                return  vehicle.Msrp;
                }else{
                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["modelContext"])){
                return "";
                }
                var model = wtk.widgetInstances["modelContext"].getSelectedModel();
                if(typeof model["Pricing"]["Low"].BaseMSRP != "undefined"){
                return model["Pricing"]["Low"].BaseMSRP;
                }
                return "";
                }
            
}
this.bodyModelTrim = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["searchInventoryContext"])){
                return "";
                }
                var value = wtk.widgetInstances["searchInventoryContext"].getSelectedBodyModel().toLowerCase();
                if(null != value){
                return value;
                }else{
                return "";
                }
            
}
this.noOfSearchResult = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["dealerSelect"])){
                return "";
                }
                var value = wtk.widgetInstances["dealerSelect"].getDealerDropDownNo();
                if(null != value){
                return  "vls: dealer: " + value;
                }else{
                return "";
                }
            
}
this.hierarchy_GQ = function(){ 

                return "shopping tools:get quote:"+this.getVehicleNameCategory()+":"+this.namePlate();
            
}
this.modelYear = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["modelContext"])){
                return "";
                }
                var selectedModel=wtk.widgetInstances["modelContext"].getSelectedModel();
                if(null != selectedModel){
                var value = selectedModel.Year;
                return value;
                }else{
                return "";
                }
            
}
this.bannerID = function(){ 

                var s_campaign = "";
                
                /* 
                    * if the bannerid in the query string is null, check the  cookies for bannerid. If it is there, assign to s_campaign 
                    * variable. if it is not there then find it from urlParamMap and assign to s_campaign variable.
                */
             
                var shared_bannerid = cookieManager.readCookie("bannerID");
                if (shared_bannerid != null && shared_bannerid != "") {
                        s_campaign = shared_bannerid;
                }else{
                    if(commUtils.isDefinedAndNotNull(urlParamMap["bannerID"])){
                        s_campaign  = urlParamMap[paramHelper.URL_MAP_BANNERID];
                    }
                    else{
                        return "";
                    }     
                }
                
                if (browserSessionManager.isCampaignDataToBeSentForThisSession()){
                    return s_campaign;
                }else{
                return "";
                }
            
}
this.client = function(){ 

                return "ford";
            
}
this.hierarchy_SSP = function(){ 

                var commString = "";
                var isCommVehicle = wtk.widgetInstances["modelContext"].isCommercialMode();
                if (isCommVehicle){
                    commString = "-comm";
                }
                return "showroom:"+this.modelYear()+":"+this.getVehicleNameCategory()+":ford super duty"+commString;
            
}
this.accessoriesPicked = function(){ 

            
}
this.optionsPkgsPicked = function(){ 

            
}
this.getVehicleNameCategory = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["modelContext"])){
                return "";
                }
                var value = null;
                var isCommVehicle = wtk.widgetInstances["modelContext"].isCommercialMode();
                if (isCommVehicle){
                    value = Constants.Leads.CommercialTruckVehicleType;
                } else {
                    value = wtk.widgetInstances["modelContext"].getSelectedModelVehicleType();
                }
                if(null != value){
                return value;
                }else{
                return "";
                }
            
}
this.exteriorInteriorColorCode = function(){ 

                if ( !commUtils.isDefinedAndNotNull(wtk.widgetInstances["searchInventoryContext"])){
                return "";
                }
                var value = wtk.widgetInstances["searchInventoryContext"].getSelectedInteriorExteriorColor();
                if(typeof value["Exterior"] != "undefined" && typeof value["Interior"] != "undefined" && null != value["Exterior"].Color && null != value["Interior"].Color){
                return value["Interior"].Color + ":" + value["Exterior"].Color;
                }else{
                return "";
                }
            
}
this.site = function(){ 

                return "fordvehicles.com";
            
}

this.getCodeForModel = function(){
if(urlParamMap['Make']){
   return '';
}
   return '';
}
//End of getters
//Start of clear vars
this.clearVars = function(){
//Clearing Omniture Variables
s.eVar21='';
s.eVar17='';
s.eVar6='';
s.eVar28='';
s.prop18='';
s.eVar24='';
s.eVar11='';
s.prop11='';
s.eVar2='';
s.eVar35='';
s.prop21='';
s.eVar28='';
s.prop18='';
s.eVar3='';
s.prop3='';
s.eVar16='';
s.prop16='';
s.eVar16='';
s.prop16='';
s.hier1='';
s.prop20='';
s.eVar3='';
s.eVar25='';
s.eVar1='';
s.eVar4='';
s.prop4='';
s.eVar18='';
s.prop30='';
s.prop5='';
s.eVar1='';
s.prop1='';
s.channel='';
s.hier1='';
s.prop6='';
s.eVar12='';
s.prop12='';
s.campaign='';
s.eVar14='';
s.prop14='';
s.hier1='';
s.eVar20='';
s.eVar23='';
s.eVar2='';
s.prop2='';
s.hier1='';
s.eVar19='';
s.eVar15='';
s.prop15='';
s.pageName='';
s.linkTrackVars='';
s.events='';
s.linkTrackEvents='';
s.pageName='';
}
}
var metricsTracker = new com.forddirect.application.bp20.metrics.MetricsTracker();/*************************************************************************
 Copyright (C) Unpublished Versata Software, Inc. All rights reserved.
 Versata Software, Inc., Confidential and Proprietary.
 This software is subject to copyright protection
 under the laws of the United States and other countries.
 Unless otherwise explicitly stated, this software is provided
 by Versata "AS IS".
 *************************************************************************/
/**
 * @author Praveen DS
 * @author Aditya Bhatia (Refactored)
 * @version 1.1
 */
/**
 * This downloads the spotlight (aka DART ) pixels.  For details please refer
 * http://wiki.ngptools.com/confluence/download/attachments/32831/FD_Floodlight-Spotlight_Tag_Refresh_eng_req_ver2_073107.doc?version=1
 *
 * We support only javascript enabled browsers, so downloading the pixel can be
 * 1) through AJAX
 * 	ruled out as it is cross-domain and is NOT working
 * 2) through document.write as mentioned in the URL above
 * 	but it clears the page of its DOM and no content which was already present was visible, hence ruled out.
 * 3) Have an iframe in the index.jsp and start using the id of the iframe and set the 'src' attribute in there.
 * 	this works and seems to be an apt solution
 */
getPackageForName("com.forddirect.application.bp20.metrics").DART = function(){
    this.trackEvent = function(templateTags, nameplateValue){
        log4javascript.getDefaultLogger().debug("Spotlight !!");
        var doubleClickElm = document.getElementById("dartTracker");
        if (!doubleClickElm) {
            doubleClickElm = document.createElement("div");
            doubleClickElm.setAttribute('id', "dartTracker");
            document.body.appendChild(doubleClickElm);
        }
        else {
            doubleClickElm.innerHTML = "";
        }
        var dartTagNameArr = templateTags.split(',');
        for (dartTagName in dartTagNameArr) {
            if (dartTagNameArr[dartTagName]) {
                var axel = Math.random() + "";
                var a = axel * 10000000000000;
                var url = this.getSpotlightURL(dartTagNameArr[dartTagName], nameplateValue, a);
                log4javascript.getDefaultLogger().debug("Blocked :: Spotlight URL " + url);
                var dartStatus = this.generate_iframe(doubleClickElm, url, "1px", "1px", "none", "0px");
                log4javascript.getDefaultLogger().debug("Dart Track Event Status = " + dartStatus + " with url= "+url);
            }
        }
    }
    
    this.getSpotlightURL = function(templateTag, nameplateValue, a){
        log4javascript.getDefaultLogger().debug("Inside Spotlight URL ");
        // modfied for 76895 bugfix start
        //return 'http://fls.doubleclick.net/activityi;src=690327;type=fvflup;cat=' + templateTag + ';u1=' + nameplateValue + ';u6=1;ord=' + a + '?';
        return 'http://fls.doubleclick.net/activityi;src=690327;type=fvflup;cat=' + templateTag + ';u1=' + nameplateValue + ';u6=0;ord=' + a + '?';
        // modfied for 76895 bugfix end
    }
    
    /**
     * Creates a DOM (iframe) with the following details
     * @param {Object} id <String> the id of this DOM
     * @param {Object} url <String> the src url
     * @param {Object} height <String> the height of this iframe
     * @param {Object} width <String> the width of this iframe
     * @param {Object} display <String> block|none
     * @param {Object} border <String> the border
     * 
     *The New Dart Source Creates dynamic iframes for each Dart Call and inserts into a div "dartTracker" which is the last child of Body. 
     * But Refactored due to many issue BP-21015,SI-2096(Not supporting Two Dart Tags in a sequence).
     * Old Src taken from:
     * http://www.oreillynet.com/pub/a/javascript/2002/02/08/iframe.html?page=last&x-order=date 
     * http://www.mabaloo.com/Web-Development/Creating-controlling-and-manipulating-an-Iframe-through-JavaScript.html
     */
    this.generate_iframe = function(containerElm, url, height, width, display, border){
        if (!document.createElement) {
            return false;
        }
        else {
            var IFrameObj;
            try {
                IFrameObj = document.createElement("iframe");
                IFrameObj.style.border = border;
                IFrameObj.style.width = width;
                IFrameObj.style.height = height;
                IFrameObj.style.display = display;
                IFrameObj.src = url;
                containerElm.appendChild(IFrameObj);
            } 
            catch (exception) {
                iframeHTML = '\<iframe style="';
                iframeHTML += 'border:' + border;
                iframeHTML += 'width:' + width;
                iframeHTML += 'height:' + height;
                iframeHTML += 'display:' + display;
                iframeHTML += '"><\/iframe>';
                containerElm.innerHTML += iframeHTML;
                IFrameObj = containerElm.lastChild;
                IFrameObj.src = url;
            }
        }
        return true;
    }
}

//The global instance of the ParamHelper
var dartTracker = new com.forddirect.application.bp20.metrics.DART();
/*************************************************************************
 Copyright (C) Unpublished Versata Software, Inc. All rights reserved.
 Versata Software, Inc., Confidential and Proprietary.

 This software is subject to copyright protection
 under the laws of the United States and other countries.

 Unless otherwise explicitly stated, this software is provided
 by Versata "AS IS".

 *************************************************************************/

/**
 * @author Abhishek Joshi
 * @version 1.0
 */

/**
 * This function represents the com.forddirect.presentation.wtk.WidgetToolkit class.
 */
getPackageForName( "com.forddirect.presentation.wtk" ).WidgetToolkit = function()
{

    this.loader = "" ;
    this.initCompleteEvent = new YAHOO.util.CustomEvent( "wtkInitCompleteEvent", null ) ;
    this.widgetInstances = "" ;
    this.widgetTypes = "" ;
    this.path = "" ;
    this.widgetInitCompleteEvents = "";
    this.wtkWidgetEvents = "";

    /**
     * This function initialized the Widget Toolkit. Any function waiting for the successful initialization
     * of the WidgetToolkit should use the event wtk.initCompleteEvent
     */
    this.init = function( )
    {
        log4javascript.getDefaultLogger( ).debug( "WTK::INIT" ) ;
        if( typeof __baseClassPath != "undefined" )
            this.path = __baseClassPath ;
        this.widgetInstances = new Object( ) ;
        this.widgetTypes = new Object( ) ;
        this.widgetInitCompleteEvents = new Object( ) ;
        this.wtkWidgetEvents = new Object( );
        this.loader = new com.forddirect.presentation.wtk.Loader( this ) ;
        //The last parameter is of the classpath for the swf files.
        var loaderInitEvent = this.loader.init( this.path + "static/", this.path + "static/", this.path + "static/",this.path + "flash/" ) ;
        loaderInitEvent.subscribe( this.onLoaderInitComplete ) ;
    }

    //This function is called on successful initialization of the loader instance. Any dependency on the
    //loader instance should execute the logic in this function.
    this.onLoaderInitComplete = function( )
    {
        log4javascript.getDefaultLogger( ).info( "Widget Toolkit class initialized" ) ;
        this.initCompleteEvent.fire( ) ;
    }

    /**
    * This function loads an array of widgets. Each widget should have the following attributes: -
    * 1) widgetClass: The class of the component. for example, com.forddirect.presentation.widgets.config.Config
    * 2) baseDiv: The div in which the component is to be loaded
    * @param {Array} widgets
    * @return an event which signals the successful loading of the group of widgets. The calling function should
    * use the id to index and subscribe to the success event.
    */
    this.loadWidgets = function( widgets, shouldInit, clubWidgets )
    {
        //log4javascript.getDefaultLogger( ).debug( "WTK::loadWidgets" ) ;
        var widgetsDownloadedEvent = this.loader.loadComponents( widgets , shouldInit , clubWidgets) ;

        //If the widgets are to be initialized after downloading, the initWidgets subscribes to
        //the downloadedEvent and the once all the widgets are initialized, the
        //widgetsInitCompletionEvent is fired.
        if( shouldInit )
        {
            var widgetsInitCompleteEvent = new YAHOO.util.CustomEvent("widgetsInitCompleteEvent", this);
            widgetsDownloadedEvent.subscribe( this.initWidgets, {  "widgets" : widgets,"widgetsInitCompleteEvent" : widgetsInitCompleteEvent } ) ;
            return widgetsInitCompleteEvent ;
        }
        return widgetsDownloadedEvent ;
    }

    /**
     * This function listens to the initWidgetsEvent which signals WTK to start the initialization
     * of the widgets. This function initializes the widget by passing the widget initParams along
     * and fires the widgetsInitCompleteEvent on successfully initializing all the widgets.
     *
     * @param {Object} initWidgetsEvent
     * @param {Object} firedData {}
     * @param {Object} subscribedData {'widgetsInitCompleteEvent', 'widgets'}
     */
    this.initWidgets = function( initWidgetsEvent, firedData, subscribedData )
    {
        //log4javascript.getDefaultLogger( ).debug( "WTK::initWidgets" ) ;
        var widgets = subscribedData[ "widgets" ] ;
        var widgetsInitCompleteEvent = subscribedData[ "widgetsInitCompleteEvent" ] ;
        var widget = null ;

        //log4javascript.getDefaultLogger( ).debug( "WTK::" + widgets.length + " widgets to be init" ) ;

        for( var widgetName in widgets ) {
            for (i in widgets[widgetName]) {
                widget = widgets[widgetName][i];
                
                log4javascript.getDefaultLogger().debug("WTK::Initializing " + i + " : " + widget.widgetId);
                
                //widget.constructorParams["widgetLocation"] = widget["widgetLocation"] ;
                if (null == widget.initParams || "undefined" == typeof widget.initParams) {
                    widget.initParams = {};
                }
                widget.isInit = false;
                widget.initParams["widgetId"] = widget["widgetId"];
                widget.initParams["widgetName"] = widget["widgetName"];
                widget.initParams["initCompletionEvent"] = new YAHOO.util.CustomEvent("widgetInitCompleteEvent", this);
                widget.initParams["initCompletionEvent"].subscribe(this.onWidgetInitComplete, {
                    "widgetsInitCompleteEvent": widgetsInitCompleteEvent,
                    "widgets": widgets
                });
                
                if (null == widget["js"] || "undefined" == typeof widget["js"]) {
                    widget.initParams["baseDivId"] = widget["baseDivId"];
                    this.widgetInstances[widget.widgetId] = eval('new ' + widget.widgetClass + '(widget.initParams)');
                }
                else {
                    //log4javascript.getDefaultLogger( ).debug( widget["js"] ) ;
                    eval(widget["js"][widget["widgetName"]]);
                    if ("swf" == widget["type"]) {
                        widget.initParams["src"] = widget["swf"];
                    }
                    else {
                        widget.initParams["baseDivId"] = widget["baseDivId"];
                        widget.initParams["css"] = widget["css"];
                        widget.initParams["html"] = widget["html"];
                        widget.initParams["js"] = widget["js"];
                    }
                    
                    this.widgetInstances[widget.widgetId] = eval('new ' + widget.widgetClass + '(widget.initParams)');
                }
                
                this.widgetTypes[widget.widgetId] = widget["type"];
                log4javascript.getDefaultLogger().debug("WTK::Adding to WidgetInstance " + i + " : " + widget.widgetId);
                this.widgetInstances[widget.widgetId].init(widget.initParams);
                log4javascript.getDefaultLogger().debug("WTK::Added to WidgetInstance " + i + " : " + widget.widgetId);
            }
        }
    }

    /**
     * This event listens to the event initCompletionEvent which the successful initialization
     * of the widget. This function then checks if all the other widgets have been initialized
     * or not. If all widgets are initialized successfully, the widgetsInitCompleteEvent is
     * fired.
     *
     * @param {Object} initCompletionEvent
     * @param {Object} firedData
     * @param {Object} subscribedData
     */
    this.onWidgetInitComplete = function( initCompletionEvent, firedData, subscribedData )
    {
        //log4javascript.getDefaultLogger( ).info( "WTK::" + firedData[0] + " initialized" );
        var widgets = subscribedData['widgets'] ;
        var someWidgetsLeft = false ;

        for(var widgetName in widgets ) {
            for (w in widgets[widgetName]) {
                //Check if the widget that fired the initCompletionEvent is the same as the current
                //widget
                if (firedData[0] == widgets[widgetName][w].widgetId) {
                    widgets[widgetName][w].isInit = true;
                }
                //Check if the current widget is init. If it is NOT init, then set the flag to false
                if (!widgets[widgetName][w].isInit) {
                    someWidgetsLeft = true;
                //log4javascript.getDefaultLogger( ).info( "WTK:: " + widgets[widgetName][w].widgetId + " not initialized" );
                }
            }
        }
        //If at least one widget is left, do NOT fire the widgetsInitCompletionEvent
        if( someWidgetsLeft ){
            return ;
        }
        log4javascript.getDefaultLogger( ).info( "WTK::All widget inits completed" ) ;
        subscribedData['widgetsInitCompleteEvent'].fire( ) ;
    }

    /**
     * This function unloads a widget. It calls loader.unloadWidget to unload it. It then removes the instance of the
     * widget from widgetInstances object.
     * @param widgetId
     * @return success true if succeeds in unloading widget; false otherwise
     */
    this.unload = function(widgetId)
    {
        log4javascript.getDefaultLogger().debug(widgetId + " getting unloaded");
        //find the widget instance in the array
        if(this.widgetInstances[widgetId] != null) {
            var _widget = this.widgetInstances[widgetId];
            //var _baseDivId = (typeof _widget["m_baseDivId"] == "undefined") ? _widget.baseDivId : _widget.m_baseDivId ;
            //this.loader.unload(_baseDivId, widgetId);
            this.widgetInstances[widgetId].unload();
            this.widgetInstances[widgetId] = null;
            this.widgetTypes[widgetId] = null;
            return true;
        } else {
            log4javascript.getDefaultLogger().error(widgetId + " widget not present");
            return false;
        }
    }

}

//The global instance of the Widget Toolkit
var wtk = new com.forddirect.presentation.wtk.WidgetToolkit( ) ;

/**
 * This global function creates and initializes the Widget Toolkit instance
 */
var initWtk = function ( )
{
    wtk.init( ) ;
}

//This statement calls the global function initWtk when the DOM is loaded.
if(typeof wtkLoadOnDomReady == "undefined"){
    YAHOO.util.Event.onDOMReady( initWtk ) ;
}
/**
 * @author Amit Yadav
 * This provides a utility method to load PNG images.
 * The caller code just has to call the fix function with all required paramaters to get this working.
 * Example Usage:
 * PNGLoader.attachPNG(
 *    ponyImg,'/static/com/forddirect/presentation/widgets/ui/internetPrice/images/pony.png', {}
 * );
 * @param {Object} el - dom element to which the image is to be attached.
 * @param {string} url - url path to the image to be loaded
 * @param {Object} params - any additional params that need to be passed. eg {isBackground: true}
 * @constructor
 */
getPackageForName( "com.forddirect.presentation.wtk.util" ).PNGLoader =  {

        /**
         * This checks if the client browser is IE.
         *  if DXImageTransform.Microsoft.AlphaImageLoader
         * method is to be used for loading images in case of IE version less than 6.
         */
        attachPNG : function(el,url,params) {

            if( params.isBackground ) {
                if( commUtils.isIE6 ) {
                    el.style.backgroundImage = "" ;
                    el.style.background = "" ;
                    var sizingMethod = (typeof params.sizingMethod == "undefined") ? "scale" : params.sizingMethod;
                    el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + url + '\', sizingMethod=\'' + sizingMethod + '\')' ;
                } else {
                    el.style.backgroundImage = 'url(' + url + ')' ;
                }
            } else {
                var img = new Image( ) ;
                if( commUtils.isIE6 ) {
                    /* Call the function that will return a reference to the inner function
                       object created in its execution context. Passing the parameters that
                       the inner function will use when it is eventually executed as
                       arguments to the outer function. The returned reference to the inner
                       function object is assigned to a local variable:-
                    */
                    img.onload = this.onLoadRef(this.onLoadAfterTimeOutRef(el, img, url ,params ));

                    img.onerror = this.imgOnError;
                    img.onabort =this.imgOnAbort ;

                } else if( el.tagName == 'IMG' ) {
                    el.src = url ;
                } else {
                    el.appendChild( img ) ;
                }
                img.src = url ;
            }
        },

        imgOnError : function( e ) {
           //ToDo
        },

        imgOnAbort : function( e ) {
            //ToDo
        },

        onLoadAfterTimeOutRef : function(elem, imgObject, src, params){
            /* Return a reference to an anonymous inner function created
               with a function expression:-
            */
            return (function(){
                /* This inner function is to be executed with - setTimeout
                   - and when it is executed it can read, and act upon, the
                   parameters passed to the outer function:-
                */

                //get dimensions of the PNG image
                if( params.overrideDimensions ) {
                    d = {
                        height: params.height,
                        width: params.width
                    }
                } else {
                    d = {
                        height: imgObject.height + 'px',
                        width: imgObject.width + 'px'
                    }
                }
                var sizingMethod = (typeof params.sizingMethod == "undefined") ? "scale" : params.sizingMethod;

                if( elem.tagName == 'IMG' ) {
                    var imgID = ( elem.id ) ? "id='" + elem.id + "' " : "" ;
                    var imgClass = ( elem.className ) ? "class='" + elem.className + "' " : "" ;
                    var imgTitle = ( elem.title ) ? "title='" + elem.title + "' " : "title='" + elem.alt + "' " ;
                    var imgStyle = "display:inline-block;" + elem.style.cssText  ;
                    if ( elem.align == "left" ) imgStyle = "float:left;" + imgStyle ;
                    if ( elem.align == "right" ) imgStyle = "float:right;" + imgStyle ;
                    var strNewHTML = "<span " + imgID + imgClass + imgTitle
                        + " style=\"" + "width:" + d.width + "; height:" + d.height + ";" + imgStyle + ";"
                        + "filter:" + 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\''+ sizingMethod +'\')' + ";\"></span>" ;
                    elem.outerHTML = strNewHTML ;
                } else {
                    var imgStyle = "display:inline-block;" ;
                    var strNewHTML = "<span id=\"PNGLoadedImg\" style=\"" + "width:" + d.width + "; height:" + d.height + ";"
                        + imgStyle + ";filter:" + 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\''+ sizingMethod +'\')'  + ";\"></span>" ;
                    var nodeList = elem.getElementsByTagName('span');
                    var toBeRemovedNode = null;
                    for(var i = 0; i < nodeList.length; i++) {
                        var nodeItem = nodeList[i];
                        if(nodeItem.id == "PNGLoadedImg") {
                            toBeRemovedNode = nodeItem;
                        }
                    }
                    if(toBeRemovedNode != null) {
                        elem.removeChild(toBeRemovedNode);
                    }
                    elem.innerHTML += strNewHTML ;
                }
            });
        },
        onLoadRef : function(functRef){
            return (function(){
                 // HACK: Added timeout so that img node is ready before applying filter.
                    setTimeout(functRef, 50);
                    return null;
            });
        }
    }

var PNGLoader = com.forddirect.presentation.wtk.util.PNGLoader;/**
 * This is the LayoutManager.  Its primary job is to create a div at the appropriate position we wanted to
 */
getPackageForName("com.forddirect.presentation.wtk.util").LayoutManager = function()
{
    this.init = function()
    {
		this.m_buffer = (BrowserDetect.getWindowSize().width- g_siteWidth - 15)/2;
	}
	
	/**
	 * The function returns the new value of x, centered on the page. 
	 * @param {Object} x
	 */
	this.getCenteredX = function(x)
	{
           var buffer = this.getOffset();
           if(buffer > 0 )
           {
              x = parseInt(x) + buffer;
           }
           return x;
	}

	this.m_buffer = 0 ;
    /**
     * TODO: This is the final version once the index.jsp is cleaned up
     * @param {Object} divId
     * @param {Object} x
     * @param {Object} y
     * @param {Object} z
     */
    this.getDivNew = function(divId, x, y, z)
    {
        var div = YAHOO.util.Dom.get(divId);
        if (typeof div != "undefined" && null !== div)
        {
			var styleSTR = "position:absolute; left:" + x + "px; top:" + y + "px; z-index:" + z;
            div.setAttribute("style", styleSTR);
            return div;
        }
        else
        {
			x = this.getCenteredX(x);
		    var styleSTR = "position:absolute; left:" + x + "px; top:" + y + "px; z-index:" + z;
            div = document.createElement("div");
            div.setAttribute("id", divId);
            div.setAttribute("style", styleSTR);
            YAHOO.util.Dom.get("display-div").appendChild(div);
            return div;
        }
    }

   /**
    * This is the hack version for transition which will eventually help cleaning up the index.jsp.
    * @param {Object} parentDivId
    * @param {Object} divId
    * @param {Object} x
    * @param {Object} y
    * @param {Object} z
    */
    this.getDiv = function(parentDivId, divId, x, y, z)
    {
        log4javascript.getDefaultLogger( ).debug( "GETDIV:: BaseDiv " + divId ) ;
		if(null == parentDivId || parentDivId == 'display-div' )
		{
			x = this.getCenteredX(x);
		}
        var styleSTR = "position:absolute; left:" + x + "px; top:" + y + "px; z-index:" + z;

        var div = this.findDiv(parentDivId, divId);

        if(div != null)
        {
            // IE doesn't support style to be applied  by setting the attribute. Hence outerHTML approached is to be applied.
            // However, outerHTML doesn't work with Firefox and other browsers, hence 'setAttribute' method is used.
            if(BrowserDetect.browser == 'Explorer')
            {
                // TODO: Need to verify if this works properly for already existing widgets. Currently there is no such senario in the framework. Also this implementation can cause slight jerkyness.
                div.outerHTML = "<div id='" + divId + "' style='" + styleSTR + "'>" + div.innerHTML + "</div>";
            }else
            {
                div.setAttribute("style", styleSTR);
            }
        }
		log4javascript.getDefaultLogger( ).debug( "GETDIV:: BaseDiv " + divId + " Completed") ;
        // When outerHTML is set, you cann't just return the div object created earlier, hence need to return the newly created dom element.
        return this.findDiv(parentDivId, divId);
    }

   /**
    * This method find the divId in the 'display-div'. And if it doesn't find it, then it searches in the given parentDivId.
    * If the div with given divId is not found, but parentDivId is found, it creates a div and returns it.
    * However if the parentDivId or 'display-div' is also not found, then it returns 'null'
    *
    * @param {Object} parentDivId
    * @param {Object} divId
    */
    this.findDiv = function(parentDivId, divId)
    {
        var __displayDiv = document.getElementById("display-div");
        if (null != parentDivId)
        {
            __displayDiv = document.getElementById(parentDivId);
        }
        var div = null;

        if (null != __displayDiv)
        {
            var childDivs = __displayDiv.getElementsByTagName("div");

            var isBaseDivPresent = false;
            //for( var i in childDivs ) {
            for (var i = 0; i < childDivs.length; i++)
            {
                try
                {
                    if (divId == childDivs[i].getAttribute("id"))
                    {
                        div = childDivs[i];
                        break;
                    }
                }
                catch (e)
                {
                }
            }

            if (null == div)
            {
                var div = document.createElement("div");
                div.setAttribute("id", divId);
                __displayDiv.appendChild(div);
            }
        }
        return div;
    }

	this.getOffset = function(){
		return this.m_buffer;
	}	
}

//The global instance of the LayoutManager
var wtkLayoutManager = new com.forddirect.presentation.wtk.util.LayoutManager();

//The global variable for site width
var g_siteWidth = 960;
wtkLayoutManager.init();
/*************************************************************************
 Copyright (C) Unpublished Versata Software, Inc. All rights reserved.
 Versata Software, Inc., Confidential and Proprietary.
 This software is subject to copyright protection
 under the laws of the United States and other countries.
 Unless otherwise explicitly stated, this software is provided
 by Versata "AS IS".
 *************************************************************************/
/**
 * @author Praveen DS
 * @version 1.0
 */
/**
 * This is a very basic session manager to detect 30 minutes of user inactivity.
 */
getPackageForName("com.forddirect.presentation.wtk.util").BrowserSessionManager = function(){
    /*
     * Mentions whether the session is on or NOT (boolean)
     */
    this.inSession = false;
    this.count = 1;
    this.intervalSet = null;
    this.sessionDurationInSec = 60*30; //30min
    this.isBPStarted = false;
	this.campaignInfoSentForSession = false;
    this.start = function(){
        this.reset(null);
		//TODO: Use YUI here
		YAHOO.util.Event.on(document, 'mousemove', this.reset, this, true);
		YAHOO.util.Event.on(document, 'keydown', this.reset, this, true);
		YAHOO.util.Event.on(document, 'mouseup', this.reset, this, true);
    }
    
	/**
	 * Doesn't work with this as is a callback from setInterval
	 */
    this.updateCount = function(){
        if (!browserSessionManager.inSession) {
            return;
        }
        if (browserSessionManager.sessionDurationInSec <= browserSessionManager.count) {
            browserSessionManager.inSession = false;
            //This might expand to a map if more such variables are needed.
            browserSessionManager.isBPStarted = false;
			browserSessionManager.campaignInfoSentForSession = false;
        } else {
            browserSessionManager.count++;
        }
    }
    
    this.reset = function(e){
        this.count = 1;
        this.inSession = true;
        if (null != this.intervalSet) {
            clearInterval(this.intervalSet);
        }
        this.intervalSet = setInterval(this.updateCount, 1000);
    }
    
    /**
     * TODO:  If in the future more such variables are needed, create a map
     * Used by s.event6 in OMTR tracking
     */
	this.isBPForANewSession = function(){
		if(this.isBPStarted){
			return false;
		}else{
			this.isBPStarted = true;
			return true;
		}
	}
	/*
	 * Used by s.campaign in OMTR tracking
	 */
	this.isCampaignDataToBeSentForThisSession = function(){
		if(this.campaignInfoSentForSession){
			return false;
		}else{
			this.campaignInfoSentForSession = true;
			return true;
		}
	}
}

//The global instance of the BrowserSessionManager
var browserSessionManager = new com.forddirect.presentation.wtk.util.BrowserSessionManager();
browserSessionManager.start();
/**
 * This function represents the com.forddirect.presentation.wtk.CommunicationManager class.
 */
getPackageForName( "com.forddirect.presentation.wtk" ).CommunicationManager = function( )
{
    /**
     * 'this.eventList' is a Dictionary and contains an array of handlers as value for corresponding Event Name as keys
     */
    this.recvList=new Object();
    this.subscriberList=new Object();

    /**
     * Adds and entry of Handler for the events in the this.sendList
     * @param {Object} senderWidgetID - widgetID of the widget that is going to handle the event
     * @param {Object} receiverWidgetID - widgetID of the widget that is going to handle the event
     * @param {Object} receiverWidgetType - type of the receiver widget
     * @param {Object} eventName - Name of the event
     * @param {Object} handler - Name of the handler for the event
     */
    this.subscribe = function( params )
    {
        //Creates a new entry of { widgetID , handler } for adding to the array in the 'this.addThrows'
        //Make sure that there is an entry in the throws before the receiver comes
        var senderWidgetID = params[0];
        var receiverWidgetID = params[1];
        var receiverWidgetType = params[2];
        var eventName = params[3];
        var handler = params[4];
        var context = params[5];
        log4javascript.getDefaultLogger().debug("subscribing to event " + eventName + " from " + senderWidgetID + " receiver:" + receiverWidgetID);

        var key = senderWidgetID + ":" + eventName;
        var yuiEvent = this.recvList[key];
        if(yuiEvent == null ) {
            yuiEvent = new YAHOO.util.CustomEvent( key ) ;
            this.recvList[key] = yuiEvent;
            this.subscriberList[key] = new Object();
        }

        //check if subscribe has already subscribed to the event
        if(receiverWidgetID in this.subscriberList[key]) {
            //log4javascript.getDefaultLogger().debug(receiverWidgetID + " already subscribed to " + key);
            //subscriber already subscribed; Do nothing
        } else {
            var subscribers = this.subscriberList[key];
            //add to the subscribe list
            //and populate subscriberList of the key
            if( "js" == receiverWidgetType || "swf" == receiverWidgetType) {
                //log4javascript.getDefaultLogger().debug("js widget receiever");
            	yuiEvent.subscribe(handler, context);
                subscribers[receiverWidgetID] = receiverWidgetID;
            } else {
                log4javascript.getDefaultLogger().debug("anonymous widget receiever");
            }
        }
        log4javascript.getDefaultLogger().debug("WTCOMM::subscribED to event " + eventName + " from " + senderWidgetID + " receiver:" + receiverWidgetID);
    }

    /**
     * Event to fire an event in a JS or FLASH widget
     * @param {Object} widgetID - ID of the widget that fires the event
     * @param {Object} widgetType - Type of the widget
     * @param {Object} eventName - Name of the event that is to be fired
     */
    this.fire = function(params)
    {
        var senderWidgetID = params[0];
        var senderWidgetType = params[1];
        var eventName = params[2];
        var eventObj = params[3];

        var key = senderWidgetID  + ":" + eventName;
        var yuiEvent = this.recvList[key];
        if(yuiEvent == null)
        {
            log4javascript.getDefaultLogger().debug("No listener configured for the event " + eventName + " from " + senderWidgetID);
            return;
        }

        log4javascript.getDefaultLogger().debug("firing the event " + eventName);
        
        //fire yui event
        yuiEvent.fire(eventObj);
    }

    /**
     * This function gets the name of the movie which is a flash movie.
     *
     * This just makes it browser independent. The way to get the movie by name is different in
     * firefox and microsoft. This handles the same.
     * @param The name of the movie which has been placed on the page. This should correspond to
     * the id being used for the object tag for the flash movie.
     * @return The instance of the movie on the page.
     */
    this.thisMovie = function(movieName)
    {
        if (navigator.appName.indexOf("Microsoft") != -1)
        {
           return window[movieName];
        } else {
            return document[movieName];
        }
    }

    /**
     * This basically initiates the flash instance of the widget on the flash controller.
     * Note: At this point the "init()" method in the equivalent JS file, would have been executing.
     *       This call should be perhaps the last statement in the JS 'init' method.
     *
     * @param widgetId   :String : The ID of the flash widget.
     * @param xVal       :String : X position.
     * @param yVal       :String : Y position.
     * @param depthVal   :String : The depth (z-index) of the flash movie among the other Flash widgets.
     * @param srcVal     :String : The SWF url for the flash movie.
     * @param initParams :String : Initial parameters
     */
    this.addFlashWidget = function(widgetId,xVal,yVal,depthVal,srcVal)
    {
        var subscribedData = new Object();
        subscribedData.widgetId = widgetId;
        subscribedData.xVal = xVal;
        subscribedData.yVal = yVal;
        subscribedData.depthVal = depthVal;
        subscribedData.srcVal = __appBasePath + srcVal;

        /**
         * Variable '__isFlashControllerLoaded' is to be defined at the main page, example: index.jsp , where FlashController is embedded.
         * This is to ensure that variable '__isFlashControllerLoaded' and method '__flashAppInitialized' are available
         * whenever FlashController is initialized. If we place these functions anywhere else in a separate JS file, we run
         * into the condition where those functions are not available, when Flash Controller is initialized.
         */
        if(__isFlashControllerLoaded == false)
        {
            /*
             * If the Flash Controller is not initiated, all the flash widgets to be initialized are subscribed here.
             * Once controller is loaded then, then the subscribed flash widgets are initiated in Flash.
             */
            //log4javascript.getDefaultLogger().debug("Add Flash getting subscribed for widget :" + widgetId);
            wtk.loader.flashControllerLoadEvent.subscribe(this.callAddFlashWidget, subscribedData);
        }else
        {
            // If flash controller is already loaded, then it call the method to load flash object
            this.callAddFlashWidget(null, null, subscribedData);
        }
    }

    /**
     * This method initiates the flash widget loading on the flash controller.
     * This is called when flash controller has been initialized successfully. It assumes that flash controller has
     * been loaded successfully and JS-AS communication is established.
     *
     * It is either passed as event handler method when flash widgets subscribe themselves to the flash controller
     * initiation event, or called directly if controller is already initiated.
     *
     * @param event          String : event that is fired. Not used in the method.
     * @param firedData      String : fired data. This is also ignored in the method.
     * @param subscribedData String : subscribed data. It contains for the relevant information for initiating flash widget.
     */
    this.callAddFlashWidget = function(event, firedData, subscribedData)
    {
        wtkComm.thisMovie('FlashController').addWidget(subscribedData.widgetId, subscribedData.xVal, subscribedData.yVal,
                                            subscribedData.depthVal,subscribedData.srcVal);
    }

    /**
     * This function clears the communication table
     */
    this.unmash = function ()
    {
        for(var key in this.recvList)
        {
            var yuiEvent = this.recvList[key];
            yuiEvent.unsubscribeAll();
            this.recvList[key] = null;
            this.subscriberList[key] = null;
        }

        this.recvList = null;
        this.recvList=new Object();
        this.subscriberList = null;
        this.subscriberList = new Object();
    }
}

//The global instance of the Widget Toolkit
var wtkComm = new com.forddirect.presentation.wtk.CommunicationManager( );
/*************************************************************************
 Copyright (C) Unpublished Versata Software, Inc. All rights reserved.
 Versata Software, Inc., Confidential and Proprietary.
 This software is subject to copyright protection
 under the laws of the United States and other countries.
 Unless otherwise explicitly stated, this software is provided
 by Versata "AS IS".
 *************************************************************************/
/**
 * @author Praveen DS
 * @version 1.0
 */
/**
 * This is a collection of utilities for manipulating the anchor element of BP application
 * in the case of cookies being disabled.
 */
getPackageForName("com.forddirect.presentation.wtk.util").URLUtils = function(){
    this.PAGE_POS = 1;
    this.YEAR_POS = 2;
    this.MAKE_POS = 3;
    this.MODEL_POS = 4;
    this.DEFINERS_POS = 5;
    this.ZIPCODE_POS = 6;
    this.CONF_TOK_POS = 7;
	this.TRANS_POS = 8;
    
    
    /**
     * Any URL which has a '#' in it is a bookmarked URL.
     * Returns true if URL has a '#', false otherwise.
     * @param {Object} url
     */
    this.isBookmarkedURL = function(url){
        return (-1 != url.indexOf("#"));
    }
    
    /**
     * Pathname passed should not have any '/'.  Example
     * http://fordirect.ford.com/Mustang?param1=value1
     * @param {Object} pathname
     */
    this.isShortURL = function(pathname){
        //remove the first / in the pathname ie.  /Mustang/whatever will become Mustang/whatever
        return (-1 == pathname.replace(/\//, "").indexOf("/"));
    }
    
    /**
     * Constructs the URL anchor element without the page info
     * Ex: 2008/Ford/Mustang/Coupe/10001/Config%5B%7CFord%7CMustang%7C2008%7C1%7C1.%7C180A......%7EYZKAA.%5D/Manual
     */
    this.getParametersPathWithoutPageInfo = function(){
        var anchorElement = "";
        if (typeof urlParamMap[paramHelper.URL_MAP_YEAR] == "undefined" || null == urlParamMap[paramHelper.URL_MAP_YEAR]) {
            anchorElement = anchorElement.concat("_");
        } else {
            anchorElement = anchorElement.concat(urlParamMap[paramHelper.URL_MAP_YEAR]);
        }
        
        if (typeof urlParamMap[paramHelper.URL_MAP_MAKE] == "undefined" || null == urlParamMap[paramHelper.URL_MAP_MAKE]) {
            anchorElement = anchorElement.concat("/_");
        } else {
            anchorElement = anchorElement.concat("/", urlParamMap[paramHelper.URL_MAP_MAKE]);
        }
        
        if (typeof urlParamMap[paramHelper.URL_MAP_MODEL] == "undefined" || null == urlParamMap[paramHelper.URL_MAP_MODEL]) {
            anchorElement = anchorElement.concat("/_");
        } else {
            anchorElement = anchorElement.concat("/", urlParamMap[paramHelper.URL_MAP_MODEL]);
        }
        
        if (typeof urlParamMap[paramHelper.URL_MAP_DEFINERS] == "undefined" || null == urlParamMap[paramHelper.URL_MAP_DEFINERS]) {
            anchorElement = anchorElement.concat("/_");
        } else {
            anchorElement = anchorElement.concat("/", urlParamMap[paramHelper.URL_MAP_DEFINERS]);
        }
        
        if (typeof urlParamMap[paramHelper.URL_MAP_ZIPCODE] == "undefined" || null == urlParamMap[paramHelper.URL_MAP_ZIPCODE]) {
            anchorElement = anchorElement.concat("/_");
        } else {
            anchorElement = anchorElement.concat("/", urlParamMap[paramHelper.URL_MAP_ZIPCODE]);
        }
        
        if (typeof urlParamMap[paramHelper.URL_MAP_CONFIGID] == "undefined" || null == urlParamMap[paramHelper.URL_MAP_CONFIGID]) {
            anchorElement = anchorElement.concat("/_");
        } else {
            anchorElement = anchorElement.concat("/", urlParamMap[paramHelper.URL_MAP_CONFIGID]);
        }
        
		if (typeof urlParamMap[paramHelper.URL_MAP_TRANS] == "undefined" || null == urlParamMap[paramHelper.URL_MAP_TRANS]) {
            anchorElement = anchorElement.concat("/_");
        } else {
            anchorElement = anchorElement.concat("/", urlParamMap[paramHelper.URL_MAP_TRANS]);
        }
        return anchorElement;
    }
    
    /**
     * Construct the URL anchor element with page info
     * Ex: /Style/2008/Ford/Mustang/Coupe/10001/Config%5B%7CFord%7CMustang%7C2008%7C1%7C1.%7C180A......%7EYZKAA.%5D/Manual
     */
    this.getParametersPathWithPageInfo = function(){
        var anchorElement = "";
        if (typeof urlParamMap == "undefined" || urlParamMap == null) {
            return "";
        }
        if (typeof urlParamMap[paramHelper.URL_MAP_PAGE] == "undefined" || null == urlParamMap[paramHelper.URL_MAP_PAGE]) {
            anchorElement = anchorElement.concat("/_/");
        } else {
            anchorElement = anchorElement.concat("/", urlParamMap[paramHelper.URL_MAP_PAGE], "/");
        }
        return anchorElement ;
    }
    
    /**
     * Updates the urlParamMap object with the values taken from the anchorElement value that is passed.
     * Note:  the passed string should be of the form 
     * /Style/2008/Ford/Mustang/Coupe/10001/Config%5B%7CFord%7CMustang%7C2008%7C1%7C1.%7C180A......%7EYZKAA.%5D/Manual
     * @param {Object} anchorElement
     */
    this.updateURLParamMapWithAnchorElementValue = function(anchorElement){
        var compArray = anchorElement.split("/");
        if (9 != compArray.length) {
            return false;
        }
        
        if (compArray[this.MAKE_POS] == "_" || compArray[this.MODEL_POS] == "_" || compArray[this.YEAR_POS] == "_" || compArray[this.PAGE_POS] == "_") {
            return false;
        }
        
        urlParamMap[paramHelper.URL_MAP_PAGE] = compArray[this.PAGE_POS];
        urlParamMap[paramHelper.URL_MAP_YEAR] = compArray[this.YEAR_POS];
        urlParamMap[paramHelper.URL_MAP_MAKE] = compArray[this.MAKE_POS];
        urlParamMap[paramHelper.URL_MAP_MODEL] = compArray[this.MODEL_POS];
        
        if (compArray[this.DEFINERS_POS] != "_") {
            urlParamMap[paramHelper.URL_MAP_DEFINERS] = compArray[this.DEFINERS_POS];
        } else {
            urlParamMap[paramHelper.URL_MAP_DEFINERS] = null;
        }
        
        if (compArray[this.TRANS_POS] != "_") {
            urlParamMap[paramHelper.URL_MAP_TRANS] = compArray[this.TRANS_POS];
        } else {
            urlParamMap[paramHelper.URL_MAP_TRANS] = null;
        }
        
        if (compArray[this.CONF_TOK_POS] != "_") {
            urlParamMap[paramHelper.URL_MAP_CONFIGID] = compArray[this.CONF_TOK_POS];
        } else {
            urlParamMap[paramHelper.URL_MAP_CONFIGID] = null;
        }
        
        if (compArray[this.ZIPCODE_POS] != "_") {
            urlParamMap[paramHelper.URL_MAP_ZIPCODE] = compArray[this.ZIPCODE_POS];
        } else {
            urlParamMap[paramHelper.URL_MAP_ZIPCODE] = null;
        }
        
    }
	
	/**
	 * 
	 */
	this.createPathNameFromURLParamMap = function(){
		var pathName = urlParamMap[paramHelper.URL_MAP_PAGE]+'?';
		for(x in urlParamMap){
			if( x === paramHelper.URL_MAP_YEAR  || x === paramHelper.URL_MAP_MAKE  || x === paramHelper.URL_MAP_MODEL  || x === paramHelper.URL_MAP_DEFINERS  || x === paramHelper.URL_MAP_TRANS  || x === paramHelper.URL_MAP_PAGE  || x === paramHelper.URL_MAP_CONFIGID  || x === paramHelper.URL_MAP_ZIPCODE  || x === paramHelper.URL_MAP_SELECT  || x === paramHelper.URL_MAP_UNSELECT ){
				continue;
			}else if( x === 'document_referrer'){
				if(urlParamMap[x])
				pathName += x+'='+escape(urlParamMap[x])+'&'
			}
			else{
				pathName += x+'='+urlParamMap[x]+'&'
			}
		}
		return pathName;
	}
	
/**
 * This function is used to set the StateToken in the case url is of the format http://localhost:8080/#page=/FindADealer/ as the named anchor
 * value is not available on the server side so the correct pageToken has to be set to maintain Correct Header Integration.
 */
this.setStateToken = function(){
    var pageStateToken;
    var pageState = location.href.split('#');
    if (pageState[1]) {
        pageStateTokenArry = pageState[1].split('=');
        if (pageStateTokenArry[1]) {
            pageStateToken = pageStateTokenArry[1].match('/[a-zA-Z]+/');
        }
    }
    if (pageStateToken && pageStateToken[0]) {
        __pathinfo = pageStateToken[0];
    }
}
}


var urlUtils = new com.forddirect.presentation.wtk.util.URLUtils();

/**
 *This function to capture Browser close event
 *for last chance window
 */
var isClosed=false;

function lastChanceWindow(){
    if(commUtils.isDefinedAndNotNull(IS_LCW_ENABLED) && IS_LCW_ENABLED=="true" && paramHelper.getPage() !="LastChanceWindow")
    {
         if(!isClosed || __isPageRefresh){
          __isPageRefresh = false;
            return;
         }
         var params='';
         params = (null==urlParamMap["log4js"]?"":"?log4js="+urlParamMap["log4js"]);
         if(null != urlParamMap[paramHelper.URL_MAP_ZIPCODE]){
            params += (""==params?"?":"&")+'zipCode='+urlParamMap[paramHelper.URL_MAP_ZIPCODE];}
         var URL = LCW2LINK+params;
         window.open( URL, 'LastChance', 'status = 1,menubar=1,toolbar=1, height = 450, width = 730, resizable = 1' );
         metricsTracker.trackMacroData('LastChance');
    }
    else 
    {
        return;
    }
}
var alterffourflag=0;
var lastkey=0;
var refreshflag=0;
var ie7=navigator.userAgent.toLowerCase().indexOf('msie 7')!=-1;
var safari=navigator.userAgent.toLowerCase().indexOf('safari')!=-1;
function doc_onkeydown(e)
{     

    e=(e!=null)?e:window.event;
     if (window.event) // IE
        {
            keynum = e.keyCode;
        }
        else
     if (e.which) // Netscape/Firefox/Opera
       {
           keynum = e.which;
        }
        var numcheck;
        keynum = e.keyCode;
        if(lastkey==18 && keynum==115)
        { 
            alterffourflag=1;
        }
        if(lastkey==17 && keynum==87)
        { 
            alterffourflag=1;
        }
        if(keynum==116)
        {
            refreshflag=1;
        }   
        lastkey=keynum;
    }

document.onkeydown=doc_onkeydown;
function onBeforeunLoadWindow(e){
    
    isClosed=false;
    if(window.event){ //for IE
        if(alterffourflag==1){ 
            //for CTRL+W ,Alt+F4 button
            isClosed=true;                
        }else if(ie7==true){
            //To close the Tab
            if(event.clientY<-10&&event.clientY>-20)
              isClosed=true;
            var offset=0.0;
            var width=0.0;
            if( document.documentElement && ( document.documentElement.clientWidth ))
            {
                width = document.documentElement.clientWidth;
            }
            else if( document.body && ( document.body.offsetWidth))
            {
                width=document.body.offsetWidth;
            } 
            offset=20;
            var diff =width-offset;
            if (refreshflag!=1 && width!=0 && window.event.clientY < 0 && (window.event.clientX > (width - offset))||alterffourflag==1) 
            {
                isClosed=true;            
            }
       }else if(safari)
        {
           if(!__isPageRefresh){
               isClosed=true;}
            onunLoadWindow(e);
        }
        
    }
}
//for IE6 & FF tab close
function onunLoadWindow(e){
    if(window.event && !ie7){ //IE6
        if(window.screenLeft>10003 && window.event.clientX < 0 && window.event.clientY){
            //closed IE6
            isClosed=true;
        }
    }else if(e!=null && e.target==null && !ie7){ //FF
            //for FF Tab
            isClosed=true;
    }else if((window.screenX < 0) && (window.screenY <0 ) && refreshflag!=1){
        //for FF close;
        isClosed=true;
    }
    // show last chance window
    lastChanceWindow();
}
if (window.addEventListener) {
    //Mozilla
    document.addEventListener('keydown', doc_onkeydown, true);
    window.addEventListener('beforeunload', onBeforeunLoadWindow, false);
    window.addEventListener('unload', onunLoadWindow, false);
}else if(window.attachEvent){
    //IE/Opera.
    document.attachEvent('onkeypress', doc_onkeydown);
    window.attachEvent('onbeforeunload', onBeforeunLoadWindow);
    window.attachEvent('onunload', onunLoadWindow);
}/*
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
*/
/**
 * Utilities for cookie management
 * @namespace YAHOO.util
 * @module cookie
 * @beta
 */
YAHOO.namespace("util");

/**
 * Cookie utility.
 * @class Cookie
 * @static
 */
YAHOO.util.Cookie = {
    
    //-------------------------------------------------------------------------
    // Private Methods
    //-------------------------------------------------------------------------
    
    /**
     * Creates a cookie string that can be assigned into document.cookie.
     * @param {String} name The name of the cookie.
     * @param {String} value The value of the cookie.
     * @param {encodeValue} encodeValue True to encode the value, false to leave as-is.
     * @param {Object} options (Optional) Options for the cookie.
     * @return {String} The formatted cookie string.
     * @method _createCookieString
     * @private
     * @static
     */
    _createCookieString : function (name /*:String*/, value /*:Variant*/, encodeValue /*:Boolean*/, options /*:Object*/) /*:String*/ {
    
        //shortcut
        var lang = YAHOO.lang;
    
        var text /*:String*/ = encodeURIComponent(name) + "=" + (encodeValue ? encodeURIComponent(value) : value);
        
    
        if (lang.isObject(options)){
            //expiration date
            if (options.expires instanceof Date){
                text += "; expires=" + options.expires.toGMTString();
            }
        
            //path
            if (lang.isString(options.path) && options.path != ""){
                text += "; path=" + options.path;
            }
    
            //domain
            if (lang.isString(options.domain) && options.domain != ""){
                text += "; domain=" + options.domain;
            }
            
            //secure
            if (options.secure === true){
                text += "; secure";
            }
        }
        
        return text;
    },
    
    /**
     * Formats a cookie value for an object containing multiple values.
     * @param {Object} hash An object of key-value pairs to create a string for.
     * @return {String} A string suitable for use as a cookie value.
     * @method _createCookieHash
     * @private
     * @static
     */
    _createCookieHashString : function (hash /*:Object*/) /*:String*/ {
        
        //shortcuts
        var lang = YAHOO.lang;
        
        if (!lang.isObject(hash)){
            throw new TypeError("Cookie._createCookieHashString(): Argument must be an object.");
        }
        
        var text /*:Array*/ = new Array();
        
        for (var key in hash){
            if (lang.hasOwnProperty(hash, key) && !lang.isFunction(hash[key]) && !lang.isUndefined(hash[key])){
                text.push(encodeURIComponent(key) + "=" + encodeURIComponent(String(hash[key])));
            }
        }
        
        return text.join("&");
    },
    
    /**
     * Parses a cookie hash string into an object.
     * @param {String} text The cookie hash string to parse. The string should already be URL-decoded.
     * @return {Object} An object containing entries for each cookie value.
     * @method _parseCookieHash
     * @private
     * @static
     */
    _parseCookieHash : function (text /*:String*/) /*:Object*/ {
    
        var hashParts /*:Array*/ = text.split("&");
        var hashPart /*:Array*/ = null;
        var hash /*:Object*/ = new Object();
        
        for (var i=0, len=hashParts.length; i < len; i++){
            hashPart = hashParts[i].split("=");
            hash[decodeURIComponent(hashPart[0])] = decodeURIComponent(hashPart[1]);
        }
        
        return hash;
    },    
    
    /**
     * Parses a cookie string into an object representing all accessible cookies.
     * @param {String} text The cookie string to parse.
     * @param {Boolean} decode (Optional) Indicates if the cookie values should be decoded or not. Default is true.
     * @return {Object} An object containing entries for each accessible cookie.
     * @method _parseCookieString
     * @private
     * @static
     */
    _parseCookieString : function (text /*:String*/, decode /*:Boolean*/) /*:Object*/ {
    
        var cookies /*:Object*/ = new Object();        
        
        if (YAHOO.lang.isString(text) && text.length > 0) {
        
            var decodeValue = (decode === false ? function(s){return s;} : decodeURIComponent);
        
            if (/[^=]+=[^=;]?(?:; [^=]+=[^=]?)?/.test(text)){            
                var cookieParts /*:Array*/ = text.split(/;\s/g);
                var cookieName /*:String*/ = null;
                var cookieValue /*:String*/ = null;
                var cookieNameValue /*:Array*/ = null;
                
                for (var i=0, len=cookieParts.length; i < len; i++){
                
                    //check for normally-formatted cookie (name-value)
                    cookieNameValue = cookieParts[i].match(/([^=]+)=/i);
                    if (cookieNameValue instanceof Array){
                        cookieName = decodeURIComponent(cookieNameValue[1]);
                        cookieValue = decodeValue(cookieParts[i].substring(cookieName.length+1));
                    } else {
                        //means the cookie does not have an "=", so treat it as a boolean flag
                        cookieName = decodeURIComponent(cookieParts[i]);
                        cookieValue = cookieName;
                    }
                    cookies[cookieName] = cookieValue;
                }
            }
        }
        
        return cookies;
    },    
    
    //-------------------------------------------------------------------------
    // Public Methods
    //-------------------------------------------------------------------------

    /**
     * Returns the cookie value for the given name.
     * @param {String} name The name of the cookie to retrieve.
     * @param {Function} converter (Optional) A function to run on the value before returning
     *      it. The function is not used if the cookie doesn't exist.
     * @return {Variant} If no converter is specified, returns a string or null if
     *      the cookie doesn't exist. If the converter is specified, returns the value
     *      returned from the converter or null if the cookie doesn't exist.
     * @method get
     * @static
     */
    get : function (name /*:String*/, converter /*:Function*/) /*:Variant*/{
        
        var lang = YAHOO.lang;
        var cookies /*:Object*/ = this._parseCookieString(document.cookie);        
        
        if (!lang.isString(name) || name === ""){
            throw new TypeError("Cookie.get(): Cookie name must be a non-empty string.");
        }
        
        if (lang.isUndefined(cookies[name])) {
            return null;
        }
        
        if (!lang.isFunction(converter)){
            return cookies[name];
        } else {
            return converter(cookies[name]);
        }
    },
    
    /**
     * Returns the value of a subcookie.
     * @param {String} name The name of the cookie to retrieve.
     * @param {String} subName The name of the subcookie to retrieve.
     * @param {Function} converter (Optional) A function to run on the value before returning
     *      it. The function is not used if the cookie doesn't exist.
     * @return {Variant} If the cookie doesn't exist, null is returned. If the subcookie
     *      doesn't exist, null if also returned. If no converter is specified and the
     *      subcookie exists, a string is returned. If a converter is specified and the
     *      subcookie exists, the value returned from the converter is returned.
     * @method getSub
     * @static
     */
    getSub : function (name /*:String*/, subName /*:String*/, converter /*:Function*/) /*:Variant*/ {
    
        var lang = YAHOO.lang;    
        var hash /*:Variant*/ = this.getSubs(name);  

        if (hash !== null) {
            
            if (!lang.isString(subName) || subName === ""){
                throw new TypeError("Cookie.getSub(): Subcookie name must be a non-empty string.");
            }
            
            if (lang.isUndefined(hash[subName])){
                return null;
            }            
        
            if (!lang.isFunction(converter)){
                return hash[subName];
            } else {
                return converter(hash[subName]);
            }
        } else {
            return null;
        }
    
    },
    
    /**
     * Returns an object containing name-value pairs stored in the cookie with the given name.
     * @param {String} name The name of the cookie to retrieve.
     * @return {Object} An object of name-value pairs if the cookie with the given name
     *      exists, null if it does not.
     * @method getHash
     * @static
     */
    getSubs : function (name /*:String*/) /*:Object*/ {
        
        //check cookie name
        if (!YAHOO.lang.isString(name) || name === ""){
            throw new TypeError("Cookie.getSubs(): Cookie name must be a non-empty string.");
        }
        
        var cookies = this._parseCookieString(document.cookie, false);
        if (YAHOO.lang.isString(cookies[name])){
            return this._parseCookieHash(cookies[name]);
        }
        return null;
    },
    
    /**
     * Removes a cookie from the machine by setting its expiration date to
     * sometime in the past.
     * @param {String} name The name of the cookie to remove.
     * @param {Object} options (Optional) An object containing one or more
     *      cookie options: path (a string), domain (a string), 
     *      and secure (true/false). The expires option will be overwritten
     *      by the method.
     * @return {String} The created cookie string.
     * @method remove
     * @static
     */
    remove : function (name /*:String*/, options /*:Object*/) /*:String*/ {
        
        //check cookie name
        if (!YAHOO.lang.isString(name) || name === ""){
            throw new TypeError("Cookie.remove(): Cookie name must be a non-empty string.");
        }
        
        //set options
        options = options || {};
        options.expires = new Date(0);
        
        //set cookie
        return this.set(name, "", options);
    },

    /**
     * Sets a cookie with a given name and value.
     * @param {String} name The name of the cookie to set.
     * @param {Variant} value The value to set for the cookie.
     * @param {Object} options (Optional) An object containing one or more
     *      cookie options: path (a string), domain (a string), expires (a Date object),
     *      and secure (true/false).
     * @return {String} The created cookie string.
     * @method set
     * @static
     */
    set : function (name /*:String*/, value /*:Variant*/, options /*:Object*/) /*:String*/ {
    
        var lang = YAHOO.lang;
    
        if (!lang.isString(name)){
            throw new TypeError("Cookie.set(): Cookie name must be a string.");
        }
        
        if (lang.isUndefined(value)){
            throw new TypeError("Cookie.set(): Value cannot be undefined.");
        }
        
    
        var text /*:String*/ = this._createCookieString(name, value, true, options);
        document.cookie = text;
        return text;
    },
        
    /**
     * Sets a sub cookie with a given name to a particular value.
     * @param {String} name The name of the cookie to set.
     * @param {String} subName The name of the subcookie to set.
     * @param {Variant} value The value to set.
     * @param {Object} options (Optional) An object containing one or more
     *      cookie options: path (a string), domain (a string), expires (a Date object),
     *      and secure (true/false).
     * @return {String} The created cookie string.
     * @method setSub
     * @static
     */
    setSub : function (name /*:String*/, subName /*:String*/, value /*:Variant*/, options /*:Object*/) /*:String*/ {
        
        var lang = YAHOO.lang;

        if (!lang.isString(name) || name === ""){
            throw new TypeError("Cookie.setSub(): Cookie name must be a non-empty string.");
        }

        if (!lang.isString(subName) || subName === ""){
            throw new TypeError("Cookie.setSub(): Subcookie name must be a non-empty string.");
        }
        
        if (lang.isUndefined(value)){
            throw new TypeError("Cookie.setSub(): Subcookie value cannot be undefined.");
        }

        var hash /*:Object*/ = this.getSubs(name);
        
        if (!lang.isObject(hash)){
            hash = new Object();
        }
        
        hash[subName] = value;        
        
        return this.setSubs(name, hash, options);
        
    },
    
    /**
     * Sets a cookie with a given name to contain a hash of name-value pairs.
     * @param {String} name The name of the cookie to set.
     * @param {Object} value An object containing name-value pairs.
     * @param {Object} options (Optional) An object containing one or more
     *      cookie options: path (a string), domain (a string), expires (a Date object),
     *      and secure (true/false).
     * @return {String} The created cookie string.
     * @method setSubs
     * @static
     */
    setSubs : function (name /*:String*/, value /*:Object*/, options /*:Object*/) /*:String*/ {
        
        var lang = YAHOO.lang;
        
        if (!lang.isString(name)){
            throw new TypeError("Cookie.setSubs(): Cookie name must be a string.");
        }
        
        if (!lang.isObject(value)){
            throw new TypeError("Cookie.setSubs(): Cookie value must be an object.");
        }
    
        var text /*:String*/ = this._createCookieString(name, this._createCookieHashString(value), false, options);
        document.cookie = text;
        return text;        
    }    

};

YAHOO.register("cookie", YAHOO.util.Cookie, {version: "2.5.2", build: "1076"});
/**
 * This is the CookieManager.  Its primary job is to create a cookie by given name n details
 * @author sdua
 * @author Praveen DS
 */
getPackageForName("com.forddirect.presentation.wtk.util").CookieManager = function(){
    this.isCookieEnabled = false;
    this.init = function(){
        var testCookieValue = 'fdtestCookie' + Math.round(Math.random() * Math.PI * 1000);
        YAHOO.util.Cookie.set("example", testCookieValue);
        var value = YAHOO.util.Cookie.get("example");
        if (null == value) {
            this.isCookieEnabled = false;
        } else if (value === testCookieValue) {
            this.isCookieEnabled = true;
        } else {
            this.isCookieEnabled = false;
        }
        YAHOO.util.Cookie.remove("example");
    }

    /**
     * this method creates a cookie given the cookie name, value and extra optional parameters.
     * @param {Object} name - the name of the cooke.
     * @param {Object} value - value for the cookie to be set.
     * @param {Object} params - optional cookie parameters such as path (a string), domain (a string),
     * expires (a Date object), and secure (true/false).
     */
    this.createCookie = function(name, value, params){
        log4javascript.getDefaultLogger().debug("CookieManager:: Cookie( " + name + " ) = " + value);
        if (null != params && typeof params != 'undefined') {
            YAHOO.util.Cookie.set(unescape(name), unescape(value), params);
        } else {
            YAHOO.util.Cookie.set(unescape(name), unescape(value));
        }
    }

    this.setSubs = function(name, value, params){
        log4javascript.getDefaultLogger().debug("CookieManager:: Sub - Cookie( " + name + " ) = " + value);
        if (null != params && typeof params != 'undefined') {
            YAHOO.util.Cookie.setSubs(name, value, params);
        } else {
            YAHOO.util.Cookie.setSubs(name, value);
        }
    }

    this.setSub = function(name, subname, value, params){
        log4javascript.getDefaultLogger().debug("CookieManager:: Sub - Cookie( " + name + " ) = " + value);
        if (null != params && typeof params != 'undefined') {
            YAHOO.util.Cookie.setSub(name, subname, value, params);
        } else {
            YAHOO.util.Cookie.setSub(name, subname, value);
        }
    }

    /**
     * this method reads a cookie given its name
     * @param {Object} name - name of the cookie to be read
     * @param {Object} conversion - Optional param. A function to run on the value before returning it.
     * The function is not used if the cookie doesn't exist.
     */
    this.readCookie = function(name, conversion){
        log4javascript.getDefaultLogger().debug("CookieManager:: Entering readCookie");
        if (null != conversion && typeof conversion != 'undefined') {
            return YAHOO.util.Cookie.get(name, conversion);
        } else {
            return YAHOO.util.Cookie.get(name);
        }
    }

    this.getSubs = function(name){
        log4javascript.getDefaultLogger().debug("CookieManager:: Entering readSubs");
        return YAHOO.util.Cookie.getSubs(name);
    }

    this.getSub = function(name, subname){
        log4javascript.getDefaultLogger().debug("CookieManager:: Entering readSubs");
        return YAHOO.util.Cookie.getSub(name, subname);
    }

    /**
     * Removes a cookie from the machine by setting its expiration date to sometime in the past.
     * @param {Object} name <String>  The name of the cookie to remove.
     * @param {Object} options <Object>  (Optional) An object containing one or more cookie options: path (a string), domain (a string),
     * and secure (true/false). The expires option will be overwritten by the method.
     */
    this.removeCookie = function(name, options){
        if(null != options){
            return YAHOO.util.Cookie.remove(name, options);
        }else{
            return YAHOO.util.Cookie.remove(name);
        }
    }
}

//The global instance of the CookieManager
var cookieManager = new com.forddirect.presentation.wtk.util.CookieManager();
/**
 * This function represents the com.forddirect.presentation.wtk.CommunicationManager class.
 */
getPackageForName( "com.forddirect.presentation.wtk" ).CommunicationManager = function( )
{
    /**
     * 'this.eventList' is a Dictionary and contains an array of handlers as value for corresponding Event Name as keys
     */
    this.recvList=new Object();
    this.subscriberList=new Object();

    /**
     * Adds and entry of Handler for the events in the this.sendList
     * @param {Object} senderWidgetID - widgetID of the widget that is going to handle the event
     * @param {Object} receiverWidgetID - widgetID of the widget that is going to handle the event
     * @param {Object} receiverWidgetType - type of the receiver widget
     * @param {Object} eventName - Name of the event
     * @param {Object} handler - Name of the handler for the event
     */
    this.subscribe = function( params )
    {
        //Creates a new entry of { widgetID , handler } for adding to the array in the 'this.addThrows'
        //Make sure that there is an entry in the throws before the receiver comes
        var senderWidgetID = params[0];
        var receiverWidgetID = params[1];
        var receiverWidgetType = params[2];
        var eventName = params[3];
        var handler = params[4];
        var context = params[5];
        log4javascript.getDefaultLogger().debug("subscribing to event " + eventName + " from " + senderWidgetID + " receiver:" + receiverWidgetID);

        var key = senderWidgetID + ":" + eventName;
        var yuiEvent = this.recvList[key];
        if(yuiEvent == null ) {
            yuiEvent = new YAHOO.util.CustomEvent( key ) ;
            this.recvList[key] = yuiEvent;
            this.subscriberList[key] = new Object();
        }

        //check if subscribe has already subscribed to the event
        if(receiverWidgetID in this.subscriberList[key]) {
            //log4javascript.getDefaultLogger().debug(receiverWidgetID + " already subscribed to " + key);
            //subscriber already subscribed; Do nothing
        } else {
            var subscribers = this.subscriberList[key];
            //add to the subscribe list
            //and populate subscriberList of the key
            if( "js" == receiverWidgetType || "swf" == receiverWidgetType) {
                //log4javascript.getDefaultLogger().debug("js widget receiever");
            	yuiEvent.subscribe(handler, context);
                subscribers[receiverWidgetID] = receiverWidgetID;
            } else {
                log4javascript.getDefaultLogger().debug("anonymous widget receiever");
            }
        }
        log4javascript.getDefaultLogger().debug("WTCOMM::subscribED to event " + eventName + " from " + senderWidgetID + " receiver:" + receiverWidgetID);
    }

    /**
     * Event to fire an event in a JS or FLASH widget
     * @param {Object} widgetID - ID of the widget that fires the event
     * @param {Object} widgetType - Type of the widget
     * @param {Object} eventName - Name of the event that is to be fired
     */
    this.fire = function(params)
    {
        var senderWidgetID = params[0];
        var senderWidgetType = params[1];
        var eventName = params[2];
        var eventObj = params[3];

        var key = senderWidgetID  + ":" + eventName;
        var yuiEvent = this.recvList[key];
        if(yuiEvent == null)
        {
            log4javascript.getDefaultLogger().debug("No listener configured for the event " + eventName + " from " + senderWidgetID);
            return;
        }

        log4javascript.getDefaultLogger().debug("firing the event " + eventName);
        
        //fire yui event
        yuiEvent.fire(eventObj);
    }

    /**
     * This function gets the name of the movie which is a flash movie.
     *
     * This just makes it browser independent. The way to get the movie by name is different in
     * firefox and microsoft. This handles the same.
     * @param The name of the movie which has been placed on the page. This should correspond to
     * the id being used for the object tag for the flash movie.
     * @return The instance of the movie on the page.
     */
    this.thisMovie = function(movieName)
    {
        if (navigator.appName.indexOf("Microsoft") != -1)
        {
           return window[movieName];
        } else {
            return document[movieName];
        }
    }

    /**
     * This basically initiates the flash instance of the widget on the flash controller.
     * Note: At this point the "init()" method in the equivalent JS file, would have been executing.
     *       This call should be perhaps the last statement in the JS 'init' method.
     *
     * @param widgetId   :String : The ID of the flash widget.
     * @param xVal       :String : X position.
     * @param yVal       :String : Y position.
     * @param depthVal   :String : The depth (z-index) of the flash movie among the other Flash widgets.
     * @param srcVal     :String : The SWF url for the flash movie.
     * @param initParams :String : Initial parameters
     */
    this.addFlashWidget = function(widgetId,xVal,yVal,depthVal,srcVal)
    {
        var subscribedData = new Object();
        subscribedData.widgetId = widgetId;
        subscribedData.xVal = xVal;
        subscribedData.yVal = yVal;
        subscribedData.depthVal = depthVal;
        subscribedData.srcVal = __appBasePath + srcVal;

        /**
         * Variable '__isFlashControllerLoaded' is to be defined at the main page, example: index.jsp , where FlashController is embedded.
         * This is to ensure that variable '__isFlashControllerLoaded' and method '__flashAppInitialized' are available
         * whenever FlashController is initialized. If we place these functions anywhere else in a separate JS file, we run
         * into the condition where those functions are not available, when Flash Controller is initialized.
         */
        if(__isFlashControllerLoaded == false)
        {
            /*
             * If the Flash Controller is not initiated, all the flash widgets to be initialized are subscribed here.
             * Once controller is loaded then, then the subscribed flash widgets are initiated in Flash.
             */
            //log4javascript.getDefaultLogger().debug("Add Flash getting subscribed for widget :" + widgetId);
            wtk.loader.flashControllerLoadEvent.subscribe(this.callAddFlashWidget, subscribedData);
        }else
        {
            // If flash controller is already loaded, then it call the method to load flash object
            this.callAddFlashWidget(null, null, subscribedData);
        }
    }

    /**
     * This method initiates the flash widget loading on the flash controller.
     * This is called when flash controller has been initialized successfully. It assumes that flash controller has
     * been loaded successfully and JS-AS communication is established.
     *
     * It is either passed as event handler method when flash widgets subscribe themselves to the flash controller
     * initiation event, or called directly if controller is already initiated.
     *
     * @param event          String : event that is fired. Not used in the method.
     * @param firedData      String : fired data. This is also ignored in the method.
     * @param subscribedData String : subscribed data. It contains for the relevant information for initiating flash widget.
     */
    this.callAddFlashWidget = function(event, firedData, subscribedData)
    {
        wtkComm.thisMovie('FlashController').addWidget(subscribedData.widgetId, subscribedData.xVal, subscribedData.yVal,
                                            subscribedData.depthVal,subscribedData.srcVal);
    }

    /**
     * This function clears the communication table
     */
    this.unmash = function ()
    {
        for(var key in this.recvList)
        {
            var yuiEvent = this.recvList[key];
            yuiEvent.unsubscribeAll();
            this.recvList[key] = null;
            this.subscriberList[key] = null;
        }

        this.recvList = null;
        this.recvList=new Object();
        this.subscriberList = null;
        this.subscriberList = new Object();
    }
}

//The global instance of the Widget Toolkit
var wtkComm = new com.forddirect.presentation.wtk.CommunicationManager( );
/**
 * This class parses the input url parameters stored in URLParamMap.
 * This also creates a legacyMap which is used for storing the parameters
 * passed to BP from FD. These parameters are to be used for any linkouts from bp.
 * @author sdua
 */
getPackageForName("com.forddirect.application.bp20.flow").LegacyParamsParser = function(){

    this.m_runInDebugMode = true;
    
    /**
     * this map provides a uniform naming for all FD linkin parameters
     */
    this.m_linkinParamsMapping = {
        "BRANDING": "branding",
        "REFERRING_SITE": "referringsite",
        "REFERRER": "referrer",
        "REFERRER_URL": "referrerurl",
        "PARTNER": "partner",
        "REFERRED_ON_DATE": "referredondate",
        "SITE_ID": "siteid",
        "OVMTC": "ovmtc",
        "CAMPAIGN_ID": "campaignid",
        "CONFIG_ID": "configid",
        "ZIPCODE": "zipcode",
        "PACODE":"pacode",
        "PLAN_TYPE": "plantype",
        "LANG": "lang",
        "REDIRECT_PAGE":"redirectpage",
        "LEAD_SOURCE" : "leadsource",
        "ALT_LEAD_SOURCE" : "altleadsource",
        "VEHICLE_TYPE" : "type"
    }
    
    /*
     * this provides a uniform naming for keying into the url map for BP2 params
     */
    this.m_bp2ParamKeys = {
        "ZIPCODE": "zipCode"
    }
    
    /**
     * this defines constants used for generic constants
     */
    this.m_constants = {
        "UI_BRANDING_FORDVEHICLES": "1",
        "UI_BRANDING_FORDDIRECT": "3",
        "UI_BRANDING_DEALERCONNECTION": "2" //this value as been assumed
    }
    
    /**
     * this defines constants for referrring site
     */
    this.s_referringSiteConsts = {
        "LEAD_SOURCE_UNKNOWN": "0",
        "LEAD_SOURCE_FORDVEHICLES": "1",
        "LEAD_SOURCE_DEALERCONNECTION": "2",
        "LEAD_SOURCE_FORD_COM": "3",
        "LEAD_SOURCE_LINKSHARE": "4",
        "LEAD_SOURCE_SEARCHENGINE": "5",
        "LEAD_SOURCE_DEALERDIRECT": "6",
        "LEAD_SOURCE_AXZPLAN": "7",
        "LEAD_SOURCE_MARKETINGPARTNER": "8",
        "LEAD_SOURCE_FORDVEHICLES_PKG": "9",
        "LEAD_SOURCE_DEALERCONNECTION_DIRECT_URL": "10",
        "LEAD_SOURCE_LINCOLNVEHICLES": "11",
        "LEAD_SOURCE_MERCURYVEHICLES": "12",
        "LEAD_SOURCE_SMART_GUIDE": "13",
        "LEAD_SOURCE_MY_FOLDER": "14"
    };
    
    /**
     * this defines constants for lead source
     */
    this.s_leadSourceConsts = {
        "FORD_VEHICLES": "Ford.com",
        "FORD_DOT_COM": "Ford.com",
        "LINKSHARE": "LinkShare",
        "SEARCH_ENGINE_SITE": "SearchEngine",
        "UNKNOWN_MARKETING_AFFILIATE": "UnknownMarketingAffiliate",
        "FORDDIRECT": "FordDirect",
        "DC_SUBSOURCE_FORD": "DC New Quote Ford",
        "UNKNOWN_SOURCE": "UnknownSource",
        "LEAD_SOURCE_DEALERDIRECT": "FORDDIRECT"
    }

    this.m_legacyParamMap = {};
    
    this.getReferringSite = function(name){
        return this.s_referringSiteConsts[name];
    }
    
    this.getLeadSource = function(name){
        return this.s_leadSourceConsts[name];
    }
    
    this.getConstant = function(key){
        return this.m_constants[key];
    }
    
    this.debug = function(){
        return this.m_runInDebugMode;
    }
    
    this.getLinkinParamNames = function(param){
        return this.m_linkinParamsMapping[param];
    }
    
    /**
     * This method reads the FD linkin parameters from urlParamsMap and
     * 1. stores the original values in a legacy map {m_legacyParamMap}
     * 2. Transforms each of the values
     * The parameters it works on are
     * {branding, referringSite, referrer, referrerURL, partner, referredOnDate, siteID, ovmtc, campaignID, configID, zipCode, lang}
     * @param {Object} paramMap
     */
    this.parseLegacyParams = function(paramMap){
        //parse the value for branding
        log4javascript.getDefaultLogger().debug("LegacyParamsParser:: Entering parseLegacyParams");
        this.m_legacyParamMap = {};
        this.transformBranding(paramMap, this.m_legacyParamMap);
        
        //Set the param Lead Source from the param map
        var leadSourceParam = paramMap[this.m_linkinParamsMapping.LEAD_SOURCE];
        if (null != leadSourceParam) {
            this.m_legacyParamMap[this.m_linkinParamsMapping.LEAD_SOURCE] = leadSourceParam;
		}
        //Set the param Alt Lead Source from the param map
        var altLeadSource = paramMap[this.m_linkinParamsMapping.ALT_LEAD_SOURCE];
        if (null != altLeadSource) {
            this.m_legacyParamMap[this.m_linkinParamsMapping.ALT_LEAD_SOURCE] = altLeadSource;
		}

        //Set the param Vehicle type from the param map
        var vehicleType = paramMap[this.m_linkinParamsMapping.VEHICLE_TYPE];
        if (null != vehicleType) {
            this.m_legacyParamMap[this.m_linkinParamsMapping.VEHICLE_TYPE] = vehicleType;
		}

        //Set the param referringSite from the param map
        var referringSite = paramMap[this.m_linkinParamsMapping.REFERRING_SITE];
        if (null != referringSite) {
            this.m_legacyParamMap[this.m_linkinParamsMapping.REFERRING_SITE] = referringSite;
        }
        //Set the param referr from the param Map
        var referrer = paramMap[this.m_linkinParamsMapping.REFERRER];
        if (null != referrer) {
            this.m_legacyParamMap[this.m_linkinParamsMapping.REFERRER] = referrer;
        }
        //Set the param referrerURL from the param Map
        var referrerURL = paramMap[this.m_linkinParamsMapping.REFERRER_URL];
        if (null != referrerURL) {
            this.m_legacyParamMap[this.m_linkinParamsMapping.REFERRER_URL] = referrerURL;
        }
        //Set the param referrerURL from the param Map
        var partner = paramMap[this.m_linkinParamsMapping.PARTNER];
        if (null != partner) {
            this.m_legacyParamMap[this.m_linkinParamsMapping.PARTNER] = partner;
        }
        //Set the param referrerURL from the param Map
        var referredOnDate = paramMap[this.m_linkinParamsMapping.REFERRED_ON_DATE];
        if (null != partner) {
            this.m_legacyParamMap[this.m_linkinParamsMapping.REFERRED_ON_DATE] = referredOnDate;
        }
        
        this.transformSiteID(paramMap, this.m_legacyParamMap);
        this.transformOVMTC(paramMap, this.m_legacyParamMap);
        var campaignID = paramMap[this.m_linkinParamsMapping["CAMPAIGN_ID"]];
        if (null != campaignID) {
            this.m_legacyParamMap[this.m_linkinParamsMapping["CAMPAIGN_ID"]] = campaignID;
        }
        var configID = paramMap[this.m_linkinParamsMapping["CONFIG_ID"]];
        if (null != configID) {
            this.m_legacyParamMap[this.m_linkinParamsMapping["CONFIG_ID"]] = configID;
        }
        var zipcode = paramMap[this.m_linkinParamsMapping["ZIPCODE"]];
        if (null != zipcode) {
            this.m_legacyParamMap[this.m_linkinParamsMapping["ZIPCODE"]] = zipcode;
        }

        this.updateLegacyParamPACode(paramMap);

        this.transformPlanType(paramMap, this.m_legacyParamMap);
        var lang = paramMap[this.m_linkinParamsMapping["LANG"]];
        if (null != lang) {
            this.m_legacyParamMap[this.m_linkinParamsMapping["LANG"]] = lang;
        }
        var redirectPage = paramMap[this.m_linkinParamsMapping["REDIRECT_PAGE"]];
        if (redirectPage) {
            this.m_legacyParamMap[this.m_linkinParamsMapping["REDIRECT_PAGE"]] = redirectPage;
        }
        //log the linkin params
        this.printMap(this.m_legacyParamMap);
        log4javascript.getDefaultLogger().debug("LegacyParamsParser:: Leaving parseLegacyParams");
    }
    
    /**
     * This function updates the legacyParamMap when zipCode is changed
     * @param {Object} paramMap
     */
    this.updateLegacyParamZipCode = function(paramMap){
        var zipcode = paramMap[this.m_linkinParamsMapping["ZIPCODE"]];
        if (null != zipcode) {
            this.m_legacyParamMap[this.m_linkinParamsMapping["ZIPCODE"]] = zipcode;
        }
    }

    /**
     * This function updates the legacyParamMap when PACode is changed
     * @param {Object} paramMap
     */
    this.updateLegacyParamPACode = function(paramMap){
        var pacode = paramMap[this.m_linkinParamsMapping["PACODE"]];
        if (pacode) {
            this.m_legacyParamMap[this.m_linkinParamsMapping["PACODE"]] = pacode;
        }
    }

    /**
     * This function updated the legacyParamMap when configId is changed
     * @param {Object} paramMap
     */
    this.updateLegacyParamConfigId = function(paramMap){
        var configID = paramMap[this.m_linkinParamsMapping["CONFIG_ID"]];
        if (null != configID) {
            this.m_legacyParamMap[this.m_linkinParamsMapping["CONFIG_ID"]] = configID;
        }
    }
    
    /**
     * This method logs the transformed paramter map from FD. This is used for integration testing
     * and verification.
     * @param {Object} legacyMap
     */
    this.printMap = function(legacyMap){
        log4javascript.getDefaultLogger().debug("---------------START: LegacyMap for outbound links is--------------------");
        for (var a in legacyMap) {
            log4javascript.getDefaultLogger().debug("" + a + " : " + legacyMap[a]);
        }
        log4javascript.getDefaultLogger().debug("---------------LegacyMap for outbound links is--------------------");
    }
    /**
     * this method extracts the plantype value from paramMap.
     * It then computes a decoded plantype based on the plan type value and stores the decoded value in the param map
     * it then checks if referrerr or referrerURL is not "DirectAZPlan" or "DirectXPlan", and sets a "PricingPlan" cookie if
     * the condition is valid.
     * @param {Object} paramMap
     * @param {Object} legacyMap
     */
    this.transformPlanType = function(paramMap, legacyMap){
        log4javascript.getDefaultLogger().debug("LegacyParamsParser:: Entering transformPlanType");
        var planType = paramMap[this.m_linkinParamsMapping["PLAN_TYPE"]];
        
        var referrer = paramMap[this.m_linkinParamsMapping["REFERRER"]];
        var referrerURL = paramMap[this.m_linkinParamsMapping["REFERRER_URL"]];
        if (null != planType) {
            legacyMap[this.m_linkinParamsMapping["PLAN_TYPE"]] = planType;
            planType = BPTrim(planType).planType = planType.toUpperCase();
            var decodedPlan = "";
            switch (planType) {
                case 'A':
                case 'Z':
                case 'AZ':
                case 'AXZ':
                case 'A/Z-PLAN':
                    decodedPlan = unescape("A/Z-Plan");
                    break;
                case 'X':
                case 'X-Plan':
                    decodedPlan = 'X-Plan';
                    break;
                default:
                    decodedPlan = null;
            }
            paramMap["DECODED_PLAN"] = decodedPlan;
            /*
             * if (referrer or referrerURL) is not one of "DirectAZPlan", "DirectXPlan" then, set a cookie by name "PricingPlan" with value
             * "<decodedPlanName> from <referrer>" for domain "forddirect.ford.com" with maxage as 30 days.
            */
            if ("DirectAZPlan" != referrer && "DirectXPlan" != referrer && "DirectAZPlan" != referrerURL && "DirectXPlan" != referrerURL) {
                var now = new Date();
                cookieManager.createCookie("PricingPlan", decodedPlan + ' from ' + referrer, {
                    domain: 'forddirect.ford.com',
                    expires: now.setDate(now.getDate() + 30),
                    path: '/'
                });
            }
        }
        
    }

    /**
     * This method transforms the branding value passed as linkin param.
     * If no valid value is passed, a value of UI_BRANDING_FORDDIRECT is taken as default
     * @param {Object} paramMap
     * @param {Object} legacyMap
     */
    this.transformBranding = function(paramMap, legacyMap){
        var branding = paramMap[this.m_linkinParamsMapping["BRANDING"]];
        if (null != branding) {
            //set the old value for branding
            legacyMap[this.m_linkinParamsMapping["BRANDING"]] = branding;
            //check if the value is valid
            if (this.getConstant("UI_BRANDING_FORDDIRECT") != branding && this.getConstant("UI_BRANDING_FORDVEHICLES") != branding && this.getConstant("UI_BRANDING_DEALERCONNECTION") != branding) {
                paramMap[this.m_linkinParamsMapping["BRANDING"]] = this.getConstant("UI_BRANDING_FORDDIRECT");
            }
            else {
                paramMap[this.m_linkinParamsMapping["BRANDING"]] = branding;
            }
        }
        else {
            paramMap[this.m_linkinParamsMapping["BRANDING"]] = this.getConstant("UI_BRANDING_FORDDIRECT");
        }
    }
    
    /**
     * This method transforms the site ID. It creates a cookie by name "Linkshare" with a value
     * <siteID>@<timestamp> if siteid exists.
     * This also checks if a "Linkshare" cookie exists and sets the referring site with LeadSourceLinkshare
     * and referredOndate with Timestamp if the cookie exists.
     * @param {Object} paramMap
     * @param {Object} legacyMap
     */
    this.transformSiteID = function(paramMap, legacyMap){
        log4javascript.getDefaultLogger().debug("LegacyParamsParser:: Entering transformSiteID");
        var siteID = paramMap[this.m_linkinParamsMapping["SITE_ID"]];
        if (null != siteID) {
            legacyMap[this.m_linkinParamsMapping["SITE_ID"]] = siteID;
            /*
             * call the cookie manager and create a cookie by name 'Linkshare'
             * with value <siteID>@<timestamp> for the domain "forddirect.ford.com"
             * with the path set to "/" for a period of 365 days.
             * <timestamp> is the current time in the format yyyy-MM-dd/HH:mm:ss
            */
            var cookieValue = siteID + '@' + formatDate(new Date(), "yyyy-MM-dd/HH:mm:ss")
            //get a date 365 days from now
            var d2 = new Date();
            var tm = d2.getTime() + 365 * 24 * 60 * 60 * 1000;
            d2.setTime(tm);
            cookieManager.createCookie("Linkshare", cookieValue, {
                expires: d2,
                path: "/",
                domain: "forddirect.ford.com"
            });
        }
        
        /*
         * If the "Linkshare" cookie is available, then
         override the referringSite by setting it to LEAD_SOURCE_LINKSHARE
         override referredOnDate with <timestamp>
         override "Affiliate Transaction Sub ID"
        */
        var linkShareCookie = cookieManager.readCookie("Linkshare");
        log4javascript.getDefaultLogger().debug("LegacyParamsParser:: TransformSiteID Linkshare cookie value is " + linkShareCookie);
        if (null != linkShareCookie) {
            //override the referringSite by setting it to LEAD_SOURCE_LINKSHARE
            paramMap[this.m_linkinParamsMapping["REFERRING_SITE"]] = this.getReferringSite("LEAD_SOURCE_LINKSHARE");
            //override referredOnDate with <timestamp>
            var cookieValueArray = linkShareCookie.split("@");
            paramMap[this.m_linkinParamsMapping["REFERRED_ON_DATE"]] = cookieValueArray[1];
            //override "Affiliate Transaction Sub ID"
            paramMap[this.m_linkinParamsMapping["SITE_ID"]] = cookieValueArray[0];
        }
        log4javascript.getDefaultLogger().debug("LegacyParamsParser:: Leaving transformSiteID");
    }
    
    /**
     * sets the ovmtc param in legacy map.
     * @param {Object} paramMap
     * @param {Object} legacyMap
     */
    this.transformOVMTC = function(paramMap, legacyMap){
        var ovmtc = paramMap[this.m_linkinParamsMapping["OVMTC"]];
        if (null != ovmtc) {
            legacyMap[this.m_linkinParamsMapping["OVMTC"]] = ovmtc;
            
        //TODO: validate the OVMTC value?
        }
    }

    /**
     * This function returns Next Gen params which are passed to other ST apps.
     */
    this.getNextGenURLParams = function(){
        var urlString = "";
        for (var param in this.m_linkinParamsMapping) {
            if (typeof(this.m_legacyParamMap[this.m_linkinParamsMapping[param]]) != "undefined") {
                urlString = urlString + (urlString != "" ? "&" : "") + this.m_linkinParamsMapping[param] + "=" + escape(this.m_legacyParamMap[this.m_linkinParamsMapping[param]]);
            }
        }
        return urlString;
    }

    this.displayUsedCarsBanner = function(){
        log4javascript.getDefaultLogger( ).debug( "displayUsedCarsBanner--- STARTED");
        var referringSite = urlParamMap[this.m_linkinParamsMapping["REFERRING_SITE"]];
        var branding = urlParamMap[this.m_linkinParamsMapping["BRANDING"]];
        
            return(branding != this.getConstant("UI_BRANDING_DEALERCONNECTION") && referringSite != this.getReferringSite("LEAD_SOURCE_AXZPLAN") && referringSite != this.getReferringSite("LEAD_SOURCE_FORDVEHICLES") && referringSite != this.getReferringSite("LEAD_SOURCE_MERCURYVEHICLES") && referringSite != this.getReferringSite("LEAD_SOURCE_LINCOLNVEHICLES") && referringSite != this.getReferringSite("LEAD_SOURCE_SMART_GUIDE") && referringSite != this.getReferringSite("LEAD_SOURCE_MY_FOLDER"));                        
    }
}
var legacyParser = new com.forddirect.application.bp20.flow.LegacyParamsParser();
/**
 * This global function creates and initializes the Widget Toolkit instance
 */
var initParser = function(){
    log4javascript.getDefaultLogger().debug("Started legacy param parsing");
    legacyParser.parseLegacyParams(urlParamMap);
    if (legacyParser.debug()) {
        log4javascript.getDefaultLogger().debug('---------------------START: PARAMS MAP IN BP2.0 ---------------');
        for (var k in urlParamMap) {
            log4javascript.getDefaultLogger().debug(k + ' : ' + urlParamMap[k]);
        }
        log4javascript.getDefaultLogger().debug('---------------------END: PARAMS MAP IN BP2.0 ---------------');
    }
}

//This statement calls the global function initWtk when the DOM is loaded.
//YAHOO.util.Event.onDOMReady( initParser ) ;
/**
 * This function represents the com.forddirect.presentation.wtk.HistoryManager class.
 * @author Sachin Kulkarni
 * @author Praveen DS
 */
getPackageForName("com.forddirect.presentation.wtk").HistoryManager = function(){
    this.stateChangeHandlerFunc;
    
    this.context;
    
    this.historyEnabled = "";
    
    this.appName = "page";
    
    this.dependenciesInitialized = false;
    this.historyManagerInitialized = false;
    this.bookMarkLoaded = false;
    
    /**
     * This function initializes YUI HistoryManager. It registers onStageChange function. It also sets the
     * initial state of the application. Later it subscribes to onLoad event of HistoryManager.
     * @param stateChangeHandler function to be called when a state change occurs (clicking browser back/forward
     * button of a call to navigate function)
     * @param initialState default initial state of the application
     */
    this.init = function(){
        var bookmarkedSection = YAHOO.util.History.getBookmarkedState(this.appName);
        /*
         * This value is being returned when the YAHOO.util.History.getCurrentState() function is called
         */
        var initSection = bookmarkedSection || __pathinfo;
        this.stateChangeHandlerFunc = null;
        
        // Register our only module. Module registration MUST take
        // place before calling YAHOO.util.History.initialize.
        YAHOO.util.History.register(this.appName, initSection, function(state){
            if (wtkHistoryManager.stateChangeHandlerFunc != null) {
                wtkHistoryManager.stateChangeHandlerFunc(state, wtkHistoryManager.context);
            }
        });
        
        // Subscribe to this event before calling YAHOO.util.History.initialize,
        // or it may never get fired! Note that this is guaranteed to be fired
        // after the window's onload event.
        YAHOO.util.History.onLoadEvent.subscribe(function(){
            wtkHistoryManager.historyManagerInitialized = true;
            wtkHistoryManager.bookMarkLoaderOnHistoryManagerInitialization();
        });
        
        // The call to YAHOO.util.History.initialize should ALWAYS be from within
        // a script block located RIGHT AFTER the opening body tag (this seems to prevent
        // an edge case bug on IE - IE seems to sometimes forget the history when
        // coming back to a page, and the back - or forward button depending on the
        // situation - is disabled...)
        //Updated to the Yui History 2.7.0
        try {
            YAHOO.util.History.initialize("yui-history-field","yui-history-iframe");
        } catch (e) {
            // The only exception that gets thrown here is when the browser is not A-grade.
            // Since scripting is enabled, we still try to provide the user with a better
            // experience using AJAX. The only caveat is that the browser history will not work.
            log4javascript.getDefaultLogger().error("Error in enabling history" + e);
        }
    }
    
    /**
     * Note: this is one time call only
     * In IE 7, the history manager is initialized first and then the flowcontroller is downloaded (and the other way in Firefox)
     * here the dependenciesInitialized is used to check whether the init() of flowcontroller is successfully called as it
     * the init() there makes a call to this.initializeHandler where this variable is set to true
     */
    this.bookMarkLoaderOnHistoryManagerInitialization = function(){
        if (!this.bookMarkLoaded) {
            if (this.dependenciesInitialized && this.historyManagerInitialized) {
                log4javascript.getDefaultLogger().info("Yahoo History manager initialized");
                var myModuleCurrentState = YAHOO.util.History.getCurrentState(wtkHistoryManager.appName);
                if (null !== myModuleCurrentState) {
                    if (state = myModuleCurrentState.match('^[a-zA-Z]+')) {
                        myModuleCurrentState = '/' + state[0];
                    }
                    log4javascript.getDefaultLogger().info("Current state NOT null " + myModuleCurrentState);
                    this.stateChangeHandlerFunc(myModuleCurrentState, this.context);
                }
                else {
                    log4javascript.getDefaultLogger().error("current state is NULL. Should NOT happen");
                }
                this.bookMarkLoaded = true;
            }
            
        }
    }
    
    /**
     *
     */
    this.initializeHandler = function(stateChangeHandler, handlerContext){
        this.dependenciesInitialized = true;
        this.stateChangeHandlerFunc = stateChangeHandler;
        this.context = handlerContext;
        this.bookMarkLoaderOnHistoryManagerInitialization();
        
    }
    
    /**
     * This function adds the new state to YUI history. Once history is updated callback to stateChangeHandler
     * is called.
     * @param stateToken new state token
     */
    this.addToHistory = function(stateToken){
        if (typeof stateToken == "undefined") {
            log4javascript.getDefaultLogger().error("ConfigStateToken is undefined!  Cannot proceed");
            return;
        }
        if (null == stateToken) {
            log4javascript.getDefaultLogger().error("ConfigStateToken is null!  Cannot proceed");
            return;
        }
        try {
            YAHOO.util.History.navigate(this.appName, stateToken);
            
        } catch (e) {
            log4javascript.getDefaultLogger().error("History not enabled. manually calling state change handler for " + stateToken);
            this.stateChangeHandlerFunc(state, this.context);
        }
        
    }
}

//The global instance of the Widget Toolkit History Manager
var wtkHistoryManager = new com.forddirect.presentation.wtk.HistoryManager();
wtkHistoryManager.init();
/*************************************************************************
 Copyright (C) Unpublished Versata Software, Inc. All rights reserved.
 Versata Software, Inc., Confidential and Proprietary.
 This software is subject to copyright protection
 under the laws of the United States and other countries.
 Unless otherwise explicitly stated, this software is provided
 by Versata "AS IS".
 *************************************************************************/
/**
 * @author Praveen DS
 * @version 1.0
 */
/**
 * This is a helper class (yeah function) for manipulating URL parameters.  In the current implementation
 * the parameters extracted from the URL can either reside in cookies or in the URLParamMap.
 * Note:
 * Initial parameter values alone will be read using this helper class.  Subsequently only writing will happen
 * 1) For cookie enabled browsers, it will be the cookies to which the data is written
 * 2) For cookie disabled browsers, it will be the URL that will hold the updated values.
 *
 * Requires cookie manager to be initialized
 * @see com.forddirect.presentation.wtk.util.CookieManager
 */
getPackageForName("com.forddirect.presentation.wtk.util").ParamHelper = function(){
    /*
     * for URL Param map
     *
     */
    this.URL_MAP_YEAR = "Year";
    this.URL_MAP_MAKE = "Make";
    this.URL_MAP_MODEL = "Model";
    this.URL_MAP_DEFINERS = "Definers";
    this.URL_MAP_TRANS = "Transmissions";
    this.URL_MAP_PAGE = "Page";
    this.URL_MAP_CONFIGID = "configid";
    this.URL_MAP_ZIPCODE = "zipcode";
    this.URL_MAP_PACODE = "pacode";
    this.URL_MAP_SELECT = "select";
    this.URL_MAP_UNSELECT = "unselect";
    this.URL_MAP_VEHICLETYPE = "vehicletype";
    this.URL_MAP_SIMODEL = "simodel";
    this.URL_MAP_SIYEAR = "siyear";
    this.URL_MAP_LCWMODEL = "lcwmodel";
    this.URL_MAP_LCWYEAR = "lcwyear";
    
    this.getMake = function(){
        return urlParamMap[this.URL_MAP_MAKE];
    }
    
    this.getModel = function(){
        return urlParamMap[this.URL_MAP_MODEL];
    }
    
    this.getYear = function(){
        return urlParamMap[this.URL_MAP_YEAR];
    }
    
    this.getPage = function(){
        if (cookieManager.isCookieEnabled) {
            return cookieManager.getSub(this.urlParamMapCookieName, this.pageCookieName);
        } else {
            return urlParamMap[this.URL_MAP_PAGE];
        }
        
    }
    
    this.getDefiners = function(){
        if (cookieManager.isCookieEnabled) {
            return cookieManager.getSub(this.urlParamMapCookieName, this.definersCookieName);
        } else {
            return urlParamMap[this.URL_MAP_DEFINERS];
        }
        
    }
    
    this.getTransmission = function(){
        if (cookieManager.isCookieEnabled) {
            return cookieManager.getSub(this.urlParamMapCookieName, this.transmissionCookieName);
        } else {
            return urlParamMap[this.URL_MAP_TRANS];
        }
        
    }
    
    /*
     * This is common across vehicles
     */
    this.getZipCode = function(){
        if (cookieManager.isCookieEnabled) {
            return cookieManager.readCookie(this.zipCodeCookieName);
        } else {
            return urlParamMap[this.URL_MAP_ZIPCODE];
        }
        
    }

    /*
     * This method returns the PACode. If cookie is enabled, it retrieves the value from the cookie,
     * otherwise returns from the urlParamMap.
     */
    this.getPACode = function(){
        if (cookieManager.isCookieEnabled) {
            return cookieManager.readCookie(this.PACodeCookieName);
        } else {
            return urlParamMap[this.URL_MAP_PACODE];
        }

    }
    
    this.getConfigToken = function(){
        if (cookieManager.isCookieEnabled) {
            return cookieManager.getSub(this.urlParamMapCookieName, this.configTokenCookieName);
        } else {
            return urlParamMap[this.URL_MAP_CONFIGID];
        }
        
    }
    
    this.getSelectPart = function(){
        if (cookieManager.isCookieEnabled) {
            return cookieManager.cookieManager.getSub(this.urlParamMapCookieName, this.selectPartCookieName);
        } else {
            return urlParamMap[this.URL_MAP_SELECT];
        }
        
    }
    
    this.getUnselectPart = function(){
        if (cookieManager.isCookieEnabled) {
            return cookieManager.cookieManager.getSub(this.urlParamMapCookieName, this.unselectPartCookieName);
        } else {
            return urlParamMap[this.URL_MAP_UNSELECT];
        }
        
    }
    
    this.getURLParamMapFromPreviousVisit = function(){
        if (cookieManager.isCookieEnabled) {
            return cookieManager.getSubs(this.urlParamMapCookieName);
        } else {
            //Captured in the URL already.
            return null;
        }
    }
    
    this.setMake = function(value){
        //TODO : Remove this cookie. We are approaching launch, and this 
        //cookie is kept to refrain from breaking any functionality due to 
        //the use of cookie directly.
        urlParamMap[this.URL_MAP_MAKE] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSub(this.urlParamMapCookieName, this.makeCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        
    }
    
    this.setModel = function(value){
        //TODO : Remove this cookie. We are approaching launch, and this 
        //cookie is kept to refrain from breaking any functionality due to 
        //the use of cookie directly.
        urlParamMap[this.URL_MAP_MODEL] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSub(this.urlParamMapCookieName, this.modelCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        
    }
    
    this.setYear = function(value){
        //TODO : Remove this cookie. We are approaching launch, and this 
        //cookie is kept to refrain from breaking any functionality due to 
        //the use of cookie directly.
        urlParamMap[this.URL_MAP_YEAR] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSub(this.urlParamMapCookieName, this.yearCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        
    }
    
    this.setPage = function(value){
        urlParamMap[this.URL_MAP_PAGE] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSub(this.urlParamMapCookieName, this.pageCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        
    }
    
    this.setDefiners = function(value){
        urlParamMap[this.URL_MAP_DEFINERS] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSub(this.urlParamMapCookieName, this.definersCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        
    }
    
    this.setTransmission = function(value){
        urlParamMap[this.URL_MAP_TRANS] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSub(this.urlParamMapCookieName, this.transmissionCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        
    }
    
    /*
     * As zipcode is common across vehicles, we need to set it as a cookie as well.
     */
    this.setZipCode = function(value){
        urlParamMap[this.URL_MAP_ZIPCODE] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.createCookie(this.zipCodeCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
            cookieManager.setSub(this.urlParamMapCookieName, this.zipCodeCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
            
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        legacyParser.updateLegacyParamZipCode(urlParamMap);
    }
  
    /*
     * This method sets the PACode in urlParamMap and if cookie is enabled then also creates the cookie.
     */
    this.setPACode = function(value){
        urlParamMap[this.URL_MAP_PACODE] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.createCookie(this.PACodeCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
            cookieManager.setSub(this.urlParamMapCookieName, this.PACodeCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });

        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        legacyParser.updateLegacyParamPACode(urlParamMap);
    }

    this.setConfigToken = function(value){
        urlParamMap[this.URL_MAP_CONFIGID] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSub(this.urlParamMapCookieName, this.configTokenCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        legacyParser.updateLegacyParamConfigId(urlParamMap);
    }
    
    this.setSelectPart = function(value){
        urlParamMap[this.URL_MAP_SELECT] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSub(this.urlParamMapCookieName, this.selectPartCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        
    }
    
    this.setUnselectPart = function(value){
        urlParamMap[this.URL_MAP_UNSELECT] = value;
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSub(this.urlParamMapCookieName, this.unselectPartCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
    }
    
    this.setURLParamMap = function(value){
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSubs(this.urlParamMapCookieName, value, {
                expires: new Date("January 12, 2025"),
                path: "/"
            });
        } else {
            //Here it is already captured in the URL
        }
    }
   /**
   * Sets a Cookie for Selected Vehicle from HomePage
   * Uses setSubs so as to keep the entire Object as a cookie
   **/
   
    this.setHPSelectedVehicle = function(value)
    {       
        if (cookieManager.isCookieEnabled) {
            cookieManager.setSubs(this.hpSelectedVehicleCookieName, value);
        } else {
            wtkHistoryManager.addToHistory(urlUtils.getParametersPathWithPageInfo());
        }
        
    }
    /**
    * Method to retrieve Cookie for Selected Vehicle from HomePage
    **/
    this.getHPSelectedVehicle = function()
    {       
        if (cookieManager.isCookieEnabled) {
            return cookieManager.getSubs(this.hpSelectedVehicleCookieName);
        } else { 
            return null;
        }
    }
    
    
    /**
     * Removes all the cookies set for identifying a vehicle (make, model, year, parts, transmission, definers, configID, zipCode)
     */
    this.removeAllVehicleCookies = function(){
        var options = {
            path: "/"
        };
        cookieManager.removeCookie(this.makeCookieName, options);
        cookieManager.removeCookie(this.modelCookieName, options);
        cookieManager.removeCookie(this.yearCookieName, options);
        cookieManager.removeCookie(this.definersCookieName, options);
        cookieManager.removeCookie(this.transmissionCookieName, options);
        cookieManager.removeCookie(this.zipCodeCookieName, options);
        cookieManager.removeCookie(this.configTokenCookieName, options);
        cookieManager.removeCookie(this.selectPartCookieName, options);
        cookieManager.removeCookie(this.unselectPartCookieName, options);
    }
    
    
    this.getCookieName = function(name){
        return this.getModel() + this.getMake() + this.getYear() + name;
    }
    
    this.makeCookieName = this.URL_MAP_MAKE;
    this.modelCookieName = this.URL_MAP_MODEL;
    this.yearCookieName = this.URL_MAP_YEAR;
    this.pageCookieName = this.URL_MAP_PAGE;
    this.definersCookieName = this.URL_MAP_DEFINERS;
    this.transmissionCookieName = this.URL_MAP_TRANS;
    this.zipCodeCookieName = this.URL_MAP_ZIPCODE;
    this.PACodeCookieName = this.URL_MAP_PACODE;
    this.configTokenCookieName = this.URL_MAP_CONFIGID;
    this.selectPartCookieName = this.URL_MAP_SELECT;
    this.unselectPartCookieName = this.URL_MAP_UNSELECT;
    this.urlParamMapCookieName = this.getCookieName("urlParamMap");
    this.hpSelectedVehicleCookieName = "hpSelectedVehicle";
}

//The global instance of the ParamHelper
var paramHelper = new com.forddirect.presentation.wtk.util.ParamHelper();/*
 * Copied from Forddirect.com (called CookieUtility in FD code).   For retrieving some session cookies set by FV.
 * Please refer http://issues.ngptools.com/jira/browse/BP-921 for details
 */
var sDefaultLifeTime = 65;
var sPATH = ";path=/";
var sEXPIRES = ";expires=";
var sDOMAIN = ";domain=";

SessionCookieUtility = function(){
}

// if non-blank, cookies shared among servers in this domain
SessionCookieUtility.COOKIE_DOMAIN = "";

//APIs to be supported for MyFolder. Please remove/modify them after 8.14
SessionCookieUtility.createCookie = function(name, value, days){
    SessionCookieUtility.setCookieValue(name, value, days);
}

SessionCookieUtility.readCookie = function(name){
    return SessionCookieUtility.getCookieValue(name);
}

SessionCookieUtility.eraseCookie = function(name){
    SessionCookieUtility.eraseCookie(name, SessionCookieUtility.COOKIE_DOMAIN);
}

SessionCookieUtility.eraseCookie = function(name, domain){
    SessionCookieUtility.setCookieValue(name, "", 0, domain);
}

/* Public Functions  Ported from Ford Vehicles for maintaining consistency of the Cookie Storage and retrieval from a sub-cookie format*/
SessionCookieUtility.setCookieValue = function(name, val, nDays){
    SessionCookieUtility.setCookieValue(name, val, nDays, SessionCookieUtility.COOKIE_DOMAIN);
}

SessionCookieUtility.setCookieValue = function(name, val, nDays, domain){
    var sCookie = "";
    var oToday = new Date();
    var oExpire = new Date();
    
    if (typeof(domain) != "string" || domain == null || domain == "") {
        domain = SessionCookieUtility.COOKIE_DOMAIN;
    }
    
    if (name == "MyFolderUserId") {
        SessionCookieUtility.COOKIE_DOMAIN = '.ford.com';
        domain = '.ford.com';
        nDays = "";
    }
    
    if (typeof(name) == "string") {
        if (name.length != 0) {
            sCookie = name + "=" + escape(val) + sPATH;
            if (typeof(nDays) == "number") {
                oExpire.setTime(oToday.getTime() + 60 * 60 * 1000 * 24 * nDays);
                sCookie = sCookie + sEXPIRES + oExpire.toGMTString();
            }
            if (domain != '') {
                domain = sDOMAIN + domain; //Add domain prefix
            }
            sCookie = sCookie + domain;
            document.cookie = sCookie;
        }
    }
}

SessionCookieUtility.setSubCookieValue = function(sname, subname, val, nDays){
    var cookie = document.cookie;
    var chkdCookie = SessionCookieUtility.removeBlanks(cookie);
    var aCookie = chkdCookie.split(";");
    var iCookie = SessionCookieUtility.getCookieIndex(aCookie, sname);
    
    if (iCookie >= 0) {
        var aSubCookie = aCookie[iCookie].split("&");
        var iSubCookie = SessionCookieUtility.getSubCookieIndex(aSubCookie, subname);
    }
    
    var sCookie = "";
    var oToday = new Date();
    var oExpire = new Date();
    
    if (typeof(sname) == "string") {
        if (subname.length != 0) {
            // Replace subcookie 
            if (Number(iSubCookie) >= 0) {
                for (j = 0; j < aSubCookie.length; ++j) {
                    splitValues = aSubCookie[j].split("=");
                    if (splitValues[0] == subname) {
                        aSubCookie[j] = subname + "=" + escape(val);
                    } else if (splitValues[0] == sname) {
                        if (splitValues[1] == subname) {
                            aSubCookie[j] = sname + "=" + subname + "=" + escape(val);
                        }
                    }
                    
                    if ((j > 0) && (j < aSubCookie.length)) {
                        sCookie = sCookie + "&";
                    }
                    sCookie = sCookie + aSubCookie[j];
                }
                sCookie = sCookie + sPATH;
            } else {
                if (iCookie >= 0) {
                    // Add to existing cookie         
                    sCookie = aCookie[iCookie] + "&" + subname + "=" + escape(val) + sPATH;
                } else {
                    sCookie = sname + "=" + subname + "=" + escape(val) + sPATH;
                }
            }
            if (typeof(nDays) == "number") {
                var sDomain = SessionCookieUtility.getDomain();
                oExpire.setTime(oToday.getTime() + 3600000 * 24 * nDays);
                sCookie = sCookie + sEXPIRES + oExpire.toGMTString() + sDomain;
            }
            document.cookie = sCookie;
        }
    }
}

SessionCookieUtility.getCookieValue = function(cname){
    var nameEQ = cname + "=";
    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;
}

SessionCookieUtility.getSubCookieValue = function(cname, subname){
    var cookie = document.cookie;
    var chkdCookie = SessionCookieUtility.removeBlanks(cookie);
    var aCookie = chkdCookie.split(";");
    var iCookie = SessionCookieUtility.getCookieIndex(aCookie, cname);
    var iSubCookie = -1;
    
    if (iCookie >= 0) {
        var aSubCookie = aCookie[iCookie].split("&");
        var iSubCookie = SessionCookieUtility.getSubCookieIndex(aSubCookie, subname);
    }
    
    var sReturn = "";
    if (iSubCookie >= 0) {
        var aT = aSubCookie[iSubCookie].split("=");
        if (iSubCookie > 0) {
            sReturn = aT[1];
        } else {
            sReturn = aT[2];
        }
    }
    return sReturn;
}

//Method to get the domain string in case the cookie is shared accross servers
SessionCookieUtility.getDomain = function(){
    var domain = '';
    if (SessionCookieUtility.COOKIE_DOMAIN != '') {
        domain = sDOMAIN + SessionCookieUtility.COOKIE_DOMAIN;
    }
    return domain;
}

SessionCookieUtility.getSubCookieIndex = function(aSubCookies, thename){
    var splitValues;
    var i;
    for (i = 0; i < aSubCookies.length; ++i) {
        if (i == 0) {
            splitValues = aSubCookies[i].split("=");
            if (splitValues[1] == thename) {
                return i;
            }
        } else {
            splitValues = aSubCookies[i].split("=");
            if (splitValues[0] == thename) {
                return i;
            }
        }
    }
    return -1;
}

SessionCookieUtility.getCookieIndex = function(aCookies, thename){
    var splitValues;
    var i;
    for (i = 0; i < aCookies.length; ++i) {
        splitValues = aCookies[i].split("=");
        if (splitValues[0] == thename) {
            return i;
        }
    }
    return -1;
}

SessionCookieUtility.removeBlanks = function(strng){
    var result = "";
    var i;
    var chrn;
    for (i = 0; i < strng.length; ++i) {
        chrn = strng.charAt(i);
        if (chrn != " ") result += chrn;
    }
    return result;
}
SessionCookieUtility.getuserInfoZipcode = function(cookieString) {
var subElements = cookieString.split(",");
var subElemPairs = new Array();
var subNameValues = new Array();

// Obtain sub-element names and values.
for (i = 0; i < subElements.length; i++)
{
    subElemPairs[i] = subElements[i].split("=");
}

// Place sub-element name-value pairs in an associative array.
for (i = 0; i < subElemPairs.length; i++)
{
    subNameValues[subElemPairs[i][0]] = subElemPairs[i][1];
}

var requestedElemName = "zip";
var resultingElemValue = subNameValues[requestedElemName];
return resultingElemValue.split("+")[1];
}


//this function is load all the widgets required for the build and price page.
function startWidgets() {
    var widgets = new Object( ) ;
    var widgetName = "flowController";
    widgets[widgetName] = new Array();
    widgets[widgetName].push( {'widgetClass': "com.forddirect.application.bp20.flow.FlowController", 'widgetLocation': __appBasePath+"static/com/forddirect/application/bp20/flow/FlowController.js", 'widgetId': "flowController", "type":"js", "initParams":{}});
    log4javascript.getDefaultLogger( ).debug( "START the first call" ) ; 
    var completionEvent = wtk.loadWidgets( widgets, true ) ;
    log4javascript.getDefaultLogger( ).debug( "START the last call" ) ;
    completionEvent.subscribe( mashup, widgets ) ; 
}

//function to glue the individual widgets.
function mashup(mashupEvent, firedData, subscribedData ) {

    
    var widgets = subscribedData ;
    var widgetArray = wtk.widgetInstances ;

    log4javascript.getDefaultLogger( ).debug( "START OF---mashup" ) ; 
    //The reference to all the objects is copied in the variable by the name Object <Widget> for easy usage
    var flowControllerWidget = widgetArray[widgets[0].loaderId] ;

    //The initial load event is defined and the *DATA* Widgets are set. Subscribing Data Widgets rather UI Widgets to the initial load event might save some checks when 2 UI widgets share the same Data Widget. In the latter case, all the UI Widgets might trigger the call to the same Data widget and in some synchronization issue, the data widget might trigger 2 calls for the data.
    //The UI Widgets can subscribe to the event and use it for locking and flagging.
    initialLoadEvent = new YAHOO.util.CustomEvent("initialLoadEvent");
    initialLoadEvent.fire( ) ;

    log4javascript.getDefaultLogger( ).debug( "END OF---mashup" ) ; 
}
//widgets for the build and price page should be loaded after the widget tool kit has been loaded completely.

wtk.initCompleteEvent.subscribe( startWidgets ) ; 
//Refer to the file WidgetToolkit.js for more information about the wtk object 
