// Create empty components array to be populated later
var components = {};

if (!window.console) { // if no console, use tfconsole if available
	window.console = {};
	window.console["log"] = function(txt) {
		if (typeof(tf_debugconsole) != 'undefined') 
			tf_debugconsole.log(txt);
	}
} else { // output to both firebug console and tfconsole
	window.console["log"] = function(txt) {
		if (typeof(tf_debugconsole) != 'undefined') 
			tf_debugconsole.log(txt);
		console.debug(txt);
	}
}

var onloads = new Array();

function addOnLoad(expr) {
  onloads.push(expr);
}
var _timer;
function setupOnLoads() {
  /* for Safari */
  if (/WebKit/i.test(navigator.userAgent)) { // sniff
    _timer = setInterval(function() {
      if (/loaded|complete/.test(document.readyState)) {
        executeOnLoads(); // call the onload handler
      }
    }, 10);
    return;
  }

  /* for Mozilla/Opera9 */
  if (document.addEventListener) {
    document.addEventListener("DOMContentLoaded", executeOnLoads, false);
    return;
  }

  /* for Internet Explorer */
  /*@cc_on @*/
  /*@if (@_win32)
      document.write("<scr"+"ipt id=\"__ie_onload\" defer src=\"javascript:void(0)\"><\/scr"+"ipt>");
      var script = document.getElementById("__ie_onload");
      script.onreadystatechange = function() {
          if (this.readyState == "complete") {
              executeOnLoads(); // call the onload handler
          }
      };
      return;
  /*@end @*/

  window.onload = executeOnLoads;
}
function executeOnLoads() {
  // quit if this function has already been called
  if (arguments.callee.done) return;

  // flag this function so we don't do the same thing twice
  arguments.callee.done = true;

  // kill the timer
  if (_timer) clearInterval(_timer);

  var script = '';
  var expr;
  while (expr = onloads.shift()) {
    var type = typeof expr;
    if (type == 'function') {
      expr(); // FIXME - this causes all functionr eferences to be executed before all strings
    } else {
      script += expr + (expr.charAt(expr.length - 1) != ';' ? ';' : '');
    }
  }
  //alert(script);
  eval(script);
}


var objInfoBox;

function InfoBox(divname) {
  this.name = divname;
  this.boxDiv = document.getElementById(divname);
  this.contentDiv = document.getElementById(divname + "Content");
  this.gutterDiv = document.getElementById(divname + "Gutter");
  this.anchorElement = null;
  this.pos = [0, 0];
  this.side = 1;
  this.visible = false;
  this.width = '20em';

  this.parentElement = null;
  this.anchorElement = null;
  this.timer = null;
  this.sticky = false;

  // variable to keep track of the timestamp when the popup is displayed
  this.showPopupStartTime = null;
  this.params = null;

  this.Show = function (event, content, width, delay, parentElement, anchorClass, sticky, params) {
    if (this.visible && !sticky) return; // Only allow elements which are "sticky" to steal the infobox for its own use
    if (!this.boxDiv) return;

    // save the params passed
    this.params = params;
 
    if (!event) var event = window.event;
    var tg = (window.event) ? event.srcElement : event.target;
    var reltg = getRelatedTarget(event);
		
    // Only process this event if it was a transition, not for mouse events sent from within the element
		if (elementIsIn(tg, parentElement) && !elementIsIn(reltg, parentElement)) {

      this.sticky = sticky;
      this.tobeshown = true;
      objInfoBox.SetWidth(width);
      objInfoBox.AttachToElement(parentElement);
      objInfoBox.SetPositionAtElement(event, anchorClass);
      objInfoBox.SetContent(content);

      if (delay && !this.visible) {
        if (!this.timer)
          this.timer = setTimeout("objInfoBox.ShowReal()", delay);
      } else {
        this.ShowReal();
      }
    }
    setTimeout("fixPNG()", 10);
  }
  this.Hide = function(event, parentElement, force) {
    if (!this.boxDiv) return;
    if (force == true) {
      this.HideReal();
    } else {
      if (!event) var event = window.event;
      var tg = (window.event) ? event.srcElement : event.target;
      var reltg = (event.relatedTarget) ? event.relatedTarget : event.toElement;

      // If we were previously created with the sticky flag, then do nothing here
      if (this.sticky) return;

      // Only fire action on REAL mouseover/mouseout events
      if (elementIsIn(tg, parentElement) && !elementIsIn(reltg, parentElement)) {
        // set to 0 to turn off infobox hovering
        var betterfied = 1;
        if (betterfied && elementIsIn(tg, this.parentElement) && elementIsIn(reltg, this.boxDiv)) {
          // We're inside the infobox now - keep the element we're attached to highlighted
          if (this.parentElement)
            elementAddClass(this.parentElement, "sfHover")
        } else if (elementIsIn(tg, this.boxDiv) && elementIsIn(reltg, this.parentElement)) {
          // We've left the infobox - dehighlight it
          if (this.parentElement)
            elementRemoveClass(this.parentElement, "sfHover")
        } else {
          // Normal case - just hide it
          this.HideReal();
        }
      }
    }
  }
  this.ShowReal = function() {
    if (!this.tobeshown) return false;
    if (!this.boxDiv || !this.contentDiv) return false;

    //var windowSize = getWindowSize();

    // set the popup start time
    var now = new Date();
    this.showPopupStartTime = now.getTime();

    document.getElementById(this.name + "TailLeft").style.visibility = "hidden";
    document.getElementById(this.name + "TailRight").style.visibility = "hidden";
    var tail = document.getElementById(this.name + "Tail" + (this.side == 1 ? "Left" : "Right"));

    this.boxDiv.style.visibility = "visible";
    this.boxDiv.style.display = "block";

    var scroll = this.GetParentScroll();
    var maxSize = this.GetParentSize();

    var tailpos = [this.pos[0], this.pos[1] - tail.height];
    var boxpos = [this.pos[0] + tail.width, this.pos[1] - (this.boxDiv.offsetHeight * 0.25) - tail.height];

    this.boxDiv.style.width = this.width;

    // Recalculate the vertical position to make sure we fit within the window as much as possible
    if (boxpos[1] - scroll[1] < 0) {
      boxpos[1] = scroll[1];

      // Prevent tail from detaching
      if (boxpos[1] > this.pos[1] - (tail.height * 2)) {
        boxpos[1] = this.pos[1] - (tail.height * 2);
      }
    } else if (boxpos[1] + this.boxDiv.offsetHeight > maxSize[1] + scroll[1]) {
      boxpos[1] = (maxSize[1] + scroll[1]) - this.boxDiv.offsetHeight;

      // Prevent tail from detaching
      if (boxpos[1] < this.pos[1] - this.boxDiv.offsetHeight) {
        boxpos[1] = this.pos[1] + tail.height - this.boxDiv.offsetHeight;
      }
    }

    // Check horizontal positioning to make sure we never go off the right of the window
    if (boxpos[0] + this.boxDiv.offsetWidth + tail.width + 15 > maxSize[0]) {
      boxpos[0] -= this.boxDiv.offsetWidth + (tail.width * 2);
      if (this.anchorElement) {
        boxpos[0] -= this.anchorElement.offsetWidth;
      }
      tail = document.getElementById(this.name + "TailRight");
      tailpos[0] = boxpos[0] + this.boxDiv.offsetWidth;
      this.gutterDiv.style.left = "auto";
      this.gutterDiv.style.right = "-" + (tail.width + 10)+ "px";
    } else {
      this.gutterDiv.style.left = "-" + tail.width + "px";
      this.gutterDiv.style.right = "auto";
    }

    this.boxDiv.style.left = boxpos[0] + "px";
    this.boxDiv.style.top = boxpos[1] + "px";

    if (browserCheck.type == "msie" && browserCheck.version <= 6) {
      var classes = getElementsByClassName(this.boxDiv, 'div', 'shadowRight');
      if (classes) classes[0].style.height = this.contentDiv.offsetHeight  + 'px';
      this.gutterDiv.style.height = this.contentDiv.offsetHeight  + 'px';
    }

    //tail.style.left = tailpos[0] + "px";
    //tail.style.top = tailpos[1] + "px";
    tail.style.top = (this.pos[1] - boxpos[1] - tail.height - 13) + "px";

    this.boxDiv.style.display = "block";
    this.boxDiv.style.visibility = "visible";
    tail.style.visibility = "visible";

    this.visible = true;
  }

  this.HideReal = function () {
   if (this.timer) {
     clearTimeout(this.timer);
     this.timer = null;
   }
    
    this.boxDiv.style.visibility = "hidden";
    this.boxDiv.style.display = "none";
    document.getElementById(this.name + "TailLeft").style.visibility = "hidden";
    document.getElementById(this.name + "TailRight").style.visibility = "hidden";
    this.boxDiv.style.left = 0;
    this.boxDiv.style.top = 0;
  
    if (this.parentElement)
      elementRemoveClass(this.parentElement,"sfHover")
  
    this.parentElement = null;
    this.anchorElement = null;
    this.visible = false; 
  }

  this.SetWidth = function(width) {
    this.width = width;
  }
  /**
   * content can be either HTML or a DOM element
   */
  this.SetContent = function (content) {
    if (this.params && this.params.closebutton && tplmgr && tplmgr.HasTemplate("page.infobox.closebutton")) 
      content = tplmgr.GetTemplate("page.infobox.closebutton") + content;

    if (this.contentDiv) {
      if (typeof content == "string")
        this.contentDiv.innerHTML = content;
      else {
        this.contentDiv.innerHTML = ""; // wipe out existing content
        this.contentDiv.appendChild(content);
      }
    }
  }

  this.SetPosition = function (event) {
    if (!event) var event = window.event;
    if (event.pageX || event.pageY)   {
      this.pos[0] = event.pageX;
      this.pos[1] = event.pageY;
    } else if (event.clientX || event.clientY)  {
      this.pos[0] = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
      this.pos[1] = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
    }
    
    this.parentElement = null;
    this.anchorElement = null;

    var maxSize = this.GetParentSize();

    if (this.boxDiv.offsetParent) {
      this.pos[1] +=  this.boxDiv.offsetParent.scrollTop;
    }
    return this.pos;
  }

  this.SetPositionAtElement = function (event, anchorClassName) {
    var anchorFamily = this.parentElement.className;
    if (anchorClassName)
      anchorFamily += '>' + anchorClassName;
    var target = getEventTarget(event, anchorFamily);
    this.pos = findPos(target);

    // Position ourselves at the right side, vertical center of the element
    this.pos[0] += target.offsetWidth;
    this.pos[1] += target.offsetHeight / 2;

    this.anchorElement = target;
  }
  this.AttachToElement = function (element) {
    this.parentElement = element;
  }

  this.GetParentSize = function () {
    var maxSize = [];
    if (this.boxDiv.offsetParent) {
      maxSize[0] = this.boxDiv.offsetParent.offsetWidth;
      maxSize[1] = this.boxDiv.offsetParent.offsetHeight;
    } else {
      maxSize = getWindowSize();
    }
    return maxSize;
  }
  this.GetParentScroll = function () {
    var scroll = [];
    if (this.boxDiv.offsetParent) {
      scroll[0] = this.boxDiv.offsetParent.scrollLeft;
      scroll[1] = this.boxDiv.offsetParent.scrollTop;
    } else { //the larry
      scroll[0] = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
      scroll[1] = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
    }
    return scroll;
  }
}
function InfoBoxInit() {
  objInfoBox = new InfoBox("infoBox");
}
function BrowserCheck() {
  this.checkIt = function (string) {
    this.place = detect.indexOf(string) + 1;
    this.tmpstring = string;
    return this.place;
  }
  var detect = navigator.userAgent.toLowerCase();

  if (this.checkIt('konqueror')) {
    this.type = "Konqueror";
    this.OS = "Linux";
  } 
  else if (this.checkIt('safari')) this.type = "safari"
  else if (this.checkIt('omniweb')) this.type = "omniweb"
  else if (this.checkIt('opera')) this.type = "opera"
  else if (this.checkIt('webtv')) this.type = "webtv";
  else if (this.checkIt('icab')) this.type = "icab"
  else if (this.checkIt('msie')) this.type = "msie"
  else if (!this.checkIt('compatible')) {
    this.type = "netscape"
    this.version = detect.charAt(8);
  }
  else this.type = "unknown";

  if (!this.version) this.version = detect.charAt(this.place + this.tmpstring.length);

  if (!this.OS) {
    if (this.checkIt('linux')) this.OS = "linux";
    else if (this.checkIt('x11')) this.OS = "unix";
    else if (this.checkIt('mac')) this.OS = "mac"
    else if (this.checkIt('win')) this.OS = "windows"
    else this.OS = "unknown";
  }
}

var browserCheck = new BrowserCheck();

function getElementsByClassName(oElm, strTagName, strClassName){
    var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
    var arrReturnElements = new Array();
    strClassName = strClassName.replace(/\-/g, "\\-");
    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
    var oElement;
    for(var i=0; i<arrElements.length; i++){
        oElement = arrElements[i];      
        if(oRegExp.test(oElement.className)){
            arrReturnElements.push(oElement);
        }   
    }
    return (arrReturnElements)
}

function elementIsIn(target, parent) {
  while (target && target != parent) {
    target = target.parentNode;
  }
  return target == parent;
}

function elementHasClass(element, className) {
  if (element && element.className) {
    var re = new RegExp("(^| )" + className + "( |$)", "g");
    return (element.className.match(re) != null);
  }
  return false;
}
function elementAddClass(element, className) {
  element.className += " " + className;
}
function elementRemoveClass(element, className) {
  var re = new RegExp("(^| )" + className + "( |$)", "g");
  element.className = element.className.replace(re, " ");
}

/* Cross-platform event handlers */
function addEvent( obj, type, fn ) {
  if (obj) {
    if (obj.addEventListener) {
      if (typeof fn == "object" && fn.handleEvent) {
        obj[type+fn] = function(e) { fn.handleEvent(e); }
        obj.addEventListener( type, obj[type+fn], false );
      } else {
        obj.addEventListener( type, fn, false );
      }
    } else if (obj.attachEvent) {
      if (typeof fn == "object" && fn.handleEvent) { 
        obj[type+fn] = function() { fn.handleEvent(fixEvent(window.event)); }
      } else {
        obj["e"+type+fn] = fn;
        obj[type+fn] = function() { obj["e"+type+fn]( fixEvent(window.event) ); }
      }
      obj.attachEvent( "on"+type, obj[type+fn]);
    }
  }
  return this;
}

function removeEvent( obj, type, fn ) {
  if (obj.removeEventListener) {
    if (typeof fn == "object" && fn.handleEvent) {
      obj.removeEventListener( type, obj[type+fn], false );
      delete obj[type+fn];
    } else {
      obj.removeEventListener( type, fn, false );
    }
  } else if (obj.detachEvent) {
    obj.detachEvent( "on"+type, obj[type+fn] );
    obj[type+fn] = null;
    obj["e"+type+fn] = null;
  }
}
function fixEvent(event) {
  event.preventDefault = fixEvent.preventDefault;
  event.stopPropagation = fixEvent.stopPropagation;
  return event;
}
fixEvent.preventDefault = function() {
  this.returnValue = false;
}
fixEvent.stopPropagation = function() {
  this.cancelBubble = true;
}
function getTarget(event) {
  return (window.event) ? event.srcElement : event.target;
}
function getRelatedTarget(event) {
  var reltg;

  if (event.relatedTarget) {
    reltg = event.relatedTarget;
  } else {
    if (event.type == "mouseover")
      reltg = event.fromElement;
    else if (event.type == "mouseout")
      reltg = event.toElement;
    else
      reltg = document;
  }

  return reltg;
}
function eventIsTransition(event, parent) {
  var tg = getTarget(event); 
  var reltg = getRelatedTarget(event);

  return (elementIsIn(tg, parent) && !elementIsIn(reltg, parent));

}

suckerFishInit = function() {
  if (document.all && getElementsByClassName) {
    var classes;
    if (classes = getElementsByClassName(document, "*", "hoverHighlight")) {
      for (var i = 0; i < classes.length; i++) {
        classes[i].attachEvent('onmouseover', function() {
          target = getEventTarget(event, "hoverHighlight");
          elementAddClass(target, "sfHover");
        });
        classes[i].attachEvent('onmouseout', function() {
          target = getEventTarget(event, "hoverHighlight");
          elementRemoveClass(target, "sfHover");
        });
      }
    }
  }
}


function getWindowSize() {
  var windowSize = [0, 0];

  windowSize[0] = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  windowSize[1] = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
  return windowSize;
}
function findPos(obj) {
  var curleft = curtop = 0;
  if (obj.offsetParent) {
    curleft = obj.offsetLeft
    curtop = obj.offsetTop
    while (obj = obj.offsetParent) {
      curleft += obj.offsetLeft
      curtop += obj.offsetTop
    }
  }
  return [curleft,curtop];
}

function getEventTarget(event, parentClassName) {
  var target;
  if (!event) var event = window.event;
  if (event.target) target = event.target;
  else if (event.srcElement) target = event.srcElement;
  if (target.nodeType == 3) target = target.parentNode; // Defeat Safari bug
  if (parentClassName) {
    // Make sure we're working with the correct element

    var classUp;
    var classDown;

    if (parentClassName.indexOf(">")) {
      var classes = parentClassName.split(">", 2);
      classDown = classes[0];
      classUp = classes[1];
    } else {
      classDown = parentClassName;
    }

    // First run DOWN the heirarchy to find the base class...
    while (!elementHasClass(target,classDown) && target.parentNode) {
      target = target.parentNode;
    }

    // Now if we've specified a child to attach to, find it!
    if (classUp) {
      var elements;
      elements = getElementsByClassName(target, "*", classUp);
      if (elements.length > 0) {
        target = elements[0];
      }
    }
  }
  return target;
}

function showLightBox(width, height) {
  hideByClassName("hideOnLightBox");
  var lightboxShade = document.getElementById("tf_lightbox_shade");
  var lightbox = document.getElementById("tf_lightbox");
  var lightboxContainer = document.getElementById("tf_lightbox_container");
  var lightboxContent = document.getElementById("tf_lightbox_content");

  var windowSize = getWindowSize();
  lightboxShade.style.display = "block";
  lightboxContainer.style.display = "block";
  //lightboxShade.style.height = '10000px'; /* IE doesn't like height: 100% */ /* seems to not mind now */
  lightboxShade.style.width = "100%";
  if (width) {
    lightbox.style.width = width;
  } else {
    lightbox.style.width = '40em';
  }
  if (height) {
    lightboxContent.style.height = height;
  }
  lightbox.style.display = "block";
  setTimeout("fixPNG()", 10);

}
function hideLightBox() {
  hideByClassName("hideOnLightBox", 1);
  var lightboxShade = document.getElementById("tf_lightbox_shade");
  var lightboxContainer = document.getElementById("tf_lightbox_container");
  var lightbox = document.getElementById("tf_lightbox");

  lightboxShade.style.display = "none";
  lightboxContainer.style.display = "none";
  lightbox.style.display = "none";
}

function hideByClassName(hideClass, show) {
  if (!show) {
    var toHide = getElementsByClassName(document, "*", hideClass);
    for (var i = 0; i < toHide.length; i++) {
      toHide[i].style.visibility = "hidden";
    }
  } else {
    var toHide = getElementsByClassName(document, "*", hideClass);
    for (var i = 0; i < toHide.length; i++) {
      toHide[i].style.visibility = "visible";
    }
  
  }
}
function focus(id) {
  var target = document.getElementById(id); 
  if(target)
     target.focus();
}
function focusError(classname) {
  if(classname)
    var target = getElementsByClassName(document, "*", classname);
  if(target[0])
     target[0].focus();

}
function resetFormBorders(form) {
  if (!form)
    form = document;
  var formelements = getElementsByClassName(form, "*", "formInput");

  if (formelements) {
    for (var i = 0; i < formelements.length; i++) {
      elementRemoveClass(formelements[i], 'formInputError');
    }
  }
}

function fixPNG() {
  if (browserCheck.type == "msie" && browserCheck.version <= 6) {
    document.execCommand("BackgroundImageCache",false,true);
    var imglist = document.getElementsByTagName("img");

    for (var i = 0; i < imglist.length; i++) {
      if(imglist[i].src.substr(imglist[i].src.length - 3, 3) == "png" && !imglist[i].style.filter) {
        var origsrc = imglist[i].src;
        imglist[i].src = '/images/misc/nothing.gif';
        imglist[i].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + origsrc + "', sizingMethod='image')";
      }
    }
  }
}

function resizeAdIframe(framename) {
  var frame = document.getElementById(framename);
  if (frame) {
    var doc = frame.contentDocument || frame.Document;
    var height = doc.body.scrollHeight;
    frame.style.height = height + "px";
  }
}

function DOMgetText(el) {
  if (el.nodeType == 3) return el.nodeValue;
  var txt = new Array(),i=0;
  while(el.childNodes[i]) {
    txt[txt.length] = DOMgetText(el.childNodes[i]);
     i++;
  }
  // return the array as a string
  return txt.join("");
}
function getChildContentByClassName(parent, className, attrname) {
  if (parent && className) {
    var ret = null;
    tmp = getElementsByClassName(parent, "*", className);
    if (tmp.length == 1 && tmp[0]) { 
      if (attrname)
        ret = tmp[0].getAttribute(attrname);
      else {
        var content = DOMgetText(tmp[0]);
        if (content.length > 0) {
          ret = content;
        }
      }
    }
  }
  return ret;
}

/**
 * This function will checkall / uncheckall
 * the checkboxes in a form.
 * state: true (check), false (uncheck)
 * 
 */
function checkall(link, state) {
  while(link.tagName != 'FORM') {
    link = link.parentNode;
  }
  var form = link;
  var inputs = form.getElementsByTagName('input');
  var checkboxes = new Array();
  for (i = 0; i < inputs.length; i++) {
    var input = inputs[i];
    if (input.type == 'checkbox')
      input.checked = state;
  }
}

function numberFormat(nStr,prefix){
    var prefix = prefix || '';
    nStr += '';
    x = nStr.split('.');
    x1 = x[0];
    x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1))
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    return prefix + x1 + x2;
}

function getTokenArray(string,delimeter) {
  array = string.split(delimeter);
  return (array)?array:false;
}
function roundTo(n,p) { x = Math.pow(10,p); n = Math.round(n / x) * x; return n; }
function addCommas(nStr) {
  nStr += '';
  x = nStr.split('.');
  x1 = x[0];
  x2 = (x.length > 1)?'.'+x[1]:'';
  var rgx = /(\d+)(\d{3})/;
  while (rgx.test(x1)) {
    x1 = x1.replace(rgx, '$1' + ',' + '$2');
  }
  return x1 + x2;
}
function setOpacity(obj,value) {
  obj.style.opacity=value/10;
  obj.style.filter='alpha(opacity='+value*10+')';
}
function FindXY(obj) {
  var x=0,y=0;
  while(obj) {
    x += obj.offsetLeft - obj.scrollLeft;
    y += obj.offsetTop - obj.scrollTop;
    obj = obj.offsetParent;
  }
  return {'x' : x, 'y' : y};
}
function FindXYWH(obj) {
	var ret = FindXY(obj);
	ret.w = obj.offsetWidth;
	ret.h = obj.offsetHeight;
  return ret;
}
function getInnerContent(obj, html){
  if(html) {
    return obj.innerHTML;
  } else {
    if (obj.innerText) {
        return obj.innerText;
    } else if (obj.textContent) {
        return obj.textContent;
    }
  }
}

function is_url(url) {
  return (/^(https?):\/\/([\w\.]+@)?([\w\-]+\.)+([\w\-\.]+)\w+(:\d+)?(\/[^\s<>\]:{\[}\^|\\`]*)?$/i).test(url);
}
function array_sum(arr) {
  for(var i=0,sum=0;i<arr.length;sum+=arr[i++]);
  return sum;
}
function isValidZipCode(value) {
   var re = /^\d{5}([\-]\d{4})?$/;
   return (re.test(value));
}

function setCookie(name,value,expires,domain,secure,path) {
    expires = (expires)?expires:'';
    domain = (domain)?domain:'';
    secure = (secure)?secure:'';
    path = (path)?path:'/';
    var curCookie = name + "=" + escape(value) +
        ((expires) ? "; expires=" + expires.toGMTString() : "") +
        ((path) ? "; path=" + path : "") +
        ((domain) ? "; domain=" + domain : "") +
        ((secure) ? "; secure" : "");
    document.cookie = curCookie;
    return curCookie;
}

function listCookies() {
    var theCookies = document.cookie.split(';');
    var aString = '';
    for (var i = 1 ; i <= theCookies.length; i++) {
        aString += i + ' ' + theCookies[i-1] + "\n";
    }
    return aString;
}
function getCookie(name) {
    var theCookies = document.cookie.split(/[; ]+/);
    for (var i = 0 ; i < theCookies.length; i++) {
        var aName = theCookies[i].substring(0,theCookies[i].indexOf('='));
        if (aName == name) {
            return theCookies[i];
        }
    }
}
function deleteCookie(name) {
    var aCookie = getCookie(name);
    if (aCookie) {
        document.cookie = aCookie + '; expires=Thu, 01-Jan-70 00:00:01 GMT';
        return name;
    }
}
function initDebugTools() {
	var url = location.href.split('?')[0];
	var page = url.split('/')[3];
  if (page != "admin.fhtml") {
		var debugToolsTimer = setTimeout(function() {
			tf_debugconsole = new tfDebugConsole("tf_debug");
			tf_debugconsolewindow.displayWindow();
			tf_toolbar = new tfToolbar("tf_debug");
			tf_state = new tfState();
			tf_state.restoreState();
			tf_debugconsole.scrollToBottom('logger');
			tf_debugconsolewindow.resize();
		},500);
	}
}

var tfWindowZIndex = new function() {
	this.zIndex = 1000;
	this.inc = function() {
		return ++this.zIndex;
	}
}
function tfState() {
  this.browser = browserCheck.type;
	this.debug = false;
	
  this.restoreState = function() {
    this.getState();
    if (this.debugSettings) {
      if ((this.debugSettings.x) || (this.debugSettings.x == 0)) tf_debugconsolewindow.setX(this.debugSettings.x);
      if ((this.debugSettings.y) || (this.debugSettings.y == 0)) tf_debugconsolewindow.setY(this.debugSettings.y);
      if (this.debugSettings.w) tf_debugconsolewindow.setW(this.debugSettings.w);
      if (this.debugSettings.h) tf_debugconsolewindow.setH(this.debugSettings.h);
      if (this.debugSettings.shaded) { 
   			tf_debugconsolewindow.setBorderCursor(false);
        tf_debugconsolewindow.shaded = this.debugSettings.shaded; 
      }
      if (this.debugSettings.visible) tf_toolbar.toggleDebugConsole();
      //if (this.browser != "msie") if (this.debugSettings.window) var debugconsolewindow = new tfWindow('tf_debug',true);
      if (this.debugSettings.docked) {
        tf_debugconsolewindow.dockConsole();
      }
      if (this.debugSettings.tab) { tf_debugconsole.setTab(this.debugSettings.tab); }
    }
    if (this.toolbarSettings) {
      if (this.toolbarSettings.shaded && !this.debugSettings.visible) { tf_toolbar.shadeToolbar(); }
      if (this.toolbarSettings.alignment=='l') { tf_toolbar.toggleAlignment(); }
      if (this.toolbarSettings.w) { tf_toolbar.setW(this.toolbarSettings.w); }
      if (this.toolbarSettings.h) { tf_toolbar.setH(this.toolbarSettings.h); }
    }
    document.getElementById('tf_toolbarContainer_r').style.display = "block";
  }
  this.getState = function() {
    var rawdata = getCookie('tf-dev');
    if (rawdata) {
      var decoded = unescape(rawdata.split('=')[1]);
      this.cookieObj = decoded.parseJSON();
    } else {
      this.cookieObj = new Object();
    }
    this.serveroverrides = this.cookieObj.serveroverrides;
    this.debugSettings = this.cookieObj.debugconsole;
    this.toolbarSettings = this.cookieObj.toolbar;
		if (this.debug) console.log(decoded);
  }
  this.saveState = function() {
    var toolbarSettings = new Object();
    toolbarSettings.shaded = tf_toolbar.shaded;
    toolbarSettings.alignment = tf_toolbar.alignment;
    toolbarSettings.w = tf_toolbar.w;
    toolbarSettings.h = tf_toolbar.h;
    this.cookieObj.toolbar = toolbarSettings;
    var debugSettings = new Object();
    debugSettings.window = tf_debugconsolewindow.window;
    debugSettings.visible = tf_debugconsolewindow.visible;
    debugSettings.docked = tf_debugconsolewindow.docked;
    debugSettings.shaded = tf_debugconsolewindow.shaded;
    debugSettings.tab = tf_debugconsole.tab;
    debugSettings.x = tf_debugconsolewindow.x;
    debugSettings.y = tf_debugconsolewindow.y;
    debugSettings.w = tf_debugconsolewindow.w;
    debugSettings.h = tf_debugconsolewindow.h;
    this.cookieObj.debugconsole = debugSettings;
    var cookieJSON = this.cookieObj.toJSONString();
    var cookie = setCookie("tf-dev",cookieJSON);
  }
}
function tfTreeView(container) {
  this.ie = (browserCheck.type == "msie");
  this.container = document.getElementById(container);
  this.treeroot = (this.container.nodeName == 'UL')?this.container:this.container.getElementsByTagName('ul')[0];
  if (!this.treeroot) return false;
	this.treeroot.style.borderWidth = "0px";
	this.treeroot.style.background = "#fff";
	this.browserOffset = (this.ie)?13:10;
	this.tvOffset = (FindXY(this.treeroot).x + this.treeroot.offsetWidth) - this.browserOffset;

  this.create = function() {
    this.branchArray = [];
    this.liArray = this.treeroot.getElementsByTagName('li');
    var bindex = 0;
    for(i=0;li = this.liArray[i];i++) {
      li.shaded = false;
      n = (this.ie)?1:0;
      if (this.ie) {
        li.childNodes[1-n].style.paddingLeft = ".6em"; 
			}
      if (li.childNodes[3-n].nodeName != "INPUT") {
        checkbox = this.createCheckbox(li,bindex);
        addEvent(checkbox,"click",this);
        addEvent(li.childNodes[2-n],"click",this);
        checkbox.style.cursor = "pointer";
				if (this.ie) { 
					li.childNodes[4-n].style.borderTop = "1px solid #bbb";
					li.childNodes[4-n].style.borderLeft = "1px solid #bbb";
				}
        li.childNodes[2-n].style.cursor = "pointer";
        this.branchArray.push(li);
				//this.liX = FindXY(li).x;
				//console.log(this.liX);
        bindex++;
      } else { 
        elementAddClass(li.childNodes[1-n],"tf_treeview_property");
        li.style.paddingLeft = "0px"; 
        li.style.background = "#eee";
      }
    }
  }
  this.createCheckbox = function(div,index) {
    cb = document.createElement('div');
    cb.id = index;
    cb.className = "treeCheckBox";
    checkboxPlusV = document.createElement('div');
    checkboxPlusV.className = "treeCheckBoxPlusV";
    checkboxPlusH = document.createElement('div');
    checkboxPlusH.className = "treeCheckBoxPlusH";
    cb.appendChild(checkboxPlusV);
    cb.appendChild(checkboxPlusH);
    div.appendChild(cb);
    div.insertBefore(cb,div.firstChild);
    return cb;
  }
  this.toggleBranchState = function(index,checkbox) {
    li = this.branchArray[index];
    if (li.shaded) { display = "block"; li.shaded = false; } 
    else { display = "none"; li.shaded = true; }
    if (li.childNodes) {
      for (i=3;child = li.childNodes[i];i++) {
        if (child.nodeName != "#text") {
          child.style.display = display;
        }
      }
    }
    if (checkbox) {
      if (li.shaded) {
				checkbox.firstChild.style.display = "block";
				checkbox.childNodes[1].style.marginTop = "-5px";
			} else {
	      n = (this.ie)?1:0;
				checkbox.firstChild.style.display = "none";
				checkbox.childNodes[1].style.marginTop = 4+n+"px";
			}
    }
  }
  this.handleEvent = function(event) {
    if (!event) event = window.event;
    var target = (event.srcElement || event.target);
    event.preventDefault();
    event.stopPropagation();
    if (target.nodeName == "LABEL") target = target.parentNode.firstChild;
    if (target.className == "treeCheckBoxPlusH") target = target.parentNode;
    if (target.className == "treeCheckBoxPlusV") target = target.parentNode;
    if (!target.id) target = target.offsetParent;
    if (event.type == "click") {
      this.toggleBranchState(target.id,target);
    }
  }
  this.setAllStates = function(state) {
    for (var i in this.branchArray) {
      if (this.branchArray[i].shaded == state) 
        this.toggleBranchState(i,this.branchArray[i].firstChild);
    }
  }
  this.create();
	this.setAllStates(false);
}
function tfToolbar(component1,component2,component3,component4) {
  this.container = document.getElementById('tf_toolbarContainer_r');
  this.debugComponentConsole = document.getElementById("tf_debug_tabs");
  this.browser = browserCheck.type;
  this.ie = (this.browser == "msie")?true:false;
  this.shaded = false;
  this.componentArray = [];
  this.tasksArray = [];
  this.alignment = "r";
  
	this.create = function() {
    if (this.ie && browserCheck.version == '6') { this.container.style.position = "absolute"; }
    this.toolbar = document.createElement('div');
    this.toolbar.id = "tf_toolbar";
    this.container.appendChild(this.toolbar);
    this.shadebtn = document.createElement('div');
    this.shadebtn.id = "tf_toolbar_shadebtn";
    this.shadebtn.title = "Shade / Resize";
    this.ccc = document.createElement('div');
    this.ccc.id = "tf_toolbar_component_container";
    this.taskbar = document.createElement('div');
    this.taskbar.id = "tf_toolbar_taskbar";
    this.toolbar.appendChild(this.shadebtn);
    this.toolbar.appendChild(this.ccc);
  }
  
	this.settingsComponent = function() {
    this.settingsComponentObj = this.addComponent("settings");
    this.settingsComponentButton1Obj = document.createElement('div');
    this.settingsComponentButton1Obj.id = "tf_toolbar_component_settings_button1";
    this.settingsComponentButton1Obj.innerHTML = "Alignment";
    this.settingsComponentObj.appendChild(this.settingsComponentButton1Obj);
    addEvent(this.settingsComponentButton1Obj, "mousedown", this);
    addEvent(this.settingsComponentButton1Obj, "mouseup", this);
    if (!this.settingsTask) this.settingsTask = this.addTask("Settings");
  }
  
	this.debugComponent = function(component) {
    this.hideComponents();
    this.debugComponentBool = true;
    this.debugComponentObj = this.addComponent("debug");
    this.debugComponentObj.appendChild(this.debugComponentConsole);
    this.debugComponentControlsObj = this.addComponent("debug_controls");
		this.addButton('Console','Launch Console Window',function() { 
			tf_toolbar.toggleDebugConsole();
			tf_debugconsole.scrollToBottom();
		});
		this.addButton('Reset','Reset Console Window',function() { 
			tf_debugconsolewindow.reset(); 
			tf_toolbar.reset(); 
		});
    if (!this.debugTask) this.debugTask = this.addTask("Debug");
    this.debugComponentConsole.style.overflow = "hidden";
    this.debugComponentConsole.style.overflowY = "scroll";
  }
	
	this.addButton = function(name,title,func) {
	  var newButton = document.createElement('div');
    newButton.className = "tf_toolbar_component_debug_controls_button1";
		newButton.innerHTML = name;
	  newButton.title = title;
    addEvent(newButton, "click", func);
	  this.debugComponentControlsObj.appendChild(newButton);
	}

	this.addComponent = function(name,component) {
    this.componentContainer = document.createElement('div');
    this.componentContainer.id = "tf_toolbar_component_" + name;
    this.ccc.appendChild(this.componentContainer);
    this.componentArray.push(this.componentContainer);
    return this.componentContainer;
  }
	
	this.remComponent = function(component) { this.ccc.removeChild(component); }

	this.addTask = function(name,func) { 
    this.task = document.createElement('div');
    this.task.id = name + "_task";
    this.task.className = "tf_toolbar_taskbar_task";
    this.task.innerHTML = name;
    addEvent(this.task,"click",this);
    this.taskbar.appendChild(this.task);
    this.tasksArray.push(this.task);
    return this.task;
  }
  
	this.remTask = function(task) { this.taskbar.removeChild(task); }
  
	this.setEvents = function() {
    addEvent(this.shadebtn, "mousedown", this);
    addEvent(this.shadebtn, "mouseup", this);
  }
	
  this.handleEvent = function(event) {
    if (!event) event = window.event;
    var target = (event.srcElement || event.target);
		var mouse = this.getMouseXY(event);
		
		switch (event.type) {
			case "click":
				switch (target.id) {
					case "Settings_task": this.showSettingsComponent(); break;
					case "Debug_task": this.showDebugComponent(); break;
				}
				tf_state.saveState();
				break;
    	case "mousedown":
				if (target == this.shadebtn) {
					if (this.ie && browserCheck.version == '6') return;
					this.shadebtn.style.borderStyle = "inset";
					this.offset = mouse;
					this.tboffset = this.ccc.offsetHeight;
					this.desktopWidth = document.documentElement.clientWidth - 3;
					this.clearEvents();
					this.eventMouseMove = addEvent(document,"mousemove",this);
					this.eventMouseUp = addEvent(document,"mouseup",this);
				}
				break;
			case "mousemove":
				event.preventDefault();
				event.stopPropagation();
				if (this.ie && browserCheck.version == '6') return;
				var diffX = this.offset.x - mouse.x;
				var diffY = this.offset.y - mouse.y;
				this.w = this.debugComponentObj.offsetWidth + diffX;
				this.h = this.tboffset - diffY;
				if ((this.toolbar.offsetWidth + diffX) < this.desktopWidth) this.setW();
				this.setH();
				this.offset.x = mouse.x - 2;
				this.dragging = true;
				break;
			case "mouseup":
				if ((target == this.shadebtn) && (!this.dragging)) this.shadeToolbar(); 
				this.dragging = false;
				if (this.ie && browserCheck.version == '6') return;
				this.shadebtn.style.borderStyle = "outset";
				this.clearEvents();
				tf_state.saveState();
				break;
		}
	}

	this.clearEvents = function() {
		if ((this.eventMouseMove) || (this.eventMouseUp)) {
			if (this.eventMouseMove) { removeEvent(document,"mousemove",this); delete this.eventMouseMove; }
			if (this.eventMouseUp) { removeEvent(document,"mouseup",this); delete this.eventMouseUp; }
		}
	}

  this.setW = function(w) {
    this.w=(w)?w:this.w;
		this.debugComponentObj.style.width = this.w + "px";
		tf_debugconsole.scrollToBottom();
  }

  this.setH = function(h) {
    this.h=(h)?h:this.h;
		this.shadebtn.style.height = this.h + "px";
		this.ccc.style.height = this.h + "px";
		tf_debugconsole.scrollToBottom();
  }

	this.reset = function() {
		this.alignment == 'l';
		//this.toggleAlignment();
		this.setH(42);
		this.setW(390);
	}

	this.getMouseXY = function(event) {
		var x = event.pageX || (event.clientX + document.body.scrollLeft);
		var y = event.pageY || (event.clientY + document.body.scrollTop);
		return {'x' : x, 'y' : y};
	}

  this.toggleAlignment = function(val) {
    if (val) this.alignment = val;
		else this.alignment = (this.alignment == 'l')?'r':'l';
    this.container.id = "tf_toolbarContainer_" + this.alignment;
  }

  this.hideComponents = function() {
    for (i=0;this.componentArray[i];i++) this.componentArray[i].style.display = "none";
  }

  this.showComponent = function(c) { c.style.display = "block"; }

  this.showSettingsComponent = function() {
    this.hideComponents();
    this.showComponent(this.settingsComponentObj);
  }

  this.showDebugComponent = function() {
    this.hideComponents();
    this.showComponent(this.debugComponentObj);
    this.showComponent(this.debugComponentControlsObj);
  }

  this.toggleDebugConsole = function() {
    if (this.debugComponentBool) {
      tf_debugconsole.toggleConsole(true);
			if (!this.shaded) this.shadeToolbar();
      this.debugComponentBool = false;
      this.debugComponentObj.style.background = "#c0c0c0";
      this.debugComponentConsole.style.overflow = "auto";
    } else {
			if (this.shaded) this.shadeToolbar();
	    this.debugComponentObj.appendChild(this.debugComponentConsole);
      this.debugComponentObj.style.background = "#fff";
      this.debugComponentBool = true;
			this.debugComponentConsole.style.overflow = "hidden";
			this.debugComponentConsole.style.overflowY = "scroll";
      tf_debugconsole.toggleConsole();
			tf_debugconsole.setTab('logger');
      this.showDebugComponent();
    }
  }

  this.shadeToolbar = function() {
    if (this.shaded) {
      this.shaded = false;
      this.showDebugComponent();
      this.ccc.style.display = "block";
      this.taskbar.style.display = "block";
			blarg = (this.ie)?'352px':'';
      this.toolbar.style.width = blarg;
    } else {
      this.shaded = true;
      this.hideComponents();
      this.ccc.style.display = "none";
      this.taskbar.style.display = "none";
			this.oldwidth = this.toolbar.offsetWidth;
      this.toolbar.style.width = "12px";
    }
		tf_state.saveState(); 
  }
  this.create();
  this.setEvents();
  //this.settingsComponent();
  if (this.debugComponentConsole) this.debugComponent(this.debugComponentConsole);
	this.reset();
}

function tfDebugConsole(divname) {
  this.logger = document.getElementById("tf_debug_tab_logger");
  this.tabs = document.getElementById("tf_debug_tabs");
  this.menu = document.getElementById("tf_debug_menu");
  this.ie = (browserCheck.type == "msie")?true:false;
  this.visible = false;
  this.tab = "logger";
  this.line = 1;
	
	this.create = function() {
		tf_debugconsolewindow = new tfWindow('tf_debug_tabs',true);
		tf_debugconsolewindow.appendMenu(this.menu);
		tf_debugconsolewindow.appendBody(this.tabs);
		this.tabs.style.height = "100%";
    this.jsdb = document.createElement('ul');
		this.jsdb.id = "tf_debug_log_jsdebug";
		this.logger.appendChild(this.jsdb);
		this.log("console.log() will write to this window.");
	}

  this.toggleConsole = function(bool) {
    if (tf_debugconsolewindow.visible) {
      tf_debugconsolewindow.hideSelf();
    } else {
			if (bool) tf_debugconsolewindow.content.appendChild(this.tabs);
      tf_debugconsolewindow.showSelf();
		}
	}

  this.log = function(linetxt) {
    var debugLI = document.createElement('li');
		debugLI.className = "logInfo";
		var debugAddress = document.createElement('address');
		debugAddress.innerHTML = "JS Log: "+this.line;
		var debugCode = document.createElement('code');
		debugCode.innerHTML = linetxt;
		debugLI.appendChild(debugCode);
		debugLI.insertBefore(debugAddress,debugCode);
		this.jsdb.appendChild(debugLI);
		this.scrollToBottom();
    this.line++;
  }

  this.setTab = function(name,bool) {
    if (!this.lis) this.lis = this.tabs.getElementsByTagName("LI");
    if (!this.menu_lis) this.menu_lis = this.menu.getElementsByTagName("LI");
    var index = 0;
    for (var i = 0; i < this.lis.length; i++) {
      if (this.lis[i].parentNode == this.tabs) {
        if (this.lis[i].id == "tf_debug_tab_" +name) {
          this.lis[i].style.display = "block";
          this.menu_lis[index].className = "tf_debug_link_selected";
        } else {
          this.lis[i].style.display = "none";
          this.menu_lis[index].className = "tf_debug_link_unselected";
        }
        index++;
      }
    }
    this.tab = name;
		if (name == 'logger') this.scrollToBottom();
		else this.tabs.scrollTop = 0;
    if (bool) tf_state.saveState();
    return false;
  }

	this.scrollToBottom = function() { this.tabs.scrollTop = this.tabs.scrollHeight; }

  this.setTab(this.tab);
  this.create();
}

function tfWindow(body,dockable,noresize) {
	this.ie = (browserCheck.type == "msie");
	this.bodyName = body;
	this.x = 50;
	this.y = 50;
	this.w = 500;
	this.h = 250;
  this.visible = false;
	this.docked = false;
	this.shaded = false;
	this.shadeable = false;
	this.dockable = false;
	this.noresize = noresize;
	this.offset = 8;

	this.create = function() {
		this.container = this.createWindowElement('tf_window');
		this.toplayer = this.createWindowElement('tf_window_top',this.container);
		this.tl = this.createWindowElement('tf_window_tl',this.toplayer);
		this.tr = this.createWindowElement('tf_window_tr',this.toplayer);
		this.tm = this.createWindowElement('tf_window_tm',this.toplayer);
		this.midlayer = this.createWindowElement('tf_window_mid',this.container);
		this.ml = this.createWindowElement('tf_window_ml',this.midlayer);
		this.mr = this.createWindowElement('tf_window_mr',this.midlayer);
		this.mm = this.createWindowElement('tf_window_mm',this.midlayer);
		this.title = this.createWindowElement('tf_window_title',this.mm);
		this.close = this.createWindowElement('tf_window_close',this.title);
		this.content = this.createWindowElement('tf_window_content',this.mm);
		this.botlayer = this.createWindowElement('tf_window_bot',this.container);
		this.bl = this.createWindowElement('tf_window_bl',this.botlayer);
		this.br = this.createWindowElement('tf_window_br',this.botlayer);
		this.bm = this.createWindowElement('tf_window_bm',this.botlayer);
		if (this.ie) {
			this.close.innerHTML = "Close";
			//if (browserCheck.version == '6') 
			this.container.style.position = "absolute";
		}
	}
	this.createWindowElement = function(id,parent) {
		var element = document.createElement('div');
		element.id = id;
		if (parent) parent.appendChild(element);
		return element;
	}
	this.updateZIndex = function() {
		this.container.style.zIndex = tfWindowZIndex.inc();
	}
	this.appendMenu = function(obj,txt) {
		if (obj) this.title.appendChild(obj);
		if (txt) {
			this.titlelabel = document.createElement('div');
			this.titlelabel.id = "tf_window_titlelabel";
			this.title.appendChild(this.titlelabel);
			this.titlelabel.innerHTML = txt;
		}
	}
	this.appendBody = function(obj) {
		this.body = obj;
	}
	this.displayWindow = function() {
		if (!this.display) {
			this.display = true;
			document.body.appendChild(this.container);
			this.content.appendChild(this.body);
			this.updateZIndex();
		}
	}
	this.setEvents = function() {
		addEvent(this.close,"click",this);
		addEvent(this.title,"click",this);
		addEvent(this.title,"mousedown",this);
		if (!this.noresize) {
			addEvent(this.tm,"mousedown",this);
			addEvent(this.tl,"mousedown",this);
			addEvent(this.tr,"mousedown",this);
			addEvent(this.ml,"mousedown",this);
			addEvent(this.mr,"mousedown",this);
			addEvent(this.bm,"mousedown",this);
			addEvent(this.bl,"mousedown",this);
			addEvent(this.br,"mousedown",this);
			this.setBorderCursor(true);
		}
	}
	this.handleEvent = function(event) {
		if (!event) event = window.event;
		var target = (event.srcElement || event.target);
		event.preventDefault();
		event.stopPropagation();
		
		switch (event.type) {
			case "click": 
				this.updateZIndex();
				if (target == this.close) {
					if (this.bodyName == "tf_debug_tabs") { tf_toolbar.toggleDebugConsole(); }
					else { this.container.style.display = "none"; }
					this.visible = false; 
					this.saveState();
					return;
				} else {
					if (this.dblClick) this.shade();
					var tObj = this;
					this.dblClick = true;
					setTimeout(function() { tObj.dblClick = false; },(this.ie)?500:250);
					this.saveState();
				}
				break;
			case "mousedown": 
				var cPos = FindXY(this.container);
				if ((this.eventMouseMove) || (this.eventMouseUp)) this.clearEvents();
				if (browserCheck.type == 'netscape' || browserCheck.type == 'opera') this.scrollTop = document.documentElement.scrollTop;
				else if (browserCheck.type == 'safari') this.scrollTop -= document.body.scrollTop;
				else this.scrollTop = 0;
				var mouse = this.getMouseXY(event);
				this.updateZIndex();
				this.offsetX = mouse.x;
				this.offsetY = mouse.y;
				this.startX = mouse.x - cPos.x;
				this.startY = mouse.y - cPos.y;
				this.desktopHeight = document.documentElement.clientHeight;
				this.desktopWidth = document.documentElement.clientWidth;
				this.target = target;
				this.eventMouseMove = addEvent(document,"mousemove",this);
				this.eventMouseUp = addEvent(document,"mouseup",this);
				break;
			case "mousemove": 
				var mouse = this.getMouseXY(event);
				if ((this.target == this.title) || (this.target.parentNode == this.title)) this.move(mouse); 
				else 	this.resize(this.target,mouse);
				break;
			case "mouseup": 
				this.clearEvents();
				this.saveState();
				break;
		}
	}
	this.clearEvents = function() {
		if ((this.eventMouseMove) || (this.eventMouseUp)) {
			if (this.eventMouseMove) { removeEvent(document,"mousemove",this); delete this.eventMouseMove; }
			if (this.eventMouseUp) { removeEvent(document,"mouseup",this); delete this.eventMouseUp; }
		}
	}
	this.shade = function() {
		if (this.shaded) {
			this.setH(this.shaded);
			this.setBorderCursor(true);
			//this.content.style.display = 'block';
			this.shaded = false;
		} else {
			this.shaded = this.container.offsetHeight;
			this.setBorderCursor(false);
			//this.content.style.display = 'none';
			this.setH((this.tm.offsetHeight * 2) + this.title.offsetHeight);
		}
	}
	this.move = function(mouse) {
		//if (this.docked) { this.startX = this.unDockOffset(mouse.x); }
		this.x = mouse.x - this.startX;
		this.y = mouse.y - this.startY;
		/*
		if (this.dockable && !this.ie) {
			if ((mouse.y >= (this.desktopHeight - (this.h / 2))) && (!this.shaded)) {
				if (!this.docked) this.dockConsole();
				return false;
			} else {
				if (this.docked) this.docked = false;
				if (this.container.offsetWidth != this.w)	this.container.style.width = this.w + "px"; 
			}
		}
		*/
		this.setY();
		this.setX();
	}
	this.resize = function(c,mouse) {
		if (this.shaded) return;
		var yo = xo = wo = ho = 0;
		
		if (c) {
			xo = this.x;	
			yo = this.y;	
			ho = this.h;	
			wo = this.w;
			switch (c) {
				case this.tm:
					this.h = (this.h - (mouse.y - (this.y + this.offset)));
					this.y = mouse.y - this.offset;
					break;
				case this.tl:
					this.w = this.w - (mouse.x - (this.x + this.offset));
					this.x = mouse.x - this.offset;
					this.h = this.h - (mouse.y - (this.y + this.offset));
					this.y = mouse.y - this.offset;
					break;
				case this.tr:
					this.w = (mouse.x - this.x) + this.offset;
					this.h = this.h - (mouse.y - (this.y + this.offset));
					this.y = mouse.y - this.offset;
					break;
				case this.ml:
					this.w = this.w - (mouse.x - (this.x + this.offset));
					this.x = mouse.x - this.offset;
					break;
				case this.mr: 
					this.w = (mouse.x - this.x) + this.offset;
					break;
				case this.bm: 
					this.h = (mouse.y - this.y) + this.offset;
					break;
				case this.bl:
					this.w = this.w - (mouse.x - (this.x + this.offset));
					this.x = mouse.x - this.offset;
					this.h = (mouse.y - this.y) + this.offset;
					break;
				case this.br:
					this.w = (mouse.x - this.x) + this.offset;
					this.h = (mouse.y - this.y) + this.offset;
					break;
			}
		}
		if (this.y != yo) this.setY();
		if (this.x != xo) this.setX();
		if (this.w != wo) this.setW();
		if (this.h != ho) this.setH();
	}
	this.setY = function(y) {
    this.y=((y) || (y == 0))?y:this.y;
		this.y=this.validatePosY(this.y);
		if (browserCheck.type == 'safari') this.y += document.body.scrollTop;
		this.container.style.top = this.y + "px";
  }
  this.setX = function(x) {
    this.x=((x) || (x == 0))?x:this.x;
		this.x=this.validatePosX(this.x);
		this.container.style.left = this.x + "px";
  }
	this.setH = function(h) {
		this.h=(h)?h:this.h;
		if (this.h < 0) return;
		this.container.style.height = this.h + "px";
		this.midlayer.style.height = (this.h - 40) + "px";
		this.content.style.height = (this.h - (40 + 16)) + "px";
  }
  this.setW = function(w) {
    this.w=(w)?w:this.w;
		this.container.style.width = this.w + "px";
  }
	this.setDimensions = function(x,y,w,h) {
		if (x) this.setX(x);
		if (y) this.setY(y);
		if (w) this.setW(w);
		if (h) this.setH(h);
	}
	this.reset = function() { //reset xywh window position to default
		delete this.shaded;
		this.setDimensions(50,50,500,250);
	}
	this.showSelf = function() {
	    setOpacity(this.container,1);
      this.container.style.display = "block";
      var windowFadeObj = new objFader(this.container,1,10,3,50);
      this.visible = true;
			this.updateZIndex();
	}
	this.hideSelf = function() {
	    setOpacity(this.container,10);
	    var windowFadeObj = new objFader(this.container,10,1,3,50,true);
      this.visible = false;
	}
	this.saveState = function() { 
		if (tf_state) tf_state.saveState(); 
	}
	this.setBorderCursor = function(bool) {
		this.tm.style.cursor = (!bool)?"default":"n-resize";
		this.tl.style.cursor = (!bool)?"default":"nw-resize";
		this.tr.style.cursor = (!bool)?"default":"ne-resize";
		this.ml.style.cursor = (!bool)?"default":"w-resize";
		this.mr.style.cursor = (!bool)?"default":"e-resize";
		this.bm.style.cursor = (!bool)?"default":"s-resize";
		this.bl.style.cursor = (!bool)?"default":"sw-resize";
		this.br.style.cursor = (!bool)?"default":"se-resize";
	}
	this.getMouseXY = function(event) {
		var x = event.pageX || (event.clientX + document.body.scrollLeft);
		var y = event.pageY || (event.clientY + document.body.scrollTop);
		y -= this.scrollTop;
		return {'x' : x, 'y' : y};
	}
	this.dockConsole = function() {
	  if (this.dockable) {
			if (!this.desktopHeight) this.desktopHeight = document.documentElement.clientHeight;
			if (!this.desktopWidth) this.desktopWidth = document.documentElement.clientWidth;
			this.y = this.desktopHeight - this.h + 18;
			this.container.style.left = "0px";
			this.container.style.top = this.y + "px";
			this.container.style.width = 100 + "%";
			if (this.ie) {
				this.tm.style.width = (this.desktopWidth - 39) + "px";
				this.mm.style.width = (this.desktopWidth - 39) + "px";
				this.bm.style.width = (this.desktopWidth - 39) + "px";
			}
			if (!this.docked) {
				this.docked = true;
			}
		}
	}
	this.unDockOffset = function(position) {
		var offsetXP = position / this.desktopWidth;
		position = offsetXP * this.w;
		return position;
	}
	this.validatePosX = function(position) {
		if ((position < 10) && (position > -75)) { position = 0; }
		if (((position + this.w) > (this.desktopWidth-10)) && ((position + this.w) < (this.desktopWidth+75))) { position = this.desktopWidth - this.w; }
		return position;
	}
	this.validatePosY = function(position) {
		if ((position < 10) && (position > -75)) { position = 0; }
		if (((position + this.h) > (this.desktopHeight-10)) && ((position + this.h) < (this.desktopHeight+75))) { position = this.desktopHeight - this.h; }
		return position;
	}
	this.create();
	this.setEvents();
}


// JSON code (minified for space)
//LLK
/*
if(!Object.prototype.toJSONString){Array.prototype.toJSONString=function(w){var a=[],i,l=this.length,v;for(i=0;i<l;i+=1){v=this[i];switch(typeof v){case'object':if(v){if(typeof v.toJSONString==='function'){a.push(v.toJSONString(w))}}else{a.push('null')}break;case'string':case'number':case'boolean':a.push(v.toJSONString())}}return'['+a.join(',')+']'};Boolean.prototype.toJSONString=function(){return String(this)};Date.prototype.toJSONString=function(){function f(n){return n<10?'0'+n:n}return'"'+this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z"'};Number.prototype.toJSONString=function(){return isFinite(this)?String(this):'null'};Object.prototype.toJSONString=function(w){var a=[],k,i,v;if(w){for(i=0;i<w.length;i+=1){k=w[i];if(typeof k==='string'){v=this[k];switch(typeof v){case'object':if(v){if(typeof v.toJSONString==='function'){a.push(k.toJSONString()+':'+v.toJSONString(w))}}else{a.push(k.toJSONString()+':null')}break;case'string':case'number':case'boolean':a.push(k.toJSONString()+':'+v.toJSONString())}}}}else{for(k in this){if(typeof k==='string'&&Object.prototype.hasOwnProperty.apply(this,[k])){v=this[k];switch(typeof v){case'object':if(v){if(typeof v.toJSONString==='function'){a.push(k.toJSONString()+':'+v.toJSONString())}}else{a.push(k.toJSONString()+':null')}break;case'string':case'number':case'boolean':a.push(k.toJSONString()+':'+v.toJSONString())}}}}return'{'+a.join(',')+'}'};(function(s){var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};s.parseJSON=function(filter){var j;function walk(k,v){var i;if(v&&typeof v==='object'){for(i in v){if(Object.prototype.hasOwnProperty.apply(v,[i])){v[i]=walk(i,v[i])}}}return filter(k,v)}if(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/.test(this.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"/g,''))){j=eval('('+this+')');return typeof filter==='function'?walk('',j):j}throw new SyntaxError('parseJSON');};s.toJSONString=function(){if(/["\\\x00-\x1f]/.test(this)){return'"'+this.replace(/[\x00-\x1f\\"]/g,function(a){var c=m[a];if(c){return c}c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16)})+'"'}return'"'+this+'"'}})(String.prototype)}
if(!Object.prototype.keys) {
  Object.prototype.keys = function() {
    var ret = [];
    for (var k in this) {
      if (this.hasOwnProperty(k)) 
        ret.push(k);
    }
    return ret;
  }
}
*/

function JSTemplateManager() {
  this.templates = {};

  this.Create = function(tplname, tplstr) {
    this.templates[tplname] = new JSTemplate(tplstr, this);
  }
  this.GetTemplate = function(tplname, tplobj) {
    var ret = "[Couldn't find template: '" + tplname + "']";
    if (typeof this.templates[tplname] != 'undefined')
      ret = this.templates[tplname].Map(tplobj);
    return ret;
  }
  this.SetTemplate = function(tplname, tplstr) {
    this.templates[tplname] = tplstr;
  }
  this.HasTemplate = function(tplname) {
    return (typeof this.templates[tplname] != 'undefined');
  }

  this.SetFunction = function(tplname, funcname, funcptr) {
    var ret = false;
    if (typeof this.templates[tplname] != 'undefined') {
      this.templates[tplname].tplfuncs[funcname] = funcptr;
      ret = true;
    }
    return ret;
  }
}

function JSTemplate(tplstr, tplmgr) {
  this.tplstr = tplstr;
  this.tplmgr = tplmgr;
  this.tplfuncs = {};
  this.tplmodifiers = {};
  this.state = {};

  this.Map = function(obj) {
    var ret = this.tplstr;

    var re = new RegExp(/\(%([^\)]+)\)/g);
    var replaces = [];
    while (matches = re.exec(this.tplstr)) {
      var replace = {key:matches[0]};
      if (matches[1].substr(0,1) == '$') {
        var varname = matches[1].substr(1);
        var modifiers = [];
        var i = matches[1].indexOf('|');
        if (i > 0) {
          modifiers = varname.substr(i).split(/\|/g);
          varname = varname.substr(0, i-1);
        }
        replace.value = this.getObjectProperty(obj, varname);

        for (var i = 0; i < modifiers.length; i++) {
          var modname = modifiers[i];
          var modargs = [];
          var pos = modname.indexOf(':');
          if (pos > 0) {
            modargs = modname.substr(pos+1);
            modname = modname.substr(0,pos);
          }
          if (typeof this.tplmodifiers[modname] == 'function') {
            replace.value = this.tplmodifiers[modname](replace.value, modargs);
          }
          
        }
      } else {
        var action = matches[1];
        var args = '';
        var i = action.indexOf(' ');
        if (i > 0) {
          var argsstr = action.substr(i+1);
          action = action.substr(0, i);
          args = this.parseActionArgs(argsstr);
        }

        if (typeof this.tplfuncs[action] == 'function') {
          replace.value = this.tplfuncs[action](this, obj, args);
        } else {
          replace.value = "[jstpl error: no such function '" + action + "']";
        }
      }
      replaces.push(replace);
    }


    for (var i = 0; i < replaces.length; i++) {
      ret = ret.replace(replaces[i].key, (typeof replaces[i].value != 'undefined' ? replaces[i].value : ''));
    }

    // Strip any comments created by if statements or left in the code (handles multi-line comments, too)
    ret = ret.replace(/\n/g, '\uffff').replace(/\(%\*.*\*%\)/g, "").replace(/\uffff/g, '\n');
    
    return ret;
  }

  this.tplfuncs['printpre'] = function(tpl, obj, args) {
    var ret;
    if (tpl.tplmgr) {
      var tplobj = tpl.getObjectProperty(obj, args.obj);
      console.log(tplobj);
    }
    return ret;
  }
  this.tplfuncs['if'] = function(tpl, obj, args) {
    var ret = "(%*";
    var result = false;
    if (typeof args.istrue != 'undefined') {
      var objval = tpl.getObjectProperty(obj, args.istrue);
      if (typeof objval != 'undefined' && objval) {
        result = true;
      }
    }
    if (typeof args.notempty != 'undefined') {
      var objval = tpl.getObjectProperty(obj, args.notempty);
      if (typeof objval != 'undefined' && objval != null) {
        result = true;
      }
    }
    if (typeof args.strcmp != 'undefined') {
      var objval = tpl.getObjectProperty(obj, args.strcmp);
      var argval = args.strval;
      var equality = args.equality;
      if (equality == 'true') {
        if (typeof objval != 'undefined' && (objval==argval) ) {
          result = true;
        }
      } else if (equality == 'false') {
        //TODO - It's a hack for now.  Negative equality statement is usually not intutive.
        result = true;
        if (typeof objval != 'undefined' && (objval==argval) ) {
          result = false;
        }
      }
    }

    if (result) {
      tpl.state['if'] = true;
      ret = "";
    }
    //console.log("if: " + ret);
    return ret;
  }

  this.tplfuncs['/if'] = function(tpl, obj, args) {
    var ret = '*%)';
    if (tpl.state['if']) {
      tpl.state['if'] = false;
      ret = '';
    }
    //console.log("/if: " + ret);
    return ret;
  }

  this.tplmodifiers['number_format'] = function(tplvar, args) {
    var ret = parseFloat(tplvar);
    return (!isNaN(ret) ? ret.toFixed(2) : 0);
  }
  this.tplmodifiers['escape'] = function(tplvar, args) {
    if (args == "js") {
      tplvar = escape(tplvar);
    } else if (args == "html") {
      tplvar = escapeHTML(tplvar);
    } else if (args == "url") {
      tplvar = encodeURIComponent(tplvar).replace(/%20/g,"+");
    }
    return tplvar;
  }

  this.getObjectProperty = function(obj, key) {
    var ret;
  
    if (typeof obj != 'undefined' && typeof key == 'string') {
      var thispart = key;
      var nextpart;
      var i = key.indexOf('\.');

      if (i > 0) {
        thispart = key.substr(0,i);
        nextpart = key.substr(i+1);
      }

      var objtype = typeof obj[thispart];
      if (objtype == 'object' && nextpart) {
        ret = this.getObjectProperty(obj[thispart], nextpart);
      } else if (objtype != 'undefined') {
        ret = obj[thispart];
      }

    }
    return ret;
  }

  this.parseActionArgs = function(argsstr) {
    var ret = {};

    // Neat/ugly trick to parse XML-formated argument strings
    var tmpdiv = document.createElement("DIV");
    tmpdiv.innerHTML = "<div " + argsstr + "></div>";
    for (var i = 0; i < tmpdiv.firstChild.attributes.length; i++) {
      if (tmpdiv.firstChild.attributes[i].specified) {
        ret[tmpdiv.firstChild.attributes[i].name] = tmpdiv.firstChild.attributes[i].value;
      }
    }

    return ret;
  }
}
function objFader(obj,start,end,interval,delay,display) {
  this.start = (start)?start:0;
  this.current = this.start;
  this.end = (end)?end:10;
  this.interval = (interval)?interval:1;
  this.delay = (delay)?delay:100;
	this.display = display;
  this.obj = obj;
  this.Create = function() {
    var thisObj = this;
    var objFaderTimer = setInterval(function() {
      setOpacity(thisObj.obj,thisObj.current);
      if (thisObj.start < thisObj.end) {
        if (thisObj.current >= thisObj.end) { clearInterval(objFaderTimer); }
        thisObj.current += thisObj.interval;
      } else {
        if (thisObj.current <= thisObj.end) { 
					if (thisObj.display) thisObj.obj.style.display = "none";
					else thisObj.obj.style.visibility = "hidden"; 
					setOpacity(thisObj.obj,10); 
					clearInterval(objFaderTimer); 
				}
        thisObj.current -= thisObj.interval;
      }
    },this.delay);
  }
  this.Create();
}

function tfAnimate(obj) {
	this.scalingMethod = 1;
	this.obj = obj;
	
	this.setFPS = function(fps) {
		this.delay = 1000 / fps;
	}

	this.setRate = function(delay,frames) {
		this.delay = (delay)?delay:50;
		this.frames = (frames)?frames:10;	
	}

	// destroy
	this.destroy = function(container) {
		this.container = (container)?container:document.body;
		this.container.removeChild(this.obj);
	}

	// Fade
	this.fade = function(start,end,func) {
		this.start = (start)?start:obj.style.opacity; //recalculate start opacity if null
		this.end = end;
		this.step = (this.end - this.start) / this.frames;
		this.funcFade = (func)?func:false;
		this.index = 1;
		var thisObj = this;
		this.calcFade();
		this.timerFade = setInterval(function() { thisObj.calcFade(); },this.delay);
	}
	this.calcFade = function() {
		if (this.index >= this.frames) this.clearFade();
		this.start += this.step;
		setOpacity(this.obj,this.start);
		this.index++;
	}
	this.clearFade = function() {
		clearInterval(this.timerFade);
		if (typeof this.funcFade == 'function') this.funcFade();
	}
	
	// Traverse
	this.traverse = function(start,end,func) {
		this.start = (start)?start:this.getXY(); //recalculate 'start' XY if null
		
		this.end = end;
		this.stepX = (this.end.x - this.start.x) / this.frames;
		this.stepY = (this.end.y - this.start.y) / this.frames;
		this.funcTraverse = (func)?func:false;
		this.index = 1;
		var thisObj = this;
		this.calcTraverse();
		this.timerTraverse = setInterval(function() { thisObj.calcTraverse(); },this.delay);
	}
	this.getXY = function() {
		if (browserCheck.type == "msie" && browserCheck.version == "7") return {'x': this.obj.offsetLeft,'y':this.obj.offsetTop}
		else return FindXY(this.obj);
	}
	this.calcTraverse = function() {
		if (this.index >= this.frames) this.clearTraverse();
		this.start.x += this.stepX;
		this.start.y += this.stepY;
		this.obj.style.left = this.start.x+'px';
		this.obj.style.top = this.start.y+'px';
		this.index++;
	}
	this.clearTraverse = function() {
		clearInterval(this.timerTraverse);
		if (typeof this.funcTraverse == 'function') this.funcTraverse();
	}
	
	// Scale
	this.scale = function(start,end,func) {
		this.start = (start)?start:FindXYWH(this.obj); //recalculate 'start' XYWH if null
		this.end = end;
		this.stepW = (this.end.w - this.start.w) / this.frames;
		this.stepH = (this.end.h - this.start.h) / this.frames;
		this.funcScale = (func)?func:false;
		this.index = 1;
		if (this.scalingMethod == 1) this.centerScale();
		var thisObj = this;
		this.calcScale();
		this.timerScale = setInterval(function() { thisObj.calcScale(); },this.delay);
	}
	this.calcScale = function() {
		if (this.index > this.frames) this.clearScale();
		this.start.w += this.stepW;
		this.start.h += this.stepH;
		try { this.obj.style.width = this.start.w+'px'; } catch(e) { }
		try { this.obj.style.height = this.start.h+'px'; } catch(e) { }
		if (this.scalingMethod == 1) {
			this.start.x += this.stepX;
			this.start.y += this.stepY;
			this.obj.style.left = this.start.x+'px';
			this.obj.style.top = this.start.y+'px';
		}
		this.index++;
	}
	this.centerScale = function() {
		var x = this.start.x + (this.start.w - this.end.w) / 2;
		var y = this.start.y + (this.start.h - this.end.h) / 2;
		this.stepX = (x - this.start.x) / this.frames;
		this.stepY = (y - this.start.y) / this.frames;
	}
	this.clearScale = function() {
		clearInterval(this.timerScale);
		if (typeof this.funcScale == 'function') this.funcScale();
	}
}

function escapeHTML (str) {
   var div = document.createElement('div');
   var text = document.createTextNode(str);
   div.appendChild(text);
   return div.innerHTML;
};
function tr_size() {
  if(window.innerWidth) {
   var tr_width = window.innerWidth;
   var tr_height = window.innerHeight;
  } else if(document.body.offsetWidth) {
   var tr_width = document.body.offsetWidth;
   var tr_height = document.body.offsetHeight;
  }
  var url = 'http://' + location.host + '/search/sizelog';
  ajaxlib.Get(url + '?width='+tr_width+'&height='+tr_height);
}

function foreach(obj, fn, limit) {
  if (obj && fn) {
    if (typeof obj == 'array') {
      if (typeof limit == 'undefined')
        limit = obj.length;
      for (var i = 0; i < limit; i++) {
        fn(obj[i]);
      }
    } else if (typeof obj == 'object') {
      var keys = obj.keys();
      if (typeof limit == 'undefined')
        limit = keys.length;
      for (var i = 0; i < limit; i++) {
        fn(obj[keys[i]]);
      }
    }
  }
}

Array.prototype.inArray = function (value)
// Returns true if the passed value is found in the
// array.  Returns false if it is not.
{
    var i;
    for (i=0; i < this.length; i++) {
        // Matches identical (===), not just similar (==).
        if (this[i] === value) {
            return true;
        }
    }
    return false;
};

// **************************************************************************
// Copyright 2007 - 2009 Tavs Dokkedahl
// Contact: http://www.jslab.dk/contact.php
//
// This file is part of the JSLab Standard Library (JSL) Program.
//
// JSL is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// any later version.
//
// JSL is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// ***************************************************************************
// Return new array with duplicate values removed
Array.prototype.unique =
  function() {
    var a = [];
    var l = this.length;
    for(var i=0; i<l; i++) {
      for(var j=i+1; j<l; j++) {
        // If this[i] is found later in the array
        if (this[i] === this[j])
          j = ++i;
      }
      a.push(this[i]);
    }
    return a;
  };

