/*                                                                  
* Copyright © 1999-2009 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 
* Event and communication setup.   
*
* @requires 
* TeaLeaf.js
* TeaLeafEventCfg.js
*
* @version 2009.02.12.1
*                                                                   
*/
if(TeaLeaf.Event && TeaLeaf.Event.Configuration){
 try{
     if(typeof TeaLeaf_PageID == "undefined"){
   TeaLeaf_PageID = null;
  }
 }
 catch(e){
  TeaLeaf_PageID = null;
 }
    
    TeaLeaf.Event.tlQueuedXML = "";
    /**
    * Get TeaLeaf UI Client Event content type that 
    * is sent in the HTTP headers of the TeaLeaf AJAX POST
    * that delivers the XML with the UI Cient Events to the 
    * capture device. 
    * @addon
    */
    TeaLeaf.Event.tlGetContentType = function(){
        var contentType = "text/xml";
        return contentType;
    }
    /**
    * Get TeaLeaf UI Client Event XEvent that 
    * is sent in the HTTP headers of the TeaLeaf AJAX POST
    * that delivers the XML with the UI Cient Events to the 
    * capture device. 
    * @addon
    */
    TeaLeaf.Event.tlGetTeaLeafXEvent = function(){
        var teaLeafXEvent = "ClientEvent";
        return teaLeafXEvent;
    }
    /**
    * Get TeaLeaf UI Client Event type set during
    * TeaLeaf event definition.
    * @addon
    */    
    TeaLeaf.Event.tlEventType = function(){
        return TeaLeaf.Event.SetType;
    }
    /**
    * Get TeaLeaf UI Client Event sub type set during
    * TeaLeaf event definition.
    * @addon
    */        
    TeaLeaf.Event.tlEventSubType = function(){
        return TeaLeaf.Event.SetSubType;
    }
    /**
    * Get the path relative to the host.
    * @addon
    */            
    TeaLeaf.Event.tlGetUrlPath = function(){
        var strpath = window.location.pathname;
        return strpath;
    }
    /**
    * Get TeaLeaf UI Client Event version that 
    * is sent in the HTTP headers of the TeaLeaf AJAX POST
    * that delivers the XML with the UI Cient Events to the 
    * capture device. 
    * @requires 
    * TeaLeafEventCfg.js
    * @addon
    */
    TeaLeaf.Event.tlGetJSVersion = function(){
        return TeaLeaf.Configuration.tlversion;
    }
    /**
    * Get the resolution type (0-4) based on the resolution defined in 
    * the configuration file. 
    * @param width 
    * @param height 
    * @requires 
    * TeaLeafEventCfg.js
    * @addon
    */
    TeaLeaf.Event.tlResolutionType = function(width, height){ 
        var res = TeaLeaf.Event.Configuration.tlResolution;
        for(var i=0; i<res.length; i++)
        {
            if(width <= res[i].width || height <= res[i].height)
            {
                return res[i].type;
            }
        }
        return res[length-1].type;        
    }
    /**
    * Get the browser resolution type. 
    * @requires 
    * TeaLeafEventCfg.js
    * @addon
    */
    TeaLeaf.Event.tlResolutionTypeBrowser = function(){
        var winWidth = 0;
        var winHeight = 0;  
        if(window.innerWidth){
            winWidth = window.innerWidth;
            winHeight = window.innerHeight;
        }
        else if(document.documentElement && document.documentElement.clientWidth){   
            winWidth = document.documentElement.clientWidth;
            winHeight = document.documentElement.clientHeight;
        }
        else if(document.body && document.body.clientWidth){
            winWidth = document.body.clientWidth;
            winHeight = document.body.clientHeight;
        }
        else{
            var elems = document.getElementsByTagName("body"); 
            if(elems.length > 0){
                winWidth = elems[0].clientWidth;
                winHeight = elems[0].clientHeight;
            }
        }                
        var retType = TeaLeaf.Event.tlResolutionType(winWidth, winHeight);  
        return retType;
    }
    /**
    * Get the page render time. 
    * @requires
    * TeaLeaf.js
    * TeaLeafCfg.js 
    * TeaLeafEventCfg.js
    * @addon
    */    
    TeaLeaf.Event.tlGetRenderTime = function(){
        return TeaLeaf.Event.PageLoadMilliSecs;
    }
    /**
    * Get element count. 
    * @param element DOM element name 
    * @addon
    */        
    TeaLeaf.Event.tlGetElementCount = function(element){
        return document.getElementsByName(element).length;      
    }
    /**
    * Get count of broaken images. 
    * @addon
    */            
    TeaLeaf.Event.tlBadImageCount = function() {
  var cnt = 0;
  var ind;
  for(ind = 0; ind < document.images.length; ind++) {
   var img = document.images[ind];
   // IE correctly identifies any images that weren't downloaded as
   // not complete. Others should too. Gecko-based browsers act
   // like NS4 in that they report this incorrectly.
      if (!img.complete) {
          cnt++;
    continue;
      }
      // However, they do have two very useful properties: naturalWidth and
      // naturalHeight. These give the true size of the image. If it failed
      // to load, either of these should be zero.
      if (typeof img.naturalWidth != "undefined" && img.naturalWidth == 0) {
          cnt++;
      }
     }
     return cnt;
 } 
    /**
    * Get TeaLeaf current event count. 
    * @addon
    */             
 TeaLeaf.Event.tlGetEventCount = function(){
        return TeaLeaf.Event.Configuration.tleventcount;      
    }
    /**
    * Get sent sting length. 
    * @param sendStr get lenght of sendStr
    * @addon
    */             
    TeaLeaf.Event.tlGetSendStringBytes = function(sendStr){
        return sendStr.length;      
    }
    /**
    * Get user dwell time on a page.
    * @requires
    * TeaLeaf.js
    * TeaLeafCfg.js 
    * TeaLeafEventCfg.js 
    * @addon
    */             
    TeaLeaf.Event.tlGetDwellTime = function(){
        return TeaLeaf.Event.tlDateDiff(TeaLeaf.tlStartLoad, TeaLeaf.Event.Configuration.tllastdwelltime);
    }
    /**
    * Get the ID of the last visited DOM element that we have listeners attached.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                 
    TeaLeaf.Event.tlGetLastVisitedElementID = function(){
        return TeaLeaf.Event.Configuration.tlidoflastvisitedcontrol;
    }
    /**
    * Get the date difference between two values.
    * @param v1 first time value 
    * @param v2 second time value 
    * @addon
    */                     
    TeaLeaf.Event.tlDateDiff = function(v1, v2) {
  return Math.abs(v1-v2);
 }
    /**
    * Get the XForm path string with ids or names in fill out order.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                  
 TeaLeaf.Event.tlGetVisitOrder= function(){
     return TeaLeaf.Event.Configuration.tlvisitorder;
 }
    /**
    * Re-format the XML.
    * @param Str containing XML to be re-formated 
    * @addon
    */                     
    TeaLeaf.Event.tlFormatXML = function(Str) {
        if (Str) {
   if( Str.replace ) {
             return Str.replace(/&/g, "&amp;").replace(/\"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
   }
   return Str;
  }
        return "";
    }
    /**
    * Get cookie value.
    * @param name cookie name 
    * @addon
    */                         
    TeaLeaf.Event.tlGetCookie = function(name){
     var dc = document.cookie;
     var prefix = name + "=";
     var begin = dc.indexOf("; " + prefix);
     if (begin == -1) {
      begin = dc.indexOf(prefix);
      if (begin != 0) {
       return "";
      }
     }
     else {
      begin += 2;
     }
     var end = document.cookie.indexOf(";", begin);
     if (end == -1) {
      end = dc.length;
     }
     return unescape(dc.substring(begin + prefix.length, end));
    }  
    /**
    * Set HTTP headers.
    * @param tlreq XMLHTTPRequest object 
    * @param tlheaderconfig JSON array with the HTTP header field values. 
    * @requires
    * TeaLeaf.js
    * TeaLeafCfg.js 
    * TeaLeafEventCfg.js 
    * @addon
    */             
    TeaLeaf.Event.tlSetHTTPHeaders = function(tlreq, tlheaderconfig){    
        for(var i=0; i<tlheaderconfig.length; i++) {
      if(tlheaderconfig[i].tlsethttpheader == true){
       tlreq.setRequestHeader(tlheaderconfig[i].tlreqhttpheadername, eval(tlheaderconfig[i].tlreqhttpheadervalue));
   }
        }
    }
    /**
    * Get TeaLeaf page id.
    * @requires
    * TeaLeaf.js
    * TeaLeafCfg.js 
    * TeaLeafEventCfg.js 
    * @addon
    */                 
    TeaLeaf.Event.tlGetPageId = function(){
     // Have we already calculated this?
     if(TeaLeaf.Event.Configuration.tlpageid) {
      return TeaLeaf.Event.Configuration.tlpageid;
     }
     // Calculate the page id.  First see if there is a
     // cookie value to be used.  If that value is there,
     // then we will use it
     if( TeaLeaf.Event.Configuration.tlpageidcookie ) {
      TeaLeaf.Event.Configuration.tlpageid = TeaLeaf.Event.tlGetCookie(TeaLeaf.Event.Configuration.tlpageidcookie);
      if(TeaLeaf.Event.Configuration.tlpageid) {
       return TeaLeaf.Event.Configuration.tlpageid;
      }
     }
     // No cookie.  Look for the page id variable that will be
     // set by javascript outside of TeaLeaf.js
     if( TeaLeaf_PageID ) {
   TeaLeaf.Event.Configuration.tlpageid = TeaLeaf_PageID;
   return TeaLeaf.Event.Configuration.tlpageid;
     }
    
     // Neither of the above options, go ahead and generate the
     // page id from a time stamp.
     TeaLeaf.Event.Configuration.tlpageid = "ID" + TeaLeaf.tlStartLoad.getHours() + "H" +
         TeaLeaf.tlStartLoad.getMinutes() + "M" +
         TeaLeaf.tlStartLoad.getSeconds() + "S" +
         TeaLeaf.tlStartLoad.getMilliseconds();
     return TeaLeaf.Event.Configuration.tlpageid;
    }
    /**
    * Send failure message.
    * @param url url 
    * @param failedUrl url where failure occured 
    * @param message failure message 
    * @requires
    * TeaLeaf.js
    * TeaLeafCfg.js 
    * TeaLeafEventCfg.js 
    * @addon
    */                 
    TeaLeaf.Event.tlSendFailure = function(url, failedUrl, message){
     var tlnow = new Date();
     var t1970 = Date.UTC(tlnow.getUTCFullYear(),tlnow.getUTCMonth(),tlnow.getUTCDate(), tlnow.getUTCHours(),tlnow.getUTCMinutes(),tlnow.getUTCSeconds(), tlnow.getUTCMilliseconds());
    
     var tltimeDur;
     if( TeaLeaf.tlStartLoad ) {
      tltimeDur = TeaLeaf.Event.tlDateDiff(tlnow, TeaLeaf.tlStartLoad);
     }
     TeaLeaf.Event.Configuration.tleventcount++;
     tlsendStr = "<ClientEvent count=\"" + TeaLeaf.Event.Configuration.tleventcount +
         "\" Type=\"INFO\" SubType=\"EXCEPTION\" " +
         "PageId=\""        + TeaLeaf.Event.tlGetPageId()+ "\" " +
         "FailedUrl=\""     + TeaLeaf.Event.tlFormatXML(failedUrl) + "\" " +
         "Message=\""       + TeaLeaf.Event.tlFormatXML(message)   + "\" " +
         "TimeDuration=\""  + tltimeDur + "\" " +
         "DateSince1970=\"" + t1970 + "\" />\r\n";
     // Send the request
     try {
         TeaLeaf.Event.Configuration.tlasync = true;
         var tlExceptionEvent = new TeaLeaf.Event("INFO", "EXCEPTION");
      tlExceptionEvent.tlSendXML(tlsendStr,true);
     }   
     catch(exc) {
         if( TeaLeaf.Event.Configuration.tlshowexceptions ) {
       alert(exc.name + ": " + exc.message + "\r\n\r\nPos 4");
   }
     }
    }   
    /**
    * Create the XMLHTTPRequest transport object.
    * @addon
    */                                   
    TeaLeaf.Event.tlGetTransport = function(){
     var tlreq;
     if(window.XMLHttpRequest) {
      try {
       tlreq = new XMLHttpRequest();
      }
      catch(e) {
       tlreq = null;
      }
     }
     else if(window.ActiveXObject) {
      try {
       tlreq = new ActiveXObject("Msxml2.XMLHTTP");
      }
      catch(e) {
       try {
        tlreq = new ActiveXObject("Microsoft.XMLHTTP");
       }
       catch(e) {
        tlreq = null;
       }
      }
     }
     return tlreq;
    }
    TeaLeaf.Event.TransportArray = [];
    
    /**
    * Get the XMLHTTPRequest transport object from the Transport Array if not create one.
    * @addon
    */                                   
    TeaLeaf.Event.tlXMLHTTPObj = function(){   
      var i = 0;
     for(; i < TeaLeaf.Event.TransportArray.length; i++) {
      if( TeaLeaf.Event.TransportArray[i] && TeaLeaf.Event.TransportArray[i].readyState > 0 ) {
       if( TeaLeaf.Event.TransportArray[i].readyState == 4 ) {
        TeaLeaf.Event.TransportArray[i].abort();
        TeaLeaf.Event.TransportArray[i].onreadystatechange = new function() {};
        return TeaLeaf.Event.TransportArray[i];
       }
      }
      else {
       TeaLeaf.Event.TransportArray[i] = TeaLeaf.Event.tlGetTransport();
       return TeaLeaf.Event.TransportArray[i];
      }
     }
     // Nope, we need another
     TeaLeaf.Event.TransportArray[i] = TeaLeaf.Event.tlGetTransport();
     return TeaLeaf.Event.TransportArray[i];
    }  
    /**
    * Clean the XMLHTTPRequest Transport Array.
    * @addon
    */                                       
    TeaLeaf.Event.tlCleanXMLHTTPObj = function(obj){
     // Zap this one!
     var i = 0;
     for(; i < TeaLeaf.Event.TransportArray.length; i++) {
      if( obj == TeaLeaf.Event.TransportArray[i] ) {
       TeaLeaf.Event.TransportArray[i] = null;
      }
     }   
    }
    /**
    * Add event handler.
    * @param tlitem element that we attach a listener
    * @param tlevt event that we listen for
    * @param tlhandler event handler
    * @addon
    */                                           
    TeaLeaf.Event.tlAddHandler = function(tlitem, tlevt, tlhandler, tlcapture) {  
  try {
       if( tlitem.addEventListener ) {
     if(navigator.userAgent.toLowerCase().indexOf('safari')!=-1){
          tlitem.addEventListener('on'+tlevt, tlhandler, tlcapture);                                          
     }
     else{
          tlitem.addEventListener(tlevt, tlhandler, tlcapture);
     }
       }
       else if( tlitem.attachEvent ) {
     tlitem.attachEvent('on'+tlevt, tlhandler);
       }
  }
  catch(exc) {
       if( TeaLeaf.Event.Configuration.tlshowexceptions ) {
     alert(exc.name + ": " + exc.message + "\r\n\r\nPos 4");
       }
  }
 } 
    /**
    * Remove event handler.
    * @param tlitem element that we attached a listener
    * @param tlevt event that we listened
    * @param tlhandler event handler
    * @addon
    */                                           
 TeaLeaf.Event.tlRemoveHandler = function(tlitem, tlevt, tlhandler, tlcapture) {
  try {
   if( tlitem.removeEventListener ) {
    tlitem.removeEventListener(tlevt, tlhandler, tlcapture);
   }
   else if( tlitem.detachEvent ) {
    tlitem.detachEvent('on'+tlevt, tlhandler);
   }
  }
  catch(exc) {
   if( TeaLeaf.Event.Configuration.tlshowexceptions ) {
    alert(exc.name + ": " + exc.message + "\r\n\r\nPos 5");
   }
  }
 }
    /**
    * Flush the event queue.
    * @param force forces the flush if true
    * @requires
    * TeaLeaf.js
    * TeaLeafCfg.js 
    * TeaLeafEventCfg.js 
    * @addon
    */                                           
 TeaLeaf.Event.tlFlushQueue = function(force) {
  var dataToSend = null;
  var queueTime = TeaLeaf.Event.Configuration.tlqueueeventstimer;
  var maxTime = queueTime * 3;
  // Nothing to send
  if(TeaLeaf.Event.Configuration.tlusetopqueue) {
   var now = new Date();
   var diff = (now - top.TeaLeaf.Event.TimeSent);  
   // If we have queued data, let's send it if appropriate
   if( top.TeaLeaf.Event.tlQueuedXML ) {
    if( force || diff >= queueTime ) {
     dataToSend = top.TeaLeaf.Event.tlQueuedXML;
     top.TeaLeaf.Event.tlQueuedXML = "";
     top.TeaLeaf.Event.TimeSent = now;
    }
   }
   // Nothing to send
   if( ! dataToSend ) {
    if( ! force && diff < (queueTime / 2) ) {
     // A little heuristics here--If the time is less than
     // 1/2 the standard time, then assume another frame
     // is handling the send.  Slow down the transmission
     // time for this frame.
     
     // we need to do this so we do not end up waiting infinately.
     if(queueTime >= maxTime){
         queueTime = maxTime;
     }
     else{
         queueTime = (queueTime * 3) / 2;
     }
    }
    return queueTime;
   }
  }
  else {
   if( ! TeaLeaf.Event.tlQueuedXML ) {
    return queueTime;
   }
   dataToSend = TeaLeaf.Event.tlQueuedXML;
   TeaLeaf.Event.tlQueuedXML = "";
  }
  
  // Get the Event
  var evt = new TeaLeaf.Event("GUI", "QUEUED");
  evt.tlSendXML(dataToSend);
  return queueTime;
    }
    /**
    * Push XML on the stack.
    * @param tag tag name
    * @addon
    */                                           
    TeaLeaf.Event.prototype.tlPushXML = function(tag){
     if( ! this.XMLStack ) {
      this.XMLStack = [];
     }
     
     var strTag = "  <" + tag;
     if(this.XMLData){
         this.XMLData += strTag;
     }
     else{
         this.XMLData = strTag;
     }
    }    
    /**
    * Pop XML from the stack.
    * @param tag tag name
    * @addon
    */                                           
    TeaLeaf.Event.prototype.tlPopXML = function(){
        if(this.XMLData){
         this.XMLData += " />\r\n";
     }
     else{
            return false;
     }
    }   
    /**
    * Add data tot he XML stack.
    * @param name0 name of the XML attribute.
    * @param value0 value of the XML attribute.
    * @addon
    */                                           
    TeaLeaf.Event.prototype.tlAddData = function(nameValueArray){
     var offset = "";
     if( this.XMLStack ) {
      for(var ind = 0; ind < this.XMLStack.length; ind++) {
       offset += "  ";
      }      
     }     
  var parts = [];
     for(var ind = 0; ind < nameValueArray.length; ind += 2) {
   name = nameValueArray[ind];
   tlValue = TeaLeaf.Event.tlFormatXML(nameValueArray[ind+1]);
   if(name && tlValue) 
    parts[parts.length] = offset + " " + name + "=" + "\""+tlValue+"\"";
  }
  if(!this.XMLData) this.XMLData = "";
  this.XMLData += parts.join("");
     delete nameValueArray;
    }   
    /**
    * Send the XML with the UI Client Events including the HTTP headers if set.
    * @param tlsendStr XML message
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                           
    TeaLeaf.Event.prototype.tlSendXML = function(tlsendStr, tlignoresendfailure ){
     // Get an the request object
     var tlreq = TeaLeaf.Event.tlXMLHTTPObj();
     if( ! tlreq ) {
      return;
     }
     // Send the request
     try {
      var tlurl = this.theUrl;
      tlreq.onreadystatechange = function(code) {
       if(tlreq.readyState == 2 && typeof TeaLeaf.Cookie != "undefined")
       {
    // Clear the queued xml stored in the cookie, by clearing the contents and setting the expiration to a day before
    // Done on readyState == 2, which means data has been sent and is waiting on a server response
    var d = new Date();
    d.setTime(d.getTime()-86400000);
    TeaLeaf.Cookie.tlSetCookieValue("tlQueuedXML", "", d, "/");
       }
       if( tlreq.readyState == 4 ) {
        // The try/catch is to catch a netscape bug
        // https://bugzilla.mozilla.org/show_bug.cgi?id=238559#c0
        // Thanks to JS for the help
        try {
         if( tlreq.status != 200 && tlreq.status != 304 ) {
                  if(TeaLeaf.Event.Configuration.tlignoresendfailure == true){
             TeaLeaf.Event.Configuration.tlignoresendfailure = false;
                   TeaLeaf.Event.tlSendFailure(tlurl, tlurl, "Status " + tlreq.status + ": " + tlreq.statusText);
          }
         }
        }
        catch(e) {
        }
       }
      }
      tlreq.open("POST", tlurl, TeaLeaf.Event.Configuration.tlasync);
      
   TeaLeaf.Event.tlSetHTTPHeaders(tlreq, TeaLeaf.Event.Configuration.tlHTTPRequestHeadersSet);
            //Set the TeaLeaf HTTP Header Values  
            if( TeaLeaf.Event.Configuration.tlinitflag == true ){           
                TeaLeaf.Event.tlSetHTTPHeaders(tlreq, TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalInit);
            }
            if( TeaLeaf.Event.Configuration.tlbeforeunloadflag == true ){
                TeaLeaf.Event.tlSetHTTPHeaders(tlreq, TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalBeforeUnload);
            }  
         tlreq.send(tlsendStr);
     }
     catch(exc) {
      if( TeaLeaf.Event.Configuration.tlshowexceptions ) {
       if( exc.name ) {
        alert(exc.name + ": " + exc.message + "\r\n\r\nURL: " + this.theUrl + "\r\n\r\nPos 3 ");
       }
       else {
        alert(exc + "\r\n\r\nURL: " + this.theUrl + "\r\n\r\nPos 3 ");
       }
      }     
      if(TeaLeaf.Event.Configuration.tlignoresendfailure == true){
                TeaLeaf.Event.Configuration.tlignoresendfailure = false;
          TeaLeaf.Event.tlSendFailure(this.theUrl, this.theUrl, exc);
      }  
   TeaLeaf.Event.tlCleanXMLHTTPObj(tlreq);
     }
    }
    /**
    * Depending on the configuration settings send the XML or queue the XML message.
    * @requires
    * TeaLeaf.js
    * TeaLeafCfg.js
    * TeaLeafEventCfg.js 
    * @addon
    */                                               
    TeaLeaf.Event.prototype.tlSend = function(bRoot){
     // Pop everything on the queue
     if( this.XMLStack ) {
      while( this.XMLStack.length > 0 ) {
       this.tlPopXML()
      }
     }
     var t1970 = Date.UTC(this.date.getUTCFullYear(),this.date.getUTCMonth(),this.date.getUTCDate(), 
                     this.date.getUTCHours(),this.date.getUTCMinutes(),this.date.getUTCSeconds(), this.date.getUTCMilliseconds());
     var timeDur;
     if( TeaLeaf.tlStartLoad ) {
      timeDur = TeaLeaf.Event.tlDateDiff(this.date, TeaLeaf.tlStartLoad);
     }
     TeaLeaf.Event.Configuration.tleventcount++;
     sendStr = "<ClientEvent count=\"" + TeaLeaf.Event.Configuration.tleventcount +
     "\" Type=\"" + this.EventType + "\" SubType=\"" + this.EventSubType+"\"";
     if( this.EventSource ) {
      sendStr = sendStr + "\" Source=\"" + this.EventSource+ "\"";
     }
     if(bRoot){
         sendStr = sendStr + 
           " PageId=\""        + TeaLeaf.Event.tlGetPageId() +"\""+
           " TimeDuration=\""  + timeDur + "\""+
           " DateSince1970=\"" + t1970 +
           "\" >\r\n" +
           this.XMLData +
           "</ClientEvent>\r\n";
     }
     else{
         sendStr = sendStr + 
           " PageId=\""        + TeaLeaf.Event.tlGetPageId() +"\""+
           this.XMLData        +
           " TimeDuration=\""  + timeDur + "\""+
           " DateSince1970=\"" + t1970 +
           "\" />\r\n";
     }
     // Queue the event
     if( TeaLeaf.Event.Configuration.tlqueueevents ) {
   if( TeaLeaf.Event.Configuration.tlusetopqueue ) {
    if( top.TeaLeaf.Event.tlQueuedXML ) {
     top.TeaLeaf.Event.tlQueuedXML += sendStr;
    }
    else {
     top.TeaLeaf.Event.tlQueuedXML = sendStr;
    }
   }
   else {
    if( TeaLeaf.Event.tlQueuedXML ) {
     TeaLeaf.Event.tlQueuedXML += sendStr; 
    }
    else {
     TeaLeaf.Event.tlQueuedXML = sendStr;
    }
   }
   // Check the size of the XML.  IF it is getting too
   // big, send it
   if( TeaLeaf.Event.Configuration.tlqueueeventsmaxsz < TeaLeaf.Event.tlQueuedXML.length ) {      
       TeaLeaf.Event.tlFlushQueue();
   }
   return;
     }
     // Send the request
     try {
      this.tlSendXML(sendStr);
      this.XMLData = "";
     }
     catch(exp) {
     }
     this.XMLData = "";
    }
    /**
    * Encode a string to be suitable for an XML attribute.
    * @param str
    * @addon
    */                                           
    TeaLeaf.Event.tlXMLEncode = function(str){
     if(str == null) return str;
     str = str.replace(/&/g, "&#38;");
     str = str.replace(/"/g, "&#34;");
     str = str.replace(/'/g, "&#39;");
     str = str.replace(/:/g, "&#58;");
     return str;
    }   
    /**
    * Decode a string encoded with tlXMLEncode.
    * @param str
    * @addon
    */                                           
    TeaLeaf.Event.tlXMLDecode = function(str){
     if(str == null) return str;
     str = str.replace(/&#58;/g, ":");
     str = str.replace(/&#39;/g, "'");
     str = str.replace(/&#34;/g, "\"");
     str = str.replace(/&#38;/g, "&");
     return str;
    }
    /**
    * Enable HTTP Headers defined in the TeaLeafEventCfg.js.
    * @param obj determines what set of HTTP headers to be set. 
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                
    TeaLeaf.Event.tlEnableAllHTTPHeaders = function(obj) {         
        if(obj){
            if(obj == "info"){
                TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersSet, true, "all");            
            }
            else if(obj == "init"){
                TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalInit, true, "all");
            }
            else if(obj == "beforeunload"){
                TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalBeforeUnload, true, "all");
            } 
        } 
        else{
            TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersSet, true, "all");            
            TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalInit, true, "all");
            TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalBeforeUnload, true, "all");        
        }        
    }
    /**
    * Enable HTTP Headers defined in the TeaLeafEventCfg.js.
    * @param obj determines what set of HTTP headers to be set. 
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                
    TeaLeaf.Event.tlEnableHTTPHeader = function(obj, headerName) { 
        if(obj == "info"){
            TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersSet, true, headerName);            
        }
        else if(obj == "init"){
            TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalInit, true, headerName);
        }
        else if(obj == "beforeunload"){
            TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalBeforeUnload, true, headerName);
        } 
    }
    /**
    * Disable HTTP Headers defined in the TeaLeafEventCfg.js.
    * @param obj determines what set of HTTP headers to be set. 
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                
    TeaLeaf.Event.tlDisableAllHTTPHeaders = function(obj) {         
        if(obj){
            if(obj == "info"){
                TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersSet, false, "all");            
            }
            else if(obj == "init"){
                TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalInit, false, "all");
            }
            else if(obj == "beforeunload"){
                TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalBeforeUnload, false, "all");
            } 
        } 
        else{
            TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersSet, false, "all");            
            TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalInit, false, "all");
            TeaLeaf.Event.tlEventJSONCfgUtil(TeaLeaf.Event.Configuration.tlHTTPRequestHeadersEvalBeforeUnload, false, "all");        
        }        
    }    
    /**
    * Enable queuing of events.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                
    TeaLeaf.Event.tlEnableQueueEvents = function() { 
        TeaLeaf.Event.Configuration.tlqueueevents = true; 
    }  
    /**
    * Disable queuing of events.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                
    TeaLeaf.Event.tlDisableQueueEvents = function() { 
        TeaLeaf.Event.Configuration.tlqueueevents = false; 
    }   
    /**
    * Enable showing of exception in an alert message.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                
    TeaLeaf.Event.tlEnableShowExceptions = function() { 
        TeaLeaf.Event.Configuration.tlshowexceptions = true; 
    }
    /**
    * Disable showing of exception in an alert message.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
    TeaLeaf.Event.tlDisableShowExceptions = function() { 
        TeaLeaf.Event.Configuration.tlshowexceptions = false; 
    } 
    /**
    * Set queue event flush time.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
    TeaLeaf.Event.tlSetQueueEventTime = function(tlvalue) { 
    
        TeaLeaf.Event.Configuration.tlqueueeventstimer = tlvalue; 
    }  
    /**
    * Get queue event flush time.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
    TeaLeaf.Event.tlGetQueueEventTime = function() { 
        return TeaLeaf.Event.Configuration.tlqueueeventstimer; 
    }
    /**
    * Set queue event maximum size.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
    TeaLeaf.Event.tlSetQueueEventMaxSize = function(tlvalue) { 
        TeaLeaf.Event.Configuration.tlqueueeventsmaxsz = tlvalue; 
    }    
    /**
    * Get queue event maximum size.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
    TeaLeaf.Event.tlGetQueueEventMaxSize = function() { 
        return TeaLeaf.Event.Configuration.tlqueueeventsmaxsz; 
    } 
    /**
    * Set the url where TeaLeaf posts.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
    TeaLeaf.Event.tlSetPostURL = function(tlvalue) { 
        TeaLeaf.Event.Configuration.tlurl = tlvalue; 
    }
    /**
    * Get the url where TeaLeaf posts.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
    TeaLeaf.Event.tlGetPostURL = function() { 
        return TeaLeaf.Event.Configuration.tlurl; 
    }  
    /**
    * Set page id cookie value.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
    TeaLeaf.Event.tlSetPageIDCookie = function(tlvalue) { 
        TeaLeaf.Event.Configuration.tlpageidcookie = tlvalue; 
    }
    /**
    * Get page id cookie value.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
    TeaLeaf.Event.tlGetPageIDCookie = function(tlvalue) { 
        return TeaLeaf.Event.Configuration.tlpageidcookie; 
    }   
    /**
    * JSON configuration utility allowing to enable/disable certain DOM events
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
    TeaLeaf.Event.tlEventJSONCfgUtil = function(tlJSONConfig, tlEnable, domEventName) {         
        for(var i = 0; i<tlJSONConfig.length; i++){
            if(domEventName == "all"){
                tlJSONConfig[i].load = tlEnable;
            }
            else if (domEventName == tlJSONConfig[i].domevent){
                tlJSONConfig[i].load = tlEnable;
            }
        }  
    }  
    /**
    * Error handler.
    * @param message error 
    * @param url url
    * @param line line where error occured
    * @requires   
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
 TeaLeaf.Event.tlErrorHandler = function(message, url, line) { 
  var now = new Date();
  if( ! line ) {
   line = "unknown";
  }
  var tlevt = new TeaLeaf.Event("INFO", "EXCEPTION");
  var tlAddNameValueArray = ["Message", message, 
                          "URL", escape(url), 
                          "Line", line];
        tlevt.tlAddData(tlAddNameValueArray);
        TeaLeaf.Event.Configuration.tlasync = true;
  tlevt.tlSend();
  TeaLeaf.Event.tlFlushQueue();
  return false;
 } 
 /**
    * Handle the before unload event and flush the queue of events.
    *
    * @requires 
    * TeaLeafEventCfg.js
    * @addon
    */                                                                                
 TeaLeaf.Event.tlBeforeUnload = function(){
     if(TeaLeaf.Event.Configuration.tleventbeforeunloadflag == true){ 
            TeaLeaf.Event.Configuration.tleventunloadflag = false;   
      // Send in the notice
      var tlevt = new TeaLeaf.Event("PERFORMANCE", "BeforeUnload"); 
      TeaLeaf.Event.SetType = tlevt.EventType;
      if(TeaLeaf.Event.SetSubType == ""){
                TeaLeaf.Event.SetSubType = tlevt.EventSubType;
            }
            else{
                TeaLeaf.Event.SetSubType += "; " + tlevt.EventSubType;
            }                    
            TeaLeaf.Event.Configuration.tlbeforeunloadflag = true;
            TeaLeaf.Event.Configuration.tlignoresendfailure = true;
          TeaLeaf.Event.Configuration.tlasync = false;
       tlevt.tlSend();  
      TeaLeaf.Event.tlFlushQueue(true);
  } 
        TeaLeaf.Event.tlRemoveHandler(window, "beforeunload", eval(TeaLeaf.Event.tlBeforeUnload), false);
        TeaLeaf.Event.tlRemoveHandler(window, "unload", eval(TeaLeaf.Event.tlUnload), false);
 }
 /**
    * Handle the unload event and flush the queue of events.
    *
    * @requires 
    * TeaLeafEventCfg.js
    * @addon
    */                                                                                 
 TeaLeaf.Event.tlUnload = function(){
        if(TeaLeaf.Event.Configuration.tleventunloadflag ){         
            TeaLeaf.Event.Configuration.tllastdwelltime = new Date();
            TeaLeaf.Event.Configuration.tleventbeforeunloadflag = false;
      // Send in the notice
      var tlevt = new TeaLeaf.Event("PERFORMANCE", "Unload");
      TeaLeaf.Event.SetType = tlevt.EventType;
      
      if(TeaLeaf.Event.SetSubType == ""){
                TeaLeaf.Event.SetSubType = tlevt.EventSubType;
            }
            else{
                TeaLeaf.Event.SetSubType += "; " + tlevt.EventSubType;
            }
            TeaLeaf.Event.Configuration.tlignoresendfailure = true;
            TeaLeaf.Event.Configuration.tlasync = false;
      tlevt.tlSend();
      TeaLeaf.Event.tlFlushQueue(true);
        }  
        TeaLeaf.Event.tlRemoveHandler(window, "beforeunload", eval(TeaLeaf.Event.tlBeforeUnload), false);
        TeaLeaf.Event.tlRemoveHandler(window, "unload", eval(TeaLeaf.Event.tlUnload), false);
 }
 
    /**
    * Event setup.
    * @requires
    * TeaLeafEventCfg.js 
    * @addon
    */                                                    
 TeaLeaf.Event.EventSetup = function() {
        //Handle Errors
        if(TeaLeaf.Event.Configuration.tlcatcherrors){
            TeaLeaf.Event.tlAddHandler(window, "error", TeaLeaf.Event.tlErrorHandler, false);                
        }
        if(!TeaLeaf.Client){
            TeaLeaf.Event.tlAddHandler(window, "beforeunload", eval(TeaLeaf.Event.tlBeforeUnload), false);
            TeaLeaf.Event.tlAddHandler(window, "unload", eval(TeaLeaf.Event.tlUnload), false);
        }
  // If we are queueing events, set up the timer
  if( TeaLeaf.Event.Configuration.tlqueueevents ) {
   TeaLeaf.Event.tlTimerRoutine = function() {
    // Amount of time until the next timeout
    var timeAmount = TeaLeaf.Event.Configuration.tlqueueeventstimer;
    try {
     timeAmount = TeaLeaf.Event.tlFlushQueue();
    }
    catch(exc) {
     if( TeaLeaf.Event.Configuration.tlshowexceptions ) {
      alert(exc.name + ": " + exc.message + "\r\n\r\nPos 7");
     }
    }
    //NOTE:  Use setTimeout instead of setInterval since
    // setInterval is only JS 1.2 and later
    setTimeout('TeaLeaf.Event.tlTimerRoutine()', timeAmount);
   }
   setTimeout('TeaLeaf.Event.tlTimerRoutine()', TeaLeaf.Event.Configuration.tlqueueeventstimer);
  }
     TeaLeaf.Event.Loaded = true;
 }
 // Get the appropriate URL
 var tmpUrl;
 if( window.location.protocol == "http:" ) {
     tmpUrl = TeaLeaf.Event.Configuration.tlurl;
 }
 else {
     tmpUrl = TeaLeaf.Event.Configuration.tlsecureurl;
 }
 // Is this an absolute vs relative url
 if( tmpUrl.substr(0, 1) == "/" ) {
    TeaLeaf.Event.prototype.theUrl = window.location.protocol + "//" + window.location.host + tmpUrl;
 }
 else {
     TeaLeaf.Event.prototype.theUrl = window.location.href.substr(0, window.location.href.lastIndexOf("/")+1) + tmpUrl;
 }
 
 if(TeaLeaf.Event.Configuration.tlinit == false){
     TeaLeaf.Event.Configuration.tlinit = true;
        TeaLeaf.Event.prototype.XMLData = "";  
        TeaLeaf.addOnLoad(TeaLeaf.Event.EventSetup); 
    }
}