/*!
 * Copyright © 1999-2011 TeaLeaf Technology, Inc.
 * All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY TEALEAF ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE DISCLAIMED.
 * IN NO EVENT SHALL TEALEAF 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.
 *
 * @fileoverview
 * This is the main UI Client Event Capture JavaScript file that is
 * used by other JavaScript to register their onload routines.
 *
 * @requires
 * TeaLeafCfg.js
 *
 * @version 2011.07.22.1
 *
 */

if (typeof TeaLeaf !== "undefined" &&
    ((typeof TeaLeaf.replay === "function") ? !TeaLeaf.replay() : !TeaLeaf.replay) &&
    TeaLeaf.Configuration &&
    !TeaLeaf.Configuration.tlinit)
{
  TeaLeaf.Configuration.tlinit = true;
  if (!TeaLeaf.tlBrowser) {
    // tlBrowser contains the detected browser. This is determined after the
    // page loads. See PageSetup() for implementation details.
    TeaLeaf.tlBrowser = { "UNKNOWN": true };
  }
  if (!TeaLeaf.$C) {

    TeaLeaf.$C = function(attr) {
      return attr;
    };
  }

  if (!Array.prototype.push) {
    Array.prototype.stackEnd = 0;
    /**
     * Add push if the browser does not supply
     * them with the Array object (IE6 and earlier)
     * @addon
     */
    Array.prototype.push = function(obj) {
      this[this.stackEnd] = obj;
      this.stackEnd++;
    };
  }
  if (!Array.prototype.pop) {
    /**
     * Add pop if the browser does not supply
     * them with the Array object (IE6 and earlier)
     * @addon
     */
    Array.prototype.pop = function(obj) {
      this.stackEnd--;
      return this[this.stackEnd];
    };
  }

  /* XHR Factory (Singleton)
   * Provides the interface for creating and requesting XMLHttpRequests
   *
   * createXHRObject()
   * Creates and returns a new XMLHttpRequest object.
   *
   * xhrRequest(reqMethod, reqUrl, reqHeaders, reqData, reqAsync, callback, xhr)
   * Makes an XMLHttpRequest and also returns the XMLHttpRequest object.
   * @param reqMethod
   *        "GET" or "POST"   
   * @param reqUrl
   *        The request URL.
   * @param reqHeaders
   *        Optional array of HTTP header objects in the form of {name, value} pairs.
   * @param reqData
   *        Optional request data.
   * @param reqAsync
   *        Optional true or false. Default 'false'
   * @param callback
   *        Optional callback object {loaded, success, failure}
   * @param xhr
   *        Optional XHR object to use. If not provided, a new XHR object is created.
   */
  TeaLeaf.XHRFactory = (function () {
    var isHttpSuccess,
        MAX_XHR_WAIT_TIME;

    // Private properties.
    /* Timeout for XHR requests (milliseconds)
     */
    MAX_XHR_WAIT_TIME = 30000;

    // Private methods.
    isHttpSuccess = function(statusCode) {
      if ((statusCode >= 200 && statusCode < 300) ||
          statusCode === 304)
      {
        return true;
      }
      return false;
    }
  
    // The public interface object.
    return {
      "createXHRObject": function() {
        var i,
            methods,
            xhr;

        methods = [
          // All modern browsers
          function () { return new XMLHttpRequest(); },
          // IE 6 (on some platforms)
          function () { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); },
          // IE 5.5, IE 6 (on some platforms)
          function () { return new ActiveXObject("Microsoft.XMLHTTP"); }
        ];

        for (i = 0; i < methods.length; i++) {
          try {
            // Try each of the functions
            xhr = methods[i]();
          }
          catch (e) {
            // Did not work
            continue;
          }

          if (xhr) {
            // Success! Memoize for the future
            this.createXHRObject = methods[i];
            return xhr;
          }
        }
        // None of the methods works!
        return null;
      },

      "xhrRequest": function(reqMethod, reqUrl, reqHeaders, reqData, reqAsync, callback, xhr) {
        var i,
            timeoutID;

        if (!reqMethod || !reqUrl) {
          return null;
        }
        reqMethod = reqMethod.toUpperCase();

        if (!xhr) {
          xhr = this.createXHRObject();
        }
        if (!xhr) {
          return null;
        }
        // Setup the callbacks but only if this is going to be an asynchronous request
        if (reqAsync) {
          xhr.onreadystatechange = function() {
            var status,
                statusText;

            try {
              switch (xhr.readyState) {
                case 0:  // UNSENT
                  break;
                case 1:  // OPENED
                  break;
                case 2:  // HEADERS_RECEIVED
                  if (callback && callback.loaded) {
                    /* Per W3C, status and statusText should exist as this state is triggered
                     * after HTTP response headers have been received. However, we ignore this
                     * callback as all browsers do not seem to implement it correctly.
                     */
                    try {
                      status = xhr.status;
                      statusText = xhr.statusText;
                    }
                    catch (e) {
                      // Set default values
                      if (!status) {
                        status = 0;
                      }
                      if (!statusText) {
                        statusText = "None";
                      }
                    }
                    finally {
                      callback.loaded(status, statusText);
                    }
                  }
                  break;
                case 3:  // LOADING
                  break;
                case 4:  // DONE
                  if (isHttpSuccess(xhr.status)) {
                    if (callback && callback.success) {
                      callback.success(xhr.responseText, xhr.responseXML);
                    }
                  }
                  else {
                    if (callback && callback.failure) {
                      callback.failure(xhr.status, xhr.statusText);
                    }
                  }
                  break;
                default:  // UNKNOWN
                  break;
              }
            } catch (e) {
              // Ignore unhandled exceptions in callback routines.
            }
          };
        }

        xhr.open(reqMethod, reqUrl, reqAsync);
        if (reqHeaders) {
          for (i = 0; i < reqHeaders.length; i++) {
            xhr.setRequestHeader(reqHeaders[i].name, reqHeaders[i].value);
          }
        }
        // Send the request along with POST data (if any)
        if (reqMethod !== "POST" || !reqData) {
          reqData = null;
        }

        if (reqAsync) {
          try {
            // Finally, schedule the cleanup before sending the request.
            timeoutID = setTimeout(function () { 
                                     TeaLeaf.XHRFactory.deleteXHRObj(xhr);
                                   }, MAX_XHR_WAIT_TIME);
            xhr.timeoutID = timeoutID;
          } catch (e) {
            // Expected if using an ActiveX object.
          }
        }
        xhr.send(reqData);

        return xhr;
      },

      "deleteXHRObj": function(xhr) {
        if (xhr && xhr.readyState !== 4) {
          if (xhr.abort) {
            xhr.abort();
          }
        }
        // Cancel any pending timeout.
        if (xhr.timeoutID) {
          clearTimeout(xhr.timeoutID);
          xhr.timeoutID = null;
        }
        // Cleanup
        xhr.onreadystatechange = function () {};
        xhr = null;
      }
    };
  })();

  /* Request API
   *
   */
  TeaLeaf.Request = function () {
    var data,
        headers,
        method,
        url;

    // Private properties
    data = headers = url = null;
    method = "POST";

    // Privileged methods
    this.getUrl = function () {
      // Get the appropriate URL
      var TCfg,
          tmpPath,
          tmpUrl,
          windowLocation,
          windowProtocol;

      if (url) {
        return url;
      }
      TCfg = TeaLeaf.Configuration;
      windowLocation = window.location;
      windowProtocol = windowLocation.protocol;
      tmpUrl = windowProtocol + "//" + windowLocation.host;
      if (windowProtocol == "http:") {
        tmpPath = TCfg.tlurl;
      }
      else {
        tmpPath = TCfg.tlsecureurl;
      }
      // Is this a site-root relative vs. page relative path
      if (tmpPath.substr(0, 1) == "/") {
        // site-root relative
        tmpUrl += tmpPath;
      }
      else {
        // page relative
        tmpUrl += windowLocation.pathname.substr(0, windowLocation.pathname.lastIndexOf("/")+1) + tmpPath;
      }

      return tmpUrl;
    };

    this.setUrl = function (newUrl) {
      url = newUrl;
    };

    this.getMethod = function () {
      return method;
    };

    this.setMethod = function (newMethod) {
      method = newMethod;
    };

    this.getData = function () {
      return data;
    };

    this.setData = function (newData) {
      var length;

      data = newData;
      if (data) {
        length = TeaLeaf.Request.totalDataLength || 0;
        length += data.length;
        TeaLeaf.Request.totalDataLength = length;
      }
    };

    this.getHeaders = function () {
      return headers;
    };

    this.setHeaders = function(newHeaders) {
      headers = newHeaders;  
    };

    this.clear = function () {
      data = headers = url = null;
    };
  };

  TeaLeaf.Request.prototype = {
    send: function(callback) {
      var iframeNode,
          iframeWindow,
          thatRequest,
          thatTealeaf,
          TCfg,
          xhr;

      TCfg = TeaLeaf.Configuration;

      // Check configuration
      if (!TCfg.xd_iframeID) {
        // Use direct XHR
        xhr = TeaLeaf.XHRFactory.xhrRequest(this.getMethod(), this.getUrl(), this.getHeaders(), this.getData(), TCfg.xhrAsync, callback);
        if (!xhr) {
          if (callback && callback.failure) {
            callback.failure(0, "XHR request failed!");
          }
          return;
        }
      }
      else {
        // Use TeaLeaf.Request API of the target iframe
        try {
          iframeNode = document.getElementById(TCfg.xd_iframeID);
          if (!iframeNode || !iframeNode.contentWindow) {
            if (callback && callback.failure) {
              callback.failure(0, "Could not retrive cross-domain iframe target!");
            }
            return;
          }

          iframeWindow = iframeNode.contentWindow;
          if (iframeWindow.postMessage && window.JSON && 0) {
            // TODO: Use postMessage API (JSON stringify)
            alert("Not implemented!");
          }
          else {
            thatTealeaf = iframeWindow.TeaLeaf;
            if (thatTealeaf && thatTealeaf.Request) {
              thatRequest = new thatTealeaf.Request();
              thatRequest.clear();
              this.setUrl(thatRequest.getUrl());
              thatRequest.setHeaders(this.getHeaders());
              thatRequest.setData(this.getData());
              thatRequest.send(callback);
            }
          }
        }
        catch (e) {
          if (callback && callback.failure) {
            callback.failure(0, (e.name ? (e.name + ": " + e.message) : e.toString()));
          }
          return;
        }
      }
    }
  };

  TeaLeaf.Request.GetTotalDataLength = function() {
    var length;

    length = TeaLeaf.Request.totalDataLength || 0;
    return length;
  };

  /**
   * Set TeaLeaf UI Client Event Capture as an SDK.
   * The default behavior is not set as an SDK
   * @requires
   * TeaLeafCfg.js
   * @addon
   */
  TeaLeaf.settlSDK = function () {
    TeaLeaf.Configuration.tlSDK = true;
  };

  /**
   * Reset TeaLeaf UI Client Event Capture not to act as an SDK.
   * The default behavior is not set as an SDK
   * @requires
   * TeaLeafCfg.js
   * @addon
   */
  TeaLeaf.resettlSDK = function () {
    TeaLeaf.Configuration.tlSDK = false;
  };

  /**
   * Set the url where TeaLeaf posts.
   */
  TeaLeaf.tlSetPostURL = function(tlvalue) { 
    TeaLeaf.Configuration.tlurl = tlvalue;
  }
  /**
   * Get the url where TeaLeaf posts.
   */
  TeaLeaf.tlGetPostURL = function() {
    return TeaLeaf.Configuration.tlurl;
  }

  /**
   * Random string generator
   */
  TeaLeaf.makeRandomString = function(length, inputSet) {
    var i, j,
        rv;

    if (!length || length <= 0) {
      return;
    }

    if (!inputSet) {
      // The default input set from which random characters will be chosen to create the string.
      inputSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890~!@#$%^+-?";
    }
    rv = "";
    for (i = 0; i < length; i++) {
      j = Math.floor(Math.random() * inputSet.length);
      rv += inputSet.charAt(j);
    }
    return rv;
  };

  TeaLeaf.getNodeType = function(node) {
    var nodeName,
        nodeType;

    if (!node) {
      return "";
    }

    nodeName = node.nodeName ? node.nodeName.toLowerCase() : "";
    nodeType = "";
    if (nodeName === "input" || nodeName === "object" || nodeName === "script") {
      nodeType = node.type ? node.type.toLowerCase() : "";
    }

    return nodeType;
  }

  /**
   * Array to store all the object that need to be loaded after the page is rendered.
   * NOTE: This will not be used if the UI Client Event Capture is used as an SDK.
   */
  TeaLeaf.tLoadObjs = [];
  /**
   * This function is used for the other javascript files to register their
   * onload functions to be called
   * @param obj object that is registered from other JavaScript to be loaded
   * @param functionName object function that is registered from other JavaScript to be loaded
   * @requires
   * TeaLeafCfg.js
   * @addon
   */
  TeaLeaf.addOnLoad = function(obj, functionName) {
    if (arguments.length === 1) {
      TeaLeaf.tLoadObjs.push(obj);
    }
    else if (arguments.length > 1) {
      TeaLeaf.tLoadObjs.push(obj[functionName]);
    }
  };

  /**
   * tlSetCookie: Sets the cookie value. Automatically creates the cookie if
   *              it doesn't already exist.
   * @param name
   *        cookie name.
   * @param value
   *        cookie value.
   * @param expires (optional) Date object
   *        cookie expiration. Default is null, which indicates a
   *        session cookie.
   * @param path (optional)
   *        cookie path. Default is root "/"
   * @param domain (optional)
   *        cookie domain, pages on a domain made up of more than one
   *        server can share cookie info. Default is same domain as that
   *        of the current page.
   * @param secure (optional) boolean
   *        Set to true if the stored info. should only be accessible from
   *        a secure environment (e.g. https) Default is false.
   */
  TeaLeaf.tlSetCookie = function(name, value, expires, path, domain, secure) {
    if (!name) {
      return;
    }
    document.cookie = name + "=" + value +
                      (expires ? (";expires=" + expires.toUTCString()) : "") +
                      ";path=" + (path ? path : "/") +
                      (domain ? (";domain=" + domain) : "") +
                      (secure ? ";secure" : "");
  };

  /**
   * tlGetCookieValue: Returns the cookie value if it exists.
   * @param name
   *        cookie name.
   * @addon
   */
  TeaLeaf.tlGetCookieValue = function(name) {
    var i, j,
        c,
        cookies,
        value,
        nameEQ;

    nameEQ = name + "=";
    value = null;
    cookies = document.cookie.split(';');
    for (i = 0; i < cookies.length; i++) {
      c = cookies[i];
      // Remove any leading whitespace
      for (j = 0; c.charAt(j) == ' '; j++) {
        ;
      }
      if (j) {
        c = c.substring(j, c.length);
      }
      // Compare the name
      if (c.indexOf(nameEQ) === 0) {
        value = c.substring(nameEQ.length, c.length);
        break;
      }
    }
	  return value;
  };

  /**
   * tlEraseCookie: Deletes the cookie if it exists.
   * @param name
   *        cookie name.
   * @addon
   */
  TeaLeaf.tlEraseCookie = function (name) {
    var expires;
    expires = new Date(1970, 1, 1);
	  TeaLeaf.tlSetCookie(name, "", expires);
  };

  /**
   * Browser sniffing functions.
   * CAUTION: Do not use these unless absolutely justified! For
   *          most cases where you would think about using these,
   *          object and functionality detection can be employed.
   */ 
  TeaLeaf.tlBrowserIsIE = function () {
    var TB;
    TB = TeaLeaf.tlBrowser;
    if (TB) {
      return !!TB["MSIE"];
    }
    return false;
  };

  TeaLeaf.tlBrowserIsMozilla = function () {
    var TB;
    TB = TeaLeaf.tlBrowser;
    if (TB) {
      return !!TB["MOZILLA"];
    }
    return false;
  };

  TeaLeaf.tlBrowserIsWebKit = function () {
    var TB;
    TB = TeaLeaf.tlBrowser;
    if (TB) {
      return !!TB["WEBKIT"];
    }
    return false;
  };

  TeaLeaf.tlBrowserIsOpera = function () {
    var TB;
    TB = TeaLeaf.tlBrowser;
    if (TB) {
      return !!TB["OPERA"];
    }
    return false;
  };

  TeaLeaf.tlBrowserIsUnknown = function () {
    var TB;
    TB = TeaLeaf.tlBrowser;
    if (TB) {
      return !!TB["UNKNOWN"];
    }
    return false;
  };

  /**
   * Keepalive
   * This functionality is used to determine how long the UI SDK
   * remains active on the page. If the keepalive callback function
   * does not register any activity the inactivity timer will trigger.
   * 
   * When the inactivity timer triggers, the action taken is dependent
   * on the configuration specified.
   *
   * If tlDisableIfInactive is set to true, the UI SDK will detach all
   * it's event listeners (for a hard disable) and not report on any
   * subsequent user activity.
   *
   * If tlDisableIfInactive is set to false, the UI SDK will NOT detach
   * it's event listeners (for a soft disable) but will continue to monitor
   * for user activity and report on it. If there is no user activity,
   * the UI SDK will not report on the beforeunload/unload event.
   */
  (function () {
    // Private members
    var T,
        TC,
        TCfg,
        TE,
        acTimerID,
        activityFlag,
        disabled;

    T = TeaLeaf;
    TC = T.Client;
    TE = T.Event;
    TCfg = T.Configuration;
    acTimerID = null;
    disabled = false,
    activityFlag = true;

    // Public members
    T.tlDisable = function () {
      // Soft disable.
      activityFlag = false;

      // Hard disable. tlDisableIfInactive == true
      if (TCfg.tlDisableIfInactive && !disabled) {
        try {
          TE.tlFlushQueue(true);
          TC.tlDetachFromAllControls();
          // Detach the beforeunload/unload handlers
          TeaLeaf.Event.tlRemoveHandler(window, "beforeunload", TeaLeaf.Event.tlBeforeUnload, false);
          TeaLeaf.Event.tlRemoveHandler(window, "unload", TeaLeaf.Event.tlUnload, false);
        }
        catch(e) {
          // Do nothing.
        }
        disabled = true;
      }
    };

    T.activitySinceDisabled = function () {
      return activityFlag;
    };

    /**
     * Call this function to indicate any user activity. Calling this
     * function resets the inactivity timer and activity flag.
     *
     * Currently called from TeaLeaf.Event.tlSend()
     */
    T.tlKeepAlive = function () {
      if (acTimerID) {
        window.clearTimeout(acTimerID);
        acTimerID = null;
      }
      // Setup the inactivity timer
      if (!disabled && TCfg.tlActivityTimeout) {
        // Reset the inactivity timer
        acTimerID = window.setTimeout(function () {
                                        T.tlDisable();
                                      }, (TCfg.tlActivityTimeout * 60000));
      }
      if (!activityFlag) {
        // Reset
        activityFlag = true;
      }
    };
  })(); 
  
  /**
   * This function is used to load UI Client Event Capture or the
   * UI Client Event Capture SDK.
   * @requires
   * TeaLeafCfg.js
   * @addon
   */
  TeaLeaf.PageSetup = function () {
    var i,
        cValue,
        expires,
        iframeNode,
        iframeSrc,
        now,
        T,
        TCfg,
        TCfgGUIDCookie,
        ua;

    // Note: FF versions prior to 3.6 do not support document.readyState
    if (document.readyState && document.readyState !== "complete") {
      // Page has not been loaded yet!
      return;
    }

    T = TeaLeaf;
    TCfg = T.Configuration;
    TCfgGUIDCookie = TCfg.tlGUIDCookie;

    if (T.PageSetup.Complete) {
      // Being called more than one time.
      return;
    }
    T.PageSetup.Complete = true;

    // Cleanup callback (if one exists)
    if (T.PageSetup.Cleanup) {
      T.PageSetup.Cleanup();
    }

    // Browser detection based on the User Agent
    T.tlBrowser["UNKNOWN"] = false;
    ua = navigator.userAgent.toLowerCase();
    if (/opera|presto/.test(ua)) {
      T.tlBrowser["OPERA"] = true;
    }
    else if (/(apple)?webkit|safari|chrome/.test(ua)) {
      T.tlBrowser["WEBKIT"] = true;
    }
    else if (/msie|trident/.test(ua)) {
      T.tlBrowser["MSIE"] = true;
    }
    else if (/^(?=.*?\b(mozilla|gecko|firefox)\b)((?!compatible).)*$/.test(ua)) {
      T.tlBrowser["MOZILLA"] = true;
    }
    else {
      T.tlBrowser["UNKNOWN"] = true;
    }

    // Cross domain initialization and iframe creation (optional)
    if (TCfg.xd_CommonDomain) {
      try {
        document.domain = TCfg.xd_CommonDomain;
      }
      catch (e) {
      }
    }
    if (TCfg.xd_iframeID) {
      try {
        // check if the cross-domain iframe exists
        iframeNode = document.getElementById(TCfg.xd_iframeID);
        if (!iframeNode) {
          // create the iframe
          iframeSrc = ((window.location.protocol === "http:") ? TCfg.xd_iframeSrcURL : TCfg.xd_iframeSrcURLSecure);
          if (iframeSrc) {
            iframeNode = document.createElement("IFRAME");
            if (iframeNode) {
              iframeNode.id = TCfg.xd_iframeID;
              iframeNode.src = iframeSrc;
              iframeNode.style.display = "none"
              iframeNode.style.visibility = "hidden";
              document.body.appendChild(iframeNode);
            }
          }
        }
      }
      catch (e) {
      }
    }

    // The SDK GUID
    if (TCfg.tlSetGUID) {
      if (!TCfgGUIDCookie || !TCfgGUIDCookie.name) {
      }
      else {
        // Check for optional members and assign defaults wherever applicable
        if (!TCfgGUIDCookie.valueLength) {
          TCfgGUIDCookie.valueLength = 32;
        }
        if (!TCfgGUIDCookie.valueSet) {
          TCfgGUIDCookie.valueSet = "0123456789ABCDEF";
        }

        cValue = T.tlGetCookieValue(TCfgGUIDCookie.name);
        if (!cValue) {
          now = new Date();
          cValue = T.makeRandomString(TCfgGUIDCookie.valueLength, TCfgGUIDCookie.valueSet);
          expires = TCfgGUIDCookie.expires ? new Date(now.getTime() + TCfgGUIDCookie.expires * 60 * 1000) : null;
          // Create a new cookie
          T.tlSetCookie(TCfgGUIDCookie.name, cValue, expires, TCfgGUIDCookie.path, TCfgGUIDCookie.domain, TCfgGUIDCookie.secure);
        }
      }
    }
    if (!TCfg.tlSDK) {
      for (i=0; i < T.tLoadObjs.length; i++) {
        T.tLoadObjs[i]();
      }
    }
    T.EndLoad = new Date();
  };

  if (document.readyState === "complete") {
    // Page is already initialized!
    TeaLeaf.PageSetup();
  }
  else if (document.addEventListener) {
    // Mozilla, Opera and Webkit
    document.addEventListener("DOMContentLoaded", TeaLeaf.PageSetup, false);
    // fallback
    window.addEventListener("load", TeaLeaf.PageSetup, false);
    TeaLeaf.PageSetup.Cleanup = function () {
      var T;

      T = TeaLeaf;
      document.removeEventListener("DOMContentLoaded", T.PageSetup, false);
      window.removeEventListener("load", T.PageSetup, false);
    }
  }
  else if (document.attachEvent) {
    // IE
    document.attachEvent("onreadystatechange", TeaLeaf.PageSetup);
    // fallback
    window.attachEvent("onload", TeaLeaf.PageSetup);
    TeaLeaf.PageSetup.Cleanup = function () {
      var T;
      
      T = TeaLeaf;
      document.detachEvent("onreadystatechange", T.PageSetup);
      window.detachEvent("onload", T.PageSetup);
    }
  }
  else {
    // others
    if (typeof window.onload === "function" ) {
      TeaLeaf.OnLoad = window.onload;
    }
    else {
      TeaLeaf.OnLoad = null;
    }
    window.onload = function() {
      var T;

      T = TeaLeaf;
      T.PageSetup();
      window.onload = T.OnLoad;
      if (T.OnLoad) {
        T.OnLoad();
      }
    };
  }
}

