if (typeof thefind == 'undefined') {
  thefind = new function () {
  	this.func = {};
		this.searches = {};
		
  	this.add = function(name, obj) {
	  	switch (typeof obj) {
		  	case 'function': this.func[name] = obj; break;
			  default: if (!this[name]) this[name] = obj; break;
  		}
	  }
		
  	this.search = function() {
  		for (var key in this.searches)
	  		return this.searches[key];  // returns first TFSearch obj
			
			return this.create_search();
  	}
		
		this.create_search = function(name, request, options) {
			var name = !name ? 'tf_search_examplesearch' : name;
			
			search = this.searches[name] = new this.func.search(name, request, options);
			
			return search;
		}
		
		this.find = function(selectors, parent) {
			if (document.querySelectorAll) 
				return (parent) 
					? parent.querySelectorAll(selectors) 
					: document.querySelectorAll(selectors);
			
			return thefind.findCore(selectors, parent);
		}
		
    // primitive selector finding
		this.findCore = function(selectors, parent) {
			var	parent = parent || document.body,
					selectors = selectors.split(','),
					elements = [],
					selector, section, tag, tags, classname;
			
			//for (var s=0; s<selectors.length; s++) {
			//	section = selectors[s].split(' ');
				
				for (var q=0; q<selectors.length; q++) {
					selector = selectors[q].split('.');
					tag = selector[0] || '*';
					tags = parent.getElementsByTagName(tag);
					classname = selector.length > 1 ? selector[1] : false;
					
					for (var i=0; i<tags.length; i++) {
						if (classname) {
							if (thefind.utils.hasClass(tags[i], classname))
								elements.push(tags[i]);
						} else
							elements.push(tags[i]);
					}
				}
				
			//	parent = 
			//}
			
			return elements;
		}
		
		this.checkHash = setInterval(function() { 
			if (typeof thefind.ajax_back_button == 'object')
				thefind.ajax_back_button.check();
		},500);
  }
}

if (!window.console) { // if no console, use tfconsole if available
	window.console = {};
	
	window.console.log = function(txt) {
		thefind.func.log(txt);
	}
} else { // output to both firebug console and tfconsole
	window.console.log = function(txt) {
		if (typeof(thefind.debug) != 'undefined') 
			thefind.func.log(txt);
		
		if (console && typeof console.debug != 'undefined') 
			console.debug.apply(this, arguments);
	}
}

thefind.add('ga', function(selector, obj, event) {
	var event = event || 'click';
	
	//thefind.timing.log(true);
	$TF(selector)[event](function() {
		if (typeof googleAnalytics != 'undefined') {
			googleAnalytics.trackEvent(obj);
		}
	});
	//thefind.timing.log();
	//thefind.timing.print();
});

thefind.add('log', function(txt) {
	if (typeof thefind.debug != 'undefined') 
		thefind.debug.log(txt);
	else {
		if (!thefind.prelog)
			thefind.prelog = [];
		
		thefind.prelog.push(txt);
	}
});

thefind.add('add_results', function(parms) {
	if (parms.extra) 
		for (var key in parms.extra) 
			parms.args[key] = parms.extra[key];
	
	if (parms.type != 'none' && parms.args) 
		parms.args.placement = parms.type;
	
	thefind.search().Bind("results", parms.type, parms.args, parms.id, parms.data, parms.relatedchildren);
});

thefind.add('add_info', function(parms) {
	parms.args.ajax = parms.ajax;
	parms.args.id = 'tf_search_item_actions_savesearchinmyfinds_link';
	
	thefind.search().Bind("info", parms.placement, parms.args);
});

thefind.add('add_input', function(parms) {
	if (!parms.formtag) {
		$TF("#" + parms.id).submit(function() {
			var query = document.getElementById(parms.id).query.value;
			if (query) {
				var placement = parms.placement;
				if (placement == 'frontpage.header' || placement == 'search.header') 
					placement = 'header';
				
				if (typeof googleAnalytics == 'object') 
					googleAnalytics.trackEvent([ 'search', googleAnalytics.pagetype + '.' + placement, query ]);
			}
		});
	}
	
	parms.args.ajax = parms.ajax;
	thefind.search().Bind("input", parms.placement, parms.args);
});

thefind.add('add_list', function(parms) {
  if (parms.name == 'brand' || parms.name == 'store') 
    for (var key in thefind.search().bindings['filters']) 
      for (var jskey in thefind.search().bindings['filters'][key]['filters']) {
        var filter = thefind.search().bindings['filters'][key]['filters'][jskey];
        
        if (jskey == parms.name && typeof filter.checked == 'object') {
          for (var i=0; i<filter.checked.length; i++) {
						element = document.getElementById('tf_search_filters_' + parms.placement + '_' + parms.type + '_' + parms.name + '_' + filter.checked[i]);
            
            if (element) 
							element.checked = 'checked';
          }
          
          // to allow unchecking, nuke all previous checked from memory
          filter.checked = [];
          thefind.search().SearchParms['filter[' + parms.name + ']'] = [];
        }  
      }
});

// panal_submit not used for now
thefind.add('myfinds_panel_submit', function(form, type) {
	var parms = '';
	
	switch(type) {
		case 'brands': type = 'brand'; break;
		case 'stores': type = 'store'; break;
	}
	
	$TF("input:checkbox:checked", form).each(function(k,v) { 
		if (v.value)
			parms += (parms == '' ? '' : ',') + v.value; 
	});
	
	var	u = window.location.href.split('?'),
			n = u[0] + '?' + type + '=' + parms;
	
	window.location.href = n;
	return false;
});

thefind.add('change_location', function(form) {
	this.ajax = function(address) {
		this.close();
		thefind.func.ajax_submit({ parms: { local: 1, location: address } });
		return;
	}

	this.address = function() {
    for (var inputs=form.getElementsByTagName('input'),i=0; i<inputs.length; i++)
      if (inputs[i].name == 'location' || inputs[i].name == 'localsettings[location]')
        if (inputs[i].value)
          return true; //this.ajax(inputs[i].value);
		
		return;
	}
	
	this.close = function() {
		setTimeout(function() {
			thefind.infobox.hide("localsettings_popup");
			thefind.infobox.hide("localsettings_popup1");
		}, 750);
	}

  if (thefind.local) {
    thefind.local.ClearMarkers();
    
		return this.ajax(thefind.local.AjaxInputRequest(search.args.query,form,true));
  } else if (typeof thefind.search().bindings.results != 'undefined') {
		this.close();
		window.location.reload();
		
		return this.address();
  } else {
		this.close();
		window.location.reload();
		
		return;
	}
});

thefind.add('add_map', function(parms) {
	thefind.search().SearchParms.local = 1;
	var inc = 0;
	
	this.init = function(parms) {
		try {
			this.run(parms);
		} catch(e) {
			this.timer();
		}
	}
	
	this.run = function(parms) {
		$TF(document).ready(function() {
			if (++inc > 15)
				return false;
			
			this.local = new thefind.func.local(search, {
				idprefix: "tf_local", 
				location: parms.location, 
				sites: parms.sites, 
				settings: parms.settings 
			});
			
			thefind.local = this.local;
			
			this.local.InitMap("tf_local_map");
			
			if (parms.change_loc) {
				thefind.infobox.add('localsettings_popup1', { 
					margin: 	10,
					absolute:	true,
					width: 		'22em', 
					event: 		'click',
					fixed: 		'tf_search_filters_right',
					border: 	'page.tfinfobox',
					titlebar: true,
					ajax:			1
				}, "&placement=" + parms.placement, '/local/settings', 'tf_search_filters_location_button', true);
			}
		});
	}
	
	this.timer = function() {
		(function(self) {
			setTimeout(function() { self.init(parms); },200);
		})(this);
	}
	
	this.init(parms);
});

thefind.add('add_location', function(location) {
	thefind.location = location;
	
	$TF(document).ready(function() {
		var	local_checkbox = document.getElementById('tf_search_filters_toggle_localtoggle_input'),
				local_tabs = document.getElementById('tf_search_filters_list_store_tabs');
		
		if (local_tabs)
			local_tabs = local_tabs.getElementsByTagName('li');
		
		if (local_checkbox) {
			local_checkbox.disabled = !location[0];
			if (local_checkbox.checked && !location[0])
				local_checkbox.checked = false;
		}
		
		if (arrayGet(local_tabs,'length') > 1)
			local_tabs[1].style.display = (location[0] ? 'block' : 'none');
	});
});

thefind.add('binary_sort', function(v, o) {
	var	i = o.length, 
			l = -1, 
			m;
	
	while (i - l > 1) {
		var n = o[m = (i + l) >> 1].getElementsByTagName('DIV')[0].innerHTML.split(' ')[0] * 100;
		
		if (n < v) 
			l = m;
		else 
			i = m;
	}
	
	return i;
});

thefind.add('googleAnalytics_myfinds', function(type, section, formtag) {
  if (typeof googleAnalytics != 'object') 
    return false;
  console.log('thefind.googleAnalytics_myfinds');
	thefind.timing.log(true);
  $TF("div#tf_myfinds_saved_" + type + " a.tf_search_item_link strong").click(function () {
    googleAnalytics.clickoutsource = (section == 'saved') ? 8 : 11;
  });
  
  $TF("div#tf_myfinds_saved_{$type} a.tf_search_item_link").click(function () {
    if (!googleAnalytics.clickoutsource) 
      googleAnalytics.clickoutsource = (section == 'saved') ? 9 : 12;
    
    googleAnalytics.myfindspanel = 'myfavs_' + section;
  });
  
  $TF("a.tf_myfinds_saved_searches_link").each(function(n) {
    $TF(this).click(function() { 
      googleAnalytics.trackEvent(['links', googleAnalytics.pagetype, 'recent_searches', n + 1])
    });
  });
  
  if (formtag)
    $TF("#tf_myfinds_searchform_" + type).submit(function() {
      var query = document.getElementById('tf_myfinds_searchform_' + type).query.value;
      if (query) googleAnalytics.trackEvent(['search', 'myfavorites.' + type, query]);
    });

	thefind.timing.log();
	thefind.timing.print();
});

thefind.add('bezier_curve', function() {
	this.order = 2;
	this.cp = [];
	this.curve = [];

	this.points = function(points) {
		this.order = points.length - 1;
		
		for (var i=0; i<points.length; i++) 
			this.cp[i] = points[i];
	}
	
	this.bf = function(i, t) {
		var	o = this.order,
				h = this.h || (this.h = o / 2),
				f = this.f || (this.f = parseInt(h)),
				c = this.c || (this.c = (h == f) ? f : f + 1),
				
				x = o * (f - (i <= f ? f - i : i - c)) || 1,
				a = Math.pow(t, o - i).toFixed(8) || 1,
				b = Math.pow(1 - t, i).toFixed(8) || 1;
		
		return x * a * b;
	}
	
	this.calc = function(precision, noround) {
		for (var i=0; i<=precision; i++) 
			this.curve[i] = (noround)
				? this.pos(i / precision)
				: Math.round(this.pos(i / precision));
		
		return this.curve;
	}
	
	this.pos = function(p) {
		for (var pos=i=0; i<=this.order; i++) 
			pos += this.cp[i] * this.bf(i, p);	
		
		return pos;
	}

	this.draw = function(color,debug,invert,container,array) {
		if (!this.container) 
			this.container = container || $TF('#tf_container')[0];
		
		array = array || this.curve;
		invert = (invert) ? 100 : 0;
		
		if (debug) 
			console.log(array);
		
		for (var i=0; i<this.curve.length; i++) {
			var point = document.createElement('div');
			this.container.appendChild(point);
			
			$TF(point).css({
				position: 'absolute',
				background: color,
				width: 2 + 'px',
				height: 2 + 'px',
				left: i + 'px',
				top: invert - array[i] + 'px'
			});
		}
	}
});

thefind.add('create', function(type, classname, styles, additional, appendTo, appendBefore) {
  var element = document.createElement(type);
  
  if (classname)
    element.className = classname;
  
  if (styles)
    for (var property in styles)
      element.style[property] = styles[property];
  
  if (additional)
    for (var property in additional)
      element[property] = additional[property];
  
	//console.log(element, appendTo, appendBefore);
	if (appendTo)
		if (appendBefore)
      appendTo.insertBefore(element, appendBefore);
    else
      appendTo.appendChild(element);
	
  return element;
});

thefind.add('bind', function(obj, type, fn) {
	//console.log('add event ' + type + ' on '+obj+' '+obj.tagName+' '+obj.id);
  if (obj) {
    if (obj.addEventListener) {
			if (type == 'mousewheel' && thefind.browser.type != 'safari') type = 'DOMMouseScroll';
      //console.log(typeof fn +' '+ typeof fn.handleEvent)
      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(thefind.utils.fixEvent(window.event)); }
      } else {
        obj["e"+type+fn] = fn;
        obj[type+fn] = function() { if (typeof obj["e"+type+fn] == 'function') obj["e"+type+fn]( thefind.utils.fixEvent(window.event) ); }
      }
      obj.attachEvent( "on"+type, obj[type+fn]);
    }
  }
  //console.log('end add event ' + type + ' on '+obj+' '+obj.tagName+' '+obj.id);

	
	return this;
});

thefind.add('unbind', function(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) {
    if (typeof obj[type+fn] == "function")
      obj.detachEvent( "on"+type, obj[type+fn] );
    obj[type+fn] = null;
    obj["e"+type+fn] = null;
  }
	
	return this;
});

thefind.add('get_scroll', function(shpadoinkle) {
  if (thefind.iphone)
    var pos = [0, -1*thefind.iphone.utils.getTranslateY(thefind.iphone.content)];
	else if (typeof pageYOffset != 'undefined') 
		var pos = [ 
			pageXOffset, 
			pageYOffset 
		];
	else 
		var	QuirksObj = document.body,
				DoctypeObj = document.documentElement,		
				element = (DoctypeObj.clientHeight) 
					? DoctypeObj 
					: QuirksObj,
				pos = [ 
					element.scrollLeft, 
					element.scrollTop 
				];

	switch (shpadoinkle) {
		case 0:
			return pos[0];
		
		case 1:
			return pos[1];
		
		default:
			return [ 
				pos[0], 
				pos[1] 
			];
	}
});

thefind.add('dimensions', function(element,ignore_size) {
	if (typeof element != 'object' || element === window) {
		var	width = window.innerWidth		|| document.documentElement.clientWidth		|| document.body.clientWidth,
				height = window.innerHeight	|| document.documentElement.clientHeight	|| document.body.clientHeight;
		
		return {
			0 : width,
			1 : height,
			x : 0,
			y : 0,
			w : width,
			h : height,
			s : thefind.func.get_scroll()
		};
	}
	
	var width = ignore_size ? 0 : element.offsetWidth,
			height = ignore_size ? 0 : element.offsetHeight,
			left = element.offsetLeft,
			top = element.offsetTop;
	
	while (element = element.offsetParent) {
		top += element.offsetTop - element.scrollTop;
		left += element.offsetLeft - element.scrollLeft;
	}
	
	if (thefind.browser.type == 'safari')
		top += thefind.func.get_scroll(1);
	
	return {
		0 : left,
		1 : top,
		x : left, 
		y : top, 
		w : width, 
		h : height 
	};
});

thefind.add('browser', new function() {
  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";
  }
	
	if (this.type+this.version == 'msie6')
		thefind.ie6 = true;
});

thefind.add('file_utils', function() {
	// grabs a js or css file and adds to document
  this.get = function(type, file, func) {
		if (!type || !file)
			return false;
		
    // FIXME - not cross-domain safe
    /*
		if (type == 'javascript') 
			return $TF.getScript(file,func);
    */
		
		var	head = document.getElementsByTagName("HEAD")[0],
				element = document.createElement((type == 'javascript' ? "SCRIPT" : "LINK"));
		
		if (type == 'javascript') {
			element.type = "text/javascript";
			element.src = file;
		} else {
			element.type = "text/css";
			element.rel = "stylesheet";
			element.href = file;
		}
		
		if (func)
			element.onload = func;
		
    head.appendChild(element);
		
		return element;
  }
});

thefind.add('dependencies_batch',function() {
	this.callbacks = [];
	this.files = [];
	
	this.add = function(url, type, component) {
		if (typeof url == 'string') {
      var dep = thefind.dependencies.add(url, this, type, component)
      
			if (dep) 
        this.files.push(dep);
    }
	}
	
	this.callback = function(script) {
		this.callbacks.push(script);
		
		if (this.files.length == 0)
			this.done(true);
	}
	
	this.done = function(url) {
		if (url)
			for (var i=0; i<this.files.length; i++) 
				if (!this.files[i].loaded && this.files[i].type != 'css') 
					return;
		
		for (var i=0; i<this.callbacks.length; i++) 
			switch (typeof this.callbacks[i]) {
				case "string": 
					eval(this.callbacks[i]); 
					break;
				
				case "function": 
					this.callbacks[i](); 
					break;
			}
		
		this.callbacks = [];
	}
});

thefind.add('dependencies',new function() {
	this.files = {};
	this.registered = { javascript: { }, css: { } };
	this.waiting = { javascript: { }, css: { } };
	this.host = '';
	
	this.register = function(sFile, check, type) {
    var	type = type || 'javascript',
				r = this.registered[type],
				w = this.waiting[type];
		
		if (r[sFile])
			return;
		
    if (typeof check == 'undefined')
      check = true;
		
		//console.log('registering: ',sFile, type);
		r[sFile] = true;
		if (w[sFile]) {
			var	url = w[sFile],
					file = this.files[url],
					components = this.getComponents(url);
			
			delete w[sFile];
      
      this.checkWaiting(file, components, type);
		}
	}
  
	this.registerMany = function(components, type) {
    for (var k in components) 
      if (components.hasOwnProperty(k) && components[k].length > 0) 
        for (var i = 0; i < components[k].length; i++) 
          if (components[k][i] != null)
            this.register(k + '.' + components[k][i], false, type);
  }
  
  this.checkWaiting = function(file, components, type) {
		var	type = type || 'javascript',
				w = this.waiting[type],
				b = true;
    
		for (var i=0; i<components.length; i++) {
			if (w[components[i]]) {
				b = false;
				break;
			}
		}
		
		if (b) 
			this.done(file);
  }
	
	this.getComponents = function(url) {
		var	ret = [],
				url = url.split('?'),
				page = url[0],
				parms = url[1].split('&');
		
		for (var i=0; i<parms.length; i++) {
			var parm = parms[i].split('='),
					files = parm[1].split('+');
			
			for (var f=0; f<files.length; f++) {
				file = parm[0] +'.'+ files[f];
				
				ret.push(file);
			}
		}
		
		return ret;
	}
	
	this.wait = function(url, type) {
		var	type = type || 'javascript',
				r = this.registered[type],
				w = this.waiting[type],
				components = this.getComponents(url);
		
		for (var i=0; i<components.length; i++)
			if (!r[components[i]]) 
				w[components[i]] = true;
		
		url = this.url(w);
		
		for (var key in w)
			w[key] = '/' + (type == 'css' ? 'css' : 'scripts') + '/main' + url;
		
		return url;
	}
	
	this.url = function(oParms) {
		var	parms = {},
				ret = '';
		
		for (var key in oParms) {
			parm = key.split('.');
			
			if (!parms[parm[0]])
				parms[parm[0]] = [];
			
			parms[parm[0]].push(parm[1]);
		}
		
		for (var key in parms) {
			ret += (ret == '' ? '?' : '&') + key + '=';
			
			for (var i=0; i<parms[key].length; i++) {
				if (parms[key][i] != 'map')
					ret += parms[key][i] + (i == parms[key].length-1?'':'+');
				else if (i == parms[key].length-1)
					ret = ret.substr(0,ret.length-1);
			}
		}
		
		if (ret.indexOf("=") < 0)
			ret = '';
		
		return ret;
	}
	
	this.done = function(oFile) {
    if (typeof oFile != 'undefined') {
  		oFile.loaded = true;
			
	  	if (oFile.batch)
		  	oFile.batch.done(oFile.url);
    }
	}
	
	this.add = function(url, batch, type, component) {
		var	file = this.files[url] || {},
				type = type || 'javascript';
		
		if (!thefind.utils.isNull(file.url)) {
			if (batch) {
				batch.done(url);
				return file;
			}
		}
		
		if (component || type == 'css') {
			url = this.wait(url, type);
			
			if (url) 
				url = '/' + (type == 'css' ? 'css' : 'scripts') + '/main' + url;
			else 
				return false;
		}
		
		//console.log(type, url);
		
		file.batch = batch;
		file.loaded = false;
		file.url = url;
		file.type = type;
    
		file.element = thefind.file_utils.get(type, this.host + url, (
			(component)
				? null
				: (function(self) { 
						self.done(file); 
					})(this)
		));
		
		this.files[url] = file;
		
		return file;
	}
});

thefind.add('component', new function() {
  this.ids = {};

  this.get = function(id, name, args) {
    // console.log('get ' + name, args);
    if (name) {
      //var reqid = this.generateRequestID();

      var url = this.host + '/' + name.replace("\.", "/") + ".js";

      
      if (args) {
        if (typeof args == 'object') {
          var urlsep = "?";
          // FIXME - this should use a common URL encoding/flattening function
          for (var k in args) {
            if (k && args[k])
              url += urlsep + k + "=" + args[k];
              urlsep = "&";
          }
        } else if (typeof args == 'string') {
          url += "?" + args;
        }
      }

      thefind.file_utils.get("javascript", url);
    }
  
  }

  this.response = function(reqid, contents) {
    if (reqid && this.ids[reqid]) {
      var id = this.ids[reqid];
      $TF("#"+id).html(contents);
    }
  }

  this.generateRequestID = function() {
    return (parseInt(new Date().getTime().toString().substring(0, 10)) + parseFloat(Math.random()));
  }
});

thefind.add('onloads',new function() {
  this.done = false;
  this.onloads = [];

  this.add = function(expr) {
    this.onloads.push(expr);
  }
  this.init = function() {
    /* for Safari */
    if (/WebKit/i.test(navigator.userAgent)) { // sniff
      this.timer = setInterval(function() {
        if (/loaded|complete/.test(document.readyState)) {
          thefind.onloads.execute(); // call the onload handler
        }
      }, 10);
      return;
    }

    /* for Mozilla/Opera9 */
    if (document.addEventListener) {
      document.addEventListener("DOMContentLoaded", thefind.onloads.execute, false);
      return;
    }
    /* for Internet Explorer */
    /*@cc_on @*/
    /*@if (@_win32)
        document.write("<scr"+"ipt id=\"__ie_onload\" defer src=\"/blank.fhtml\"><\/scr"+"ipt>");
        var script = document.getElementById("__ie_onload");
        script.onreadystatechange = function() {
            if (this.readyState == "complete") {
                thefind.onloads.execute(); // call the onload handler
            }
        };
        return;
    /*@end @*/
  
    window.onload = thefind.onloads.execute;
  }
  this.execute = function() {
    // FIXME - there's no reason for this to be here.  Or is there...
	  //$TF(document).ready(function() { fixPNG(); });
    // quit if this function has already been called
    if (thefind.onloads.done) return;

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

    // kill the timer
    if (thefind.onloads.timer) clearInterval(thefind.onloads.timer);

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

thefind.add('log_size', function(result_view_id) {
	if (typeof result_view_id == 'undefined')
		result_view_id = '';
	
	if (window.innerWidth) 
		var	tr_width = window.innerWidth,
				tr_height = window.innerHeight;
	else 
		if (document.body.offsetWidth) 
			var	tr_width = document.body.offsetWidth,
					tr_height = document.body.offsetHeight;
	
	if (ajaxlib)
		ajaxlib.Get('/page/sizelog?width=' + tr_width + '&height=' + tr_height + '&result_view_id=' + result_view_id);
});

thefind.add("utils", new function() {
  this.encodemap = {"_": "//",	// technically this replaces "_" with "__"
                    "/": "_",
                    "+": "&&",	// technically this replaces "+" with "++"
                    "&": "+",
                    "-": "~",
                    " ": "-",
                    "\"": "%22",
                    "'": "%27" };

  this.regexps = {};

  this.FriendlyURLEncode = function(str) {
    var ret = str;
    var utils = this;

    if (typeof str == 'string')
      $TF.each(this.encodemap, function(key, val) { if (!utils.regexps[key]) { utils.regexps[key] = new RegExp(utils.escapeRegexp(key), "g"); } ret = ret.replace(utils.regexps[key], val); });
    else if (typeof str == 'array')
      ret = str.join(",");
      
    return ret;
  }

  this.escapeRegexp = function(text) {
    if (!this.regexps.regexp) {
      var specials = [
        '/', '.', '*', '+', '?', '|',
        '(', ')', '[', ']', '{', '}', '\\'
      ];
      this.regexps.regexp = new RegExp(
        '(\\' + specials.join('|\\') + ')', 'g'
      );
    }
    return text.replace(this.regexps.regexp, '\\$1');
  }

  this.encodeURLParams = function(obj) {
		var value,ret = '';
		
    if (typeof obj == "string") {
      ret = obj;
    } else {
      for (var key in obj) {
        ret += (ret != '' ? '&' : '') + key + '=' + encodeURIComponent(obj[key]); 
      }
    }
		
		return ret;
  }
	
  this.getElementsByClassName = function(oElm, strTagName, strClassName) {
		var arrElements = (strTagName == "*" && oElm.all)
					? oElm.all 
					: oElm.getElementsByTagName(strTagName),
				arrReturnElements = new Array(),
				oElement;
		
		strClassName = strClassName.replace(/\-/g, "\\-");
		var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
		
		for (var i=0; i<arrElements.length; i++) {
			oElement = arrElements[i];
      
			if (oRegExp.test(oElement.className)) {
				arrReturnElements.push(oElement);
			}   
		}
		
		return arrReturnElements;
  }
	
  this.isTrue = function(obj) {
  	if (obj == true || obj == 'true') 
	  	return true;
		
  	return false;
  }
	
  this.isNull = function(obj) {
  	if (obj == null || typeof obj == 'undefined') 
	  	return true;
		
  	return false;
  }
	
	this.isEmpty = function(obj) {
		if (obj !== null && obj !== "" && obj !== 0 && typeof obj !== "undefined" && obj !== false) 
			return false;
		
		return true;
	}
	
  this.elementAddClass = function(element, className) {
    if (element.className)
			element.className += " " + className;
		else
			element.className = className;
  }
	
  this.elementRemoveClass = function(element, className) {
    var re = new RegExp("(^| )" + className + "( |$)", "g");
		
		if (this.hasClass(element, className))
			element.className = element.className.replace(re, " ");
  }
  
  this.toggleClass = function(element, className) {
    if (this.hasClass(element, className))
      this.removeClass(element, className)
    else
      this.addClass(element, className);
  }
  
  this.addClass = function(element, className) {
    this.elementAddClass(element, className);
  }
  
  this.removeClass = function(element, className) {
    this.elementRemoveClass(element, className);
  }

  this.hasClass = function(element, className) {
    return this.elementHasClass(element, className);
  }
	
  this.elementHasClass = function(element, className) {
    if (element && element.className) {
      var re = new RegExp("(^| )" + className + "( |$)", "g");
      return (element.className.match(re) != null);
    }
		
    return false;
  }
	
	this.getFirstChild = function(obj, tag, className) {
		for (var i=0; i<obj.childNodes.length; i++)
			if (obj.childNodes[i].nodeName == tag.toUpperCase())
        if (className && this.hasClass(obj, className))
          return obj.childNodes[i];
        else if (!className)
          return obj.childNodes[i];
		
		return null;
	}
  
	this.getLastChild = function(obj, tag, className) {
		for (var i=obj.childNodes.length-1; i>=0; i--)
			if (obj.childNodes[i].nodeName == tag.toUpperCase())
        if (className && this.hasClass(obj, className))
          return obj.childNodes[i];
        else if (!className)
          return obj.childNodes[i];
		
		return null;
	}
	
	this.getAll = function(obj, tag, className) {
		var	ret = [],
				all = obj.getElementsByTagName(tag);
		
		for (var i=0; i<all.length; i++)
			if (className && this.hasClass(all[i], className))
				ret.push(all[i]);
			else if (!className)
				ret.push(all[i]);
		
		return ret;
	}

	this.getOnly = function(obj, tag, className) {
		var ret = [];
		
		for (var i=0; el=obj.childNodes[i]; i++)
			if (el.nodeName == tag.toUpperCase())
				if (className && this.hasClass(el, className))
					ret.push(el);
				else if (!className)
					ret.push(el);
		
		return ret;
	}
  
	this.find = thefind.find;
	
	this.getTarget = function(event) {
		return (window.event) ? event.srcElement : event.target;
	}

	this.getRelatedTarget = function(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;
	}

	this.getEventTarget = function(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, 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 (!this.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 = this.getElementsByClassName(target, "*", classUp);
				if (elements.length > 0) {
					target = elements[0];
				}
			}
		}
		
		return target;
	}

	this.eventIsTransition = function(event, parent) {
		var	tg = this.getTarget(event),
				reltg = this.getRelatedTarget(event);
		
		return (this.elementIsIn(tg, parent) && !this.elementIsIn(reltg, parent));
	}
	
  this.fixEvent = function(event) {
    this.preventDefault = function() {
      this.returnValue = false;
    }
		
    this.stopPropagation = function() {
      this.cancelBubble = true;
    }
		
    event.preventDefault = this.preventDefault;
    event.stopPropagation = this.stopPropagation;
		
    return event;
  }
});

thefind.add('file_utils', new thefind.func.file_utils());

// adds Array.indexOf to javascript for IE
if (!Array.indexOf) {
	Array.prototype.indexOf = function(obj) {
		for(var i=0; i<this.length; i++)
			if(this[i] == obj)
				return i;
		
		return -1;
	}
}

// JSON code (minified for space)
if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;}Date.prototype.toJSON=function(key){return this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z';};var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapeable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapeable.lastIndex=0;return escapeable.test(string)?'"'+string.replace(escapeable,function(a){var c=meta[a];if(typeof c==='string'){return c;}return'\\u'+('0000'+(+(a.charCodeAt(0))).toString(16)).slice(-4);})+'"':'"'+string+'"';}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}if(typeof rep==='function'){value=rep.call(holder,key,value);}switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}gap+=indent;partial=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}v=partial.length===0?'[]':gap?'[\n'+gap+partial.join(',\n'+gap)+'\n'+mind+']':'['+partial.join(',')+']';gap=mind;return v;}if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value,rep);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value,rep);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}return{stringify:function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}return str('',{'':value});},parse:function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}return reviver.call(holder,key,value);}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+('0000'+(+(a.charCodeAt(0))).toString(16)).slice(-4);});}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}throw new SyntaxError('JSON.parse');}};}();}

thefind.add('JSON', new function() {
  this.parse = function(text) {
    return this.JSON(['decode','parse'],text);
  },
  
  this.stringify = function(text) {
    return this.JSON(['encode','stringify'],text);
  },
  
  this.JSON = function(parms,text) {
    return JSON[(typeof JSON[parms[0]]=='function'?parms[0]:parms[1])](text);
  }
});

thefind.add('ie6_purge', function(d) {
	if (!thefind.ie6 || !d)
		return;
	
	var	a = d.attributes, 
			i, l, n;
	
	if (a) {
		l = a.length;
		
		for (i = 0; i < l; i += 1) {
			n = a[i].name;
			
			if (typeof d[n] === 'function')
				d[n] = null;
		}
	}
	
	a = d.childNodes;
	
	if (a) {
		l = a.length;
		
		for (i = 0; i < l; i += 1)
			thefind.func.ie6_purge(d.childNodes[i]);
	}

  CollectGarbage();
});
thefind.add("tplmgr", new function() {
  this.templates = {};

  this.Create = function(tplname, tplstr) {
		if (!this.templates[tplname]) {
			//this.templates[tplname] = new thefind.func.jstemplate(tplstr, this);
			this.SetTemplate(tplname, tplstr);
			//console.log('create template: ' + tplname, this.templates[tplname]);
		}
	}
  this.GetTemplate = function(tplname, tplobj) {
    var ret = "[Couldn't find template: '" + tplname + "']";
    if (typeof this.templates[tplname] != 'undefined')
      ret = this.templates[tplname].Map(tplobj);
    else 
			console.log('Template not found: ' + tplname + ' ' + this.templates[tplname]);
    
		return ret;
  }
	
  this.SetTemplate = function(tplname, tplstr) {
    this.templates[tplname] = new thefind.func.jstemplate(tplstr, this);
  }
	
  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;
  }
});
thefind.add("jstemplate", function(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) == '$') {  // print variable - (%$varname)
        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 { // Execute template function - (%funcname)
        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.empty != 'undefined') {
      var objval = tpl.getObjectProperty(obj, args.empty);
      if (typeof objval == 'undefined' || objval == null) {
        result = true;
      }
    }
    if (typeof args.notempty != 'undefined') {

      var objval = tpl.getObjectProperty(obj, args.notempty);
      if (typeof objval != 'undefined' && objval != null && objval !== '') {

        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 = "";
    }
    return ret;
  }

  this.tplfuncs['/if'] = function(tpl, obj, args) {
    var ret = '*%)';
    if (tpl.state['if']) {
      tpl.state['if'] = false;
      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.tplmodifiers['friendlyurl'] = function(tplvar, args) {
    var utils = new TFHtmlUtils();
    return utils.FriendlyURLEncode(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;
  }
});
$TF = jQuery.noConflict();

(function($){$.fn.bgIframe=$.fn.bgiframe=function(s){if($.browser.msie&&/6.0/.test(navigator.userAgent)){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($('> iframe.bgiframe',this).length==0)this.insertBefore(document.createElement(html),this.firstChild);});}return this;};})(jQuery);
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(b($){$.m.E=$.m.g=b(s){h($.x.10&&/6.0/.I(D.B)){s=$.w({c:\'3\',5:\'3\',8:\'3\',d:\'3\',k:M,e:\'F:i;\'},s||{});C a=b(n){f n&&n.t==r?n+\'4\':n},p=\'<o Y="g"W="0"R="-1"e="\'+s.e+\'"\'+\'Q="P:O;N:L;z-H:-1;\'+(s.k!==i?\'G:J(K=\\\'0\\\');\':\'\')+\'c:\'+(s.c==\'3\'?\'7(((l(2.9.j.A)||0)*-1)+\\\'4\\\')\':a(s.c))+\';\'+\'5:\'+(s.5==\'3\'?\'7(((l(2.9.j.y)||0)*-1)+\\\'4\\\')\':a(s.5))+\';\'+\'8:\'+(s.8==\'3\'?\'7(2.9.S+\\\'4\\\')\':a(s.8))+\';\'+\'d:\'+(s.d==\'3\'?\'7(2.9.v+\\\'4\\\')\':a(s.d))+\';\'+\'"/>\';f 2.T(b(){h($(\'> o.g\',2).U==0)2.V(q.X(p),2.u)})}f 2}})(Z);',62,63,'||this|auto|px|left||expression|width|parentNode||function|top|height|src|return|bgiframe|if|false|currentStyle|opacity|parseInt|fn||iframe|html|document|Number||constructor|firstChild|offsetHeight|extend|browser|borderLeftWidth||borderTopWidth|userAgent|var|navigator|bgIframe|javascript|filter|index|test|Alpha|Opacity|absolute|true|position|block|display|style|tabindex|offsetWidth|each|length|insertBefore|frameborder|createElement|class|jQuery|msie'.split('|'),0,{}));

(function($) {
    $.fn.extend({
        isChildOf: function( filter_string ) {
          
          var parents = $(this).parents().get();
         
          for ( j = 0; j < parents.length; j++ ) {
           if ( $(parents[j]).is(filter_string) ) {
      return true;
           }
          }
          
          return false;
        }
    });
})(jQuery); 

$TF.delegate = function(rules, checkparents) {
  return function(e) {
    var target = $TF(e.target);

    if (typeof checkparents == 'undefined') 
      checkparents = true;

    for (var selector in rules) {
      if (target.is(selector)) {
        var args = $TF.makeArray(arguments);
        args.push(selector);
        return rules[selector].apply(this, args);
      } else if (checkparents) {
        // Check to see if we're inside of the selector we want
        var parents = target.parents(selector);
        if (parents.length > 0) {
          var args = $TF.makeArray(arguments);
          args.push(selector);
          return rules[selector].apply(this, args);
        }
      }
    }
  }
}
$TF.undelegate = function(rules, checkparents) {
  return function(e) {
    var target = $TF(e.target);

    if (typeof checkparents == 'undefined') 
      checkparents = true;

    for (var selector in rules) {
      if (target.is(selector)) {
        var args = $TF.makeArray(arguments);
        args.push(selector);
        return rules[selector].apply(this, args);
      } else if (checkparents) {
        // Check to see if we're inside of the selector we want
        var parents = target.parents(selector);
        if (parents.length > 0) {
          var args = $TF.makeArray(arguments);
          args.push(selector);
          return rules[selector].apply(this, args);
        }
      }
    }
  }
}



/*
 * jQuery Easing v1.1.1 - http://gsgd.co.uk/sandbox/jquery.easing.php
 *
 * Uses the built in easing capabilities added in jQuery 1.1
 * to offer multiple easing options
 *
 * Copyright (c) 2007 George Smith
 * Licensed under the MIT License:
 *   http://www.opensource.org/licenses/mit-license.php
 */

jQuery.extend(jQuery.easing, {
	easein: function(x, t, b, c, d) {
		return c*(t/=d)*t + b; // in
	},
	easeinout: function(x, t, b, c, d) {
		if (t < d/2) return 2*c*t*t/(d*d) + b;
		var ts = t - d/2;
		return -2*c*ts*ts/(d*d) + 2*c*ts/d + c/2 + b;		
	},
	easeout: function(x, t, b, c, d) {
		return -c*t*t/(d*d) + 2*c*t/d + b;
	},
	expoin: function(x, t, b, c, d) {
		var flip = 1;
		if (c < 0) {
			flip *= -1;
			c *= -1;
		}
		return flip * (Math.exp(Math.log(c)/d * t)) + b;		
	},
	expoout: function(x, t, b, c, d) {
		var flip = 1;
		if (c < 0) {
			flip *= -1;
			c *= -1;
		}
		return flip * (-Math.exp(-Math.log(c)/d * (t-d)) + c + 1) + b;
	},
	expoinout: function(x, t, b, c, d) {
		var flip = 1;
		if (c < 0) {
			flip *= -1;
			c *= -1;
		}
		if (t < d/2) return flip * (Math.exp(Math.log(c/2)/(d/2) * t)) + b;
		return flip * (-Math.exp(-2*Math.log(c/2)/d * (t-d)) + c + 1) + b;
	},
	bouncein: function(x, t, b, c, d) {
		return c - jQuery.easing['bounceout'](x, d-t, 0, c, d) + b;
	},
	bounceout: function(x, t, b, c, d) {
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
		} else {
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
		}
	},
	bounceinout: function(x, t, b, c, d) {
		if (t < d/2) return jQuery.easing['bouncein'] (x, t*2, 0, c, d) * .5 + b;
		return jQuery.easing['bounceout'] (x, t*2-d,0, c, d) * .5 + c*.5 + b;
	},
	elasin: function(x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	},
	elasout: function(x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
	},
	elasinout: function(x, t, b, c, d) {
		var s=1.70158;var p=0;var a=c;
		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
		if (a < Math.abs(c)) { a=c; var s=p/4; }
		else var s = p/(2*Math.PI) * Math.asin (c/a);
		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
	},
	backin: function(x, t, b, c, d) {
		var s=1.70158;
		return c*(t/=d)*t*((s+1)*t - s) + b;
	},
	backout: function(x, t, b, c, d) {
		var s=1.70158;
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	},
	backinout: function(x, t, b, c, d) {
		var s=1.70158;
		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
	}
});

/**
 * jQuery.ScrollTo - Easy element scrolling using jQuery.
 * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under MIT and GPL.
 * Date: 9/11/2008
 * @author Ariel Flesler
 * @version 1.4
 *
 * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
 */
;(function(h){var m=h.scrollTo=function(b,c,g){h(window).scrollTo(b,c,g)};m.defaults={axis:'y',duration:1};m.window=function(b){return h(window).scrollable()};h.fn.scrollable=function(){return this.map(function(){var b=this.parentWindow||this.defaultView,c=this.nodeName=='#document'?b.frameElement||b:this,g=c.contentDocument||(c.contentWindow||c).document,i=c.setInterval;return c.nodeName=='IFRAME'||i&&h.browser.safari?g.body:i?g.documentElement:this})};h.fn.scrollTo=function(r,j,a){if(typeof j=='object'){a=j;j=0}if(typeof a=='function')a={onAfter:a};a=h.extend({},m.defaults,a);j=j||a.speed||a.duration;a.queue=a.queue&&a.axis.length>1;if(a.queue)j/=2;a.offset=n(a.offset);a.over=n(a.over);return this.scrollable().each(function(){var k=this,o=h(k),d=r,l,e={},p=o.is('html,body');switch(typeof d){case'number':case'string':if(/^([+-]=)?\d+(px)?$/.test(d)){d=n(d);break}d=h(d,this);case'object':if(d.is||d.style)l=(d=h(d)).offset()}h.each(a.axis.split(''),function(b,c){var g=c=='x'?'Left':'Top',i=g.toLowerCase(),f='scroll'+g,s=k[f],t=c=='x'?'Width':'Height',v=t.toLowerCase();if(l){e[f]=l[i]+(p?0:s-o.offset()[i]);if(a.margin){e[f]-=parseInt(d.css('margin'+g))||0;e[f]-=parseInt(d.css('border'+g+'Width'))||0}e[f]+=a.offset[i]||0;if(a.over[i])e[f]+=d[v]()*a.over[i]}else e[f]=d[i];if(/^\d+$/.test(e[f]))e[f]=e[f]<=0?0:Math.min(e[f],u(t));if(!b&&a.queue){if(s!=e[f])q(a.onAfterFirst);delete e[f]}});q(a.onAfter);function q(b){o.animate(e,j,a.easing,b&&function(){b.call(this,r,a)})};function u(b){var c='scroll'+b,g=k.ownerDocument;return p?Math.max(g.documentElement[c],g.body[c]):k[c]}}).end()};function n(b){return typeof b=='object'?b:{top:b,left:b}}})(jQuery);

/*
 * jQuery Color Animations
 * Copyright 2007 John Resig
 * Released under the MIT and GPL licenses.
 */

(function(jQuery){

	// We override the animation for all of these color styles
	jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
		jQuery.fx.step[attr] = function(fx){
			if ( fx.state == 0 ) {
				fx.start = getColor( fx.elem, attr );
				fx.end = getRGB( fx.end );
			}

			fx.elem.style[attr] = "rgb(" + [
				Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
			].join(",") + ")";
		}
	});

	// Color Conversion functions from highlightFade
	// By Blair Mitchelmore
	// http://jquery.offput.ca/highlightFade/

	// Parse strings looking for color tuples [255,255,255]
	function getRGB(color) {
		var result;

		// Check if we're already dealing with an array of colors
		if ( color && color.constructor == Array && color.length == 3 )
			return color;

		// Look for rgb(num,num,num)
		if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
			return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];

		// Look for rgb(num%,num%,num%)
		if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
			return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];

		// Look for #a0b1c2
		if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
			return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];

		// Look for #fff
		if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
			return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];

		// Otherwise, we're most likely dealing with a named color
		return colors[jQuery.trim(color).toLowerCase()];
	}
	
	function getColor(elem, attr) {
		var color;

		do {
			color = jQuery.curCSS(elem, attr);

			// Keep going until we find an element that has color, or we hit the body
			if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
				break; 

			attr = "backgroundColor";
		} while ( elem = elem.parentNode );

		return getRGB(color);
	};
	
	// Some named colors to work with
	// From Interface by Stefan Petre
	// http://interface.eyecon.ro/

	var colors = {
		aqua:[0,255,255],
		azure:[240,255,255],
		beige:[245,245,220],
		black:[0,0,0],
		blue:[0,0,255],
		brown:[165,42,42],
		cyan:[0,255,255],
		darkblue:[0,0,139],
		darkcyan:[0,139,139],
		darkgrey:[169,169,169],
		darkgreen:[0,100,0],
		darkkhaki:[189,183,107],
		darkmagenta:[139,0,139],
		darkolivegreen:[85,107,47],
		darkorange:[255,140,0],
		darkorchid:[153,50,204],
		darkred:[139,0,0],
		darksalmon:[233,150,122],
		darkviolet:[148,0,211],
		fuchsia:[255,0,255],
		gold:[255,215,0],
		green:[0,128,0],
		indigo:[75,0,130],
		khaki:[240,230,140],
		lightblue:[173,216,230],
		lightcyan:[224,255,255],
		lightgreen:[144,238,144],
		lightgrey:[211,211,211],
		lightpink:[255,182,193],
		lightyellow:[255,255,224],
		lime:[0,255,0],
		magenta:[255,0,255],
		maroon:[128,0,0],
		navy:[0,0,128],
		olive:[128,128,0],
		orange:[255,165,0],
		pink:[255,192,203],
		purple:[128,0,128],
		violet:[128,0,128],
		red:[255,0,0],
		silver:[192,192,192],
		white:[255,255,255],
		yellow:[255,255,0]
	};
	
})(jQuery);

/* isChildOf
	http://blog.pengoworks.com/index.cfm/2008/9/24/Using-jQuery-to-determine-if-an-element-is-a-child-of-another-element
*/

jQuery.fn.isChildOf = function(b) {
	return (this.parents(b).length > 0);
};

// suckerfish

jQuery.fn.sfHover = function() {
  jQuery(this).hover(
    function() { jQuery(this).addClass("sfHover"); },
    function() { jQuery(this).removeClass("sfHover"); }
  )

  return this

}

jQuery.fn.sfFocus = function() {
  jQuery(this).each(function(i) {
    jQuery(this).bind("focus", function() { jQuery(this).addClass('sfFocus');});
    jQuery(this).bind("blur", function() { jQuery(this).removeClass('sfFocus'); });
  });
  return this;
}

jQuery.fn.sfActive = function() {
    jQuery(this).each(function(i) {
      jQuery(this).mousedown (
        function() { jQuery(this).addClass('sfActive');}
      )
      jQuery(this).mouseup (
        function() { $(this).removeClass('sfActive');  }
      )
    });
    return this;
}

jQuery.fn.sfTarget = function() {
    jQuery(this).each(function(i) {
      jQuery(this).click(
        function() {
          jQuery(".sfTarget").removeClass('sfTarget');
          elem = jQuery(this).attr("href");
          if(elem) {
            jQuery(elem).addClass('sfTarget');
          }
          return this
        }
      )
    });
    return this;
}


/* 
  Copyright (c) 2005 James Baicoianu

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

/* 
  Simple AJAX library - this works by sending requests to the server, which
  returns results as XML-encapsulated XHTML, which is then placed in the 
  target div automatically.

  Typical response:

  <responses>
   <response target="id-of-status-div">
    <![CDATA[
     <h1>Data updated successfully</h1>
    ]]>
   </response>
   <response target="id-of-data-div">
    <![CDATA[
     (xhtml representation of updated data)
    ]]>
   </response>
   <response type="javascript">
    <![CDATA[
     JavascriptCode();
    ]]>
  </responses>

  Any number of <response></response> blocks can be returned in response to
  a single request, thus giving the backend direct control over every
  named element on the webpage.

  Supports full command queueing - multiple calls to Queue() can be made, followed
  by a single call to Go() to retrieve them all at once (currently only using a
  single XMLHttpRequest object - if needed, could be extended to thread multiple
  XMLHttpRequest objects for parallelized data retrieval
*/

ajaxlib = new function () {
	this.Queue = function (obj) {
    if (obj.constructor.toString().indexOf("Array") != -1) {
      for (var i = 0; i < obj.length; i++) {
        if (!obj[i].method) obj[i].method = "GET";
        this.urlqueue.push(obj[i]);
      }
    } else {
      if (!obj.method) obj.method = "GET";
      this.urlqueue.push(obj);
    }

    if (this.xmlhttpReady())
      this.Go();
  }
  this.Get = function (url, params, args) {
    // FIXME - handle generating url using params array
    var req = this.parseURL(url);
    this.ProcessRequest(req, args);
  }
  this.Post = function (form, params, args) {
    // FIXME - handle merging params array into form request
    var req = this.parseForm(form);
    this.ProcessRequest(req, args);
  }
  this.ProcessRequest = function (req, args) {
    if (typeof args != 'undefined') {
      req.history = args.history || false;

      if (args.callback) 
        req.callback = args.callback;
      if (args.failurecallback) 
        req.failurecallback = args.failurecallback;
      if (args.timeout) 
        req.timeout = args.timeout;
      if (args.timeoutcallback) 
        req.timeoutcallback = args.timeoutcallback;
    }
    this.Queue(req);
  }

  this.Go = function() {
    if (this.urlqueue.length > 0) {
      obj = this.urlqueue.shift();
      //this._get(url);
      if (!this._go(obj))
        this.urlqueue.unshift(obj);
    }
  }
  
  this.parseURL = function(turl) {
    var ret = new Object();
    ret.method = "GET";

    var url = new String(turl); // JavaScript passes a reference to the A HREF, not an actual string 

    if (url.indexOf("?") > 0) {
      ret.url = url.substr(0, url.indexOf("?"));
      ret.args = url.substr(url.indexOf("?") + 1);
    } else {
      ret.url = url;
      ret.args = "";
    }
    return ret;
  }

  this.parseForm = function(form) {
    var ret = new Object();
    ret.method = (form.getAttribute("method") ? form.getAttribute("method").toUpperCase() : "GET");
    ret.url = form.getAttribute("action");

    ret.args = "";
    for (var i = 0; i < form.elements.length; i++) {
      element = form.elements[i];
      var name = new String(element.name); // for some reason, element.name isn't a String by default
      
      if (name.length > 0 && name != "undefined" && element.value != "undefined" && !element.disabled) {
        if (element.type == "checkbox") {
          ret.args += "&" + escape(name) + "=" + (element.checked ? (element.getAttribute("value") ? escape(element.value) : 1) : 0);
        } else if (element.type == "radio") {
          if (element.checked) {
            ret.args += "&" + escape(name) + "=" + escape(element.value);
          }
        } else {
          ret.args += "&" + escape(name) + "=" + escape(element.value).replace(/\+/g, "%2B");
        }
      }
    }

    return ret;
  }

  this.xmlhttpReady = function() {
    if (this.xmlhttp.readyState > 0 && this.xmlhttp.readyState < 4) {
      return false;
    }
		
    return true;
  }

  this.blah = function(responses) {
    var common = {
			inlinescripts: [],
			data: {},
			dependencies: {}
		};
		
    for (var i = 0; i < responses.length; i++) {
      if (typeof this.responsehandlers[responses[i]['type']] == 'function')
        this.responsehandlers[responses[i]['type']](responses[i], common);
      else
        console.log('No handler for type ' + responses[i]['type']);
    }
		
    var cssparms = '', javascriptparms = '';
    for (var key in common.dependencies.css) {
      if (common.dependencies.css.hasOwnProperty(key)) {
        if (common.dependencies.css[key].length > 0)
          cssparms += key + '=' + common.dependencies.css[key].join('+') + '&';
      }
    }
		
    for (var key in common.dependencies.javascript) {
      if (common.dependencies.javascript.hasOwnProperty(key)) {
        if (common.dependencies.javascript[key].length > 0) 
          javascriptparms += key + '=' + common.dependencies.javascript[key].join('+') + '&';
      }
    }
    
    var batch = new thefind.func.dependencies_batch();
    if (cssparms.length > 0)
      batch.add('/css/main?'+cssparms.substr(0,cssparms.length-1),'css');
    if (javascriptparms.length > 0)
      batch.add('/scripts/main?'+javascriptparms.substr(0,javascriptparms.length-1),null,true);
		
    // If caller passed in a callback, execute it
    if (obj && obj.callback) {
      try {
        ajaxlib.executeCallback(obj.callback, common.data);
      } catch(e) {
        batch.callback(function() { ajaxlib.executeCallback(obj.callback, common.data); });
      }
    }
  }

  this.responsehandlers = {
    'xhtml': function(response, common) {
      //console.log('process xhtml', response);
      if (response['target'] && response['_content']) {
        var targetel = document.getElementById(response['target']);
        if (targetel) {
          if (response['append'] == 1 || response['append'] == 'true')
            targetel.innerHTML += response['_content'];
          else {
            thefind.func.ie6_purge(targetel);
						targetel.innerHTML = response['_content'];
          }// FIXME - parse/eval inline scripts
        }
      }
    },
    'javascript': function(response, common) {
      //console.log('process javascript', response);
      if (response['_content'])
        common.inlinescripts.push(response['_content']);
    },
    'data': function(response, common) {
      //console.log('process data', response);
      if (response['name'] && response['_content']) {
        common.data[response['name']] = thefind.JSON.parse(response['_content']);
      }
    },
    'dependency': function(response, common) {
      //console.log('process dependency', response);
      if (response['deptype'] == 'component' && response['name']) {
        var name = response['name'].split('.', 2);
        if (name[0] && response['subtypes']) {
          var subtypes = response['subtypes'].split(',');
          for (var i = 0; i < subtypes.length; i++) {
            if (!common.dependencies[subtypes[i]])
              common.dependencies[subtypes[i]] = [];
            if (!common.dependencies[subtypes[i]][name[0]])
              common.dependencies[subtypes[i]][name[0]] = [];
            common.dependencies[subtypes[i]][name[0]].push(name[1]);
          }
        }
      }
    },
    'debug': function(response, common) {
      //console.log('process debug', response);
      if (response['_content']) {
        var debugcontainer = document.getElementById('tf_debug_tab_logger');
        if (debugcontainer) {
          thefind.func.ie6_purge(debugcontainer);
					debugcontainer.innerHTML += response['_content'];
        }
				
				if (typeof tf_debugconsole != 'undefined')
          tf_debugconsole.scrollToBottom();
      }
    }
  }

  this.processResponse = function(dom, docroot, obj, ignore) {
		if (
			(typeof thefind != 'undefined' && typeof thefind.ajax_back_button != 'undefined') && 
			(typeof search != 'undefined' && search.urlhash) && 
			(typeof obj != 'undefined' && obj.url == '') && 
			(!ignore)
		) {
			thefind.ajax_back_button.add(dom, docroot, obj);
		}
		
    if (!dom) 
			return;
    
    var	batch = new thefind.func.dependencies_batch(),
				inlinescripts = [],
				components = {}, 
				data = {}, 
				css = {}, 
				js = {};
		
    for (var i = 0; i < dom.childNodes.length; i++) {
      var res = dom.childNodes.item(i);
			
      if (res.nodeType == 1) { // Right now we only understand ELEMENT_NODE types
        var	typeattr = res.attributes.getNamedItem("type"),
						type = "xhtml"; // default the type to standard XHTML
				
        if (typeattr)
          type = typeattr.nodeValue;
        
        if (type == "xhtml") {
          var targetattr = res.attributes.getNamedItem("target");
          
					if (targetattr) {
            var	target = targetattr.nodeValue,
								append = res.attributes.getNamedItem("append"),
								content = res.firstChild.nodeValue,
								element = docroot.getElementById(target);
						
            if (element) {
              if (append && (append.nodeValue == 1 || append.nodeValue == "true")) 
                element.innerHTML += content;
              else {
                thefind.func.ie6_purge(element);
								element.innerHTML = content;
              }
              var scripts = element.getElementsByTagName("SCRIPT");
              
							if (scripts.length > 0) {
                for (var j = 0; j < scripts.length; j++) {
                  if (typeof scripts[j].text == 'string') {
                    var text = scripts[j].text;
                    
                    inlinescripts.push(text);
                  } else if (scripts[j].src) {
                  }
                }
              }
            }
          }
        } else if (type == "javascript") {
          var content = res.firstChild.nodeValue;
					
          inlinescripts.push(content);
        } else if (type == "data") {
          var	nameattr = res.attributes.getNamedItem("name"),
							content = res.firstChild;
          
					if (nameattr && content) {
						if (nameattr.nodeValue == 'infobox.content') {
							var	text = thefind.JSON.parse(content.nodeValue),
									div = document.createElement('div');
							
							thefind.func.ie6_purge(div);
							div.innerHTML = text;
							
							$TF("script",div).each(function(k,v) {
								inlinescripts.push(v.innerHTML);
							});
							
							if (arrayGet(thefind.infobox.current.args,'reposition'))
								inlinescripts.push("thefind.infobox.position(thefind.infobox.current,true);");
						}
						
            data[nameattr.nodeValue] = thefind.JSON.parse(content.nodeValue);
          }
        } else if (type == "debug") {
          var	content = res.firstChild.nodeValue,
							debugcontainer = document.getElementById('tf_debug_tab_logger');
					
          if (debugcontainer)
            debugcontainer.innerHTML += content;
          
					if (typeof tf_debugconsole != 'undefined')
            tf_debugconsole.scrollToBottom();
        } else if (type == "dependency") {
          var deptype = thefind.utils.isNull(res.attributes) 
						? '' 
						: res.attributes.getNamedItem("deptype").nodeValue;
          
          switch (deptype) {
            case 'javascript':
              var  url = thefind.utils.isNull(res.attributes) ? '' : res.attributes.getNamedItem("url").nodeValue;
							
              batch.add(url + '&async=2');
              
							break;
            
						case 'component':
              var  name = thefind.utils.isNull(res.attributes) 
                ? '' 
                : res.attributes.getNamedItem("name").nodeValue.split('.');
							
              var subtypes = thefind.utils.isNull(res.attributes) 
								? false 
								: res.attributes.getNamedItem("subtypes").nodeValue;
              
							if (name[0] && subtypes) {
                if (typeof name[1] == 'undefined') 
									name[1] = name[0];
                
								subtypes = subtypes.split(',');
                
								for (var typenum = 0; typenum < subtypes.length; typenum++) {
                  if (!components[subtypes[typenum]])
                    components[subtypes[typenum]] = [];
                  
									if (!components[subtypes[typenum]][name[0]])
                    components[subtypes[typenum]][name[0]] = [];
                  
									components[subtypes[typenum]][name[0]].push(name[1]);
                }
              }
              
							break;
            
						case 'placemark':
              break;
            
						case 'css':
              break;
          }
        }
      }
    }
		
    var	parms = '', key,
				cssparms = '', javascriptparms = '',
				delim = '?';
    
		for (var key in components.css) {
      if (components.css.hasOwnProperty(key)) {
        if (components.css[key].length > 0)
          cssparms += delim + key + '=' + components.css[key].join('+');
        
				delim = '&';
      }
    }
    
		delim = '?';
    
		for (var key in components.javascript) {
      if (components.javascript.hasOwnProperty(key)) {
        if (components.javascript[key].length > 0) 
          javascriptparms += delim + key + '=' + components.javascript[key].join('+');
        
				delim = '&';
      }
    }
    
    if (cssparms.length > 0)
      batch.add('/css/main'+cssparms,'css');
    
		if (javascriptparms.length > 0)
      batch.add('/scripts/main'+javascriptparms,null,true);
		
		var execute_scripts = function() {
			if (inlinescripts.length > 0) {
				var	script_text = '';
				
				for (var i = 0; i < inlinescripts.length; i++) 
					if (!inlinescripts[i] || typeof inlinescripts[i] == 'undefined') 
						continue;
					else
						script_text += inlinescripts[i] + '\n';
				
				try {
					eval(script_text);
				} catch(e) {
					batch.callback(script_text);
				}
			}
		}
		
		if (nameattr && nameattr.nodeValue == 'infobox.content')
			setTimeout(execute_scripts,1);  // infobox needs to do something before scripts can execute
		else
			execute_scripts();  // no timer makes priceslider happy!  no ugly delay.
		
    // If caller passed in a callback, execute it
    if (obj && obj.callback)
      ajaxlib.executeCallback(obj.callback, data);
  }
	
  this._go = function(obj) {
    var docroot = this.docroot;

    // Need to assign these to local variables so the subfunction can access them
    var xmlhttp = this.xmlhttp;
    var processResponse = this.processResponse;
    var timeouttimer = false;

    if (obj.history) {
      this.setHistory(obj.args);

      if (this.iframe) {
        this.iframe.src = "/ajax-blank.htm?" + obj.args + "#" + obj.url;
        // We'll get back to the processing once the iframe has loaded.  Bail out early here.
        return;
      }
    }
    if (!obj.cache) {
      obj.args = (obj.args && obj.args.length > 0 ? obj.args + "&" : "") + "_ajaxlibreqid=" + (parseInt(new Date().getTime().toString().substring(0, 10)) + parseFloat(Math.random()));
    }


    if (obj.timeout && obj.timeoutcallback) {
      timeouttimer = window.setTimeout(function() { obj.failurecallback = false; xmlhttp.abort(); obj.timeoutcallback(); }, obj.timeout || 5000);
    }

    readystatechange = function() {
      if (xmlhttp.readyState == 4) {
        if (timeouttimer)
          window.clearTimeout(timeouttimer);

        if (xmlhttp.status == 200) {
          if (xmlhttp.responseXML) {
            var dom = xmlhttp.responseXML.firstChild;
            processResponse(dom, docroot, obj);
          } else if (xmlhttp.responseText) {
            if (obj.callback) {
              ajaxlib.executeCallback(obj.callback, xmlhttp.responseText);
            }
          }
        } else {
          if (obj.failurecallback) {
            ajaxlib.executeCallback(obj.failurecallback);
          }
        }
        setTimeout('ajaxlib.Go()', 0);
      }
    }

     //alert('trying '+obj.method+' '+obj.url);
    try {
      if (obj.method == "POST") {
        xmlhttp.open(obj.method, obj.url, true);
        xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xmlhttp.setRequestHeader("X-Ajax", "1");
        xmlhttp.onreadystatechange = readystatechange;
        xmlhttp.send(obj.args);
      } else if (obj.method == "GET") {
        xmlhttp.open(obj.method, obj.url + "?" + obj.args, true);
        xmlhttp.setRequestHeader("X-Ajax", "1");
        xmlhttp.onreadystatechange = readystatechange;
        xmlhttp.send(null);
      } else if (obj.method == "SCRIPT") {
        var url = this.host + obj.url;
        if (obj.args) url += '?' + thefind.utils.encodeURLParams(obj.args);
        thefind.file_utils.get('javascript', url);
      }
    } catch (e) {
      if (obj.failurecallback) {
        ajaxlib.executeCallback(obj.failurecallback, e);
      }
      return false;
    }
    return true;
  }

  this.setHistory = function(hash) {
    // FIXME - history shoult also store page, not just query string
    this.docroot.location.hash = hash;
    this.lasthash = this.docroot.location.hash;
  }

  this.checkHistory = function() {
    if (this.docroot.location.hash != this.lasthash) {
      this.processHash(this.docroot.location.hash);
      this.lasthash = this.docroot.location.hash;
    }
  }

  this.processHash = function(hash) {
    return false;
    url = String(document.location);
    if (hash.length > 0)
      if (url.indexOf("#") > 0)
        this.Get(url.substr(0, url.indexOf("#")) + "?" + hash.substr(1));
      else
        this.Get(url + "?" + hash.substr(1));
    else
      this.Get(url.replace("#", "?"));
  }

  this.setLoader = function(target, img, text) {
    if (!text) text = "";
    if (e = document.getElementById(target)) {
			thefind.func.ie6_purge(e);
      e.innerHTML = '<div style="text-align: center;">' + text + '<img src="' + img + '" alt="Loading..." /></div>';
    }
  }

  this.getHTTPObject = function() {
    if (!this.xmlhttp) {
      var xmlhttp = false;
      
      if (typeof ActiveXObject != 'undefined') {
        try {
          xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) {
          try {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
          } catch (E) {
            xmlhttp = false;
          }
        }
      } 
      
      if (!xmlhttp && typeof XMLHttpRequest != "undefined") {
        try {
          xmlhttp = new XMLHttpRequest();
        } catch (e) {
          xmlhttp = false;
        }
      }
      this.xmlhttp = xmlhttp;
    }
    return this.xmlhttp;
  }
  
  this.getIFRAMEObject = function(iframeID) {
    /*
      dynamic IFRAME code
      original JS by Eric Costello (glish.com) for ADC
      http://developer.apple.com/internet/webcontent/iframe.html
  
      courtesy of http://jszen.blogspot.com/2005/03/dynamic-old-school-iframes.html
    */
    if (!this.iframe) {
      //FIXME this is because james is angry... and because ie6 is reporting an ssl erro because of the iframe
      return;
      var iframe, iframeDocument;
    
      if (document.createElement) {   
        try {
         
          var tempIFrame = document.createElement('iframe');
          tempIFrame.setAttribute('id',iframeID);
          tempIFrame.style.border = '0px';
          tempIFrame.style.width = '0px';
          tempIFrame.style.height = '0px';
          iframe = document.body.appendChild(tempIFrame);
            
          if (document.frames) {
            
            /* IE5 Mac only allows access to the document
            of the IFrame through frames collection */
              
            iframe = document.frames[iframeID];
          }
            
        } catch (ex) {
          
          /* This part is CRAZY! -- scottandrew */
      
          /* IE5 PC does not allow dynamic creation and 
          manipulation of an iframe object. Instead, we'll fake
          it up by creating our own objects. */
          var iframeHTML = '\<iframe id="' + iframeID + '"';
          iframeHTML += ' style="border:0px; width:0px; height:0px;"';
          iframeHTML += '><\/iframe>';
          document.body.innerHTML += iframeHTML;
//
iframe = new Object();
          iframe.document = new Object();
          iframe.document.location = new Object();
          iframe.document.location.iframe = 
            document.getElementById(iframeID);
          iframe.document.location.replace = 
            function(location) {
              this.iframe.src = location;
            }
        }
      }
      this.iframe = document.getElementById(iframeID);
    }
    return this.iframe;
  }

  this.executeCallback = function() {
    var args = [];
    for (var i = 0; i < arguments.length; i++)
      args[i] = arguments[i];
		
    var callback = args.shift();
		
    if (callback) {
      if (callback.constructor.toString().indexOf("Array") != -1 && callback.length == 2) {
        // If array is passed, use first element as thisObject, and second element as function reference
				callback[1].apply(callback[0], args);
      } else {
        callback.apply(this, args);
      }
    }
  }

  // AJAX object initialization
  this.getHTTPObject(); 
  if (thefind.browser.type == "msie") {
    this.getIFRAMEObject("hiddeniframe");
  }

  this.lasthash = "";
  this.urlqueue = new Array();
  this.docroot = document;
  this.host = document.location.protocol + '//' + document.location.host;
}

// AJAX child for use within an IFRAME 
function ajaxChild(url) {
  var qstr = url.substr(url.indexOf("?")+1, (url.indexOf("#") - url.indexOf("?") - 1));
  var file = url.substr(url.indexOf("#")+1);

  if (file.length > 0 && qstr.length > 0) {
    if (parent.ajaxlib) { // Workaround for when iframe finishes loading before parent does
      parent.ajaxlib.Get(file + "?" + qstr);
    } else {
      setTimeout('parent.ajaxlib.Get("' + file + '?' + qstr + '")', 100);
    }
  }
}

// Convenience functions to use within webpages

function ajaxLink(ajaxlib, link, history) {
  ajaxlib.Get(link, history);
  return false;
}

function ajaxForm(ajaxlib, form, history) {
  ajaxlib.Post(form, history);
  return false;
}
thefind.add('infobox', function(options) {
	this.options = options;
	this.infoboxes = [];
	this.infomap = {};
	
	this.add = function(name, args, data, content, parent, nuke_old_infobox) {
		if (!nuke_old_infobox && (infobox = this.infoboxes[this.infomap[name]])) {
			if (infobox.args.event) 
				thefind.func.unbind(infobox.parent, infobox.args.event, this);
			
			if (infobox.args.event == "mouseover") 
				thefind.func.unbind(infobox.parent, "mouseout", this);
			
			var update = true;
		} else {
			infobox = {};
		}
		
		infobox.parent 		= document.getElementById(parent) || parent || infobox.parent || false;
		infobox.childWidth= (infobox.parent && infobox.parent.firstChild) ? infobox.parent.firstChild.offsetWidth : 0;
		infobox.data 			= data 		|| infobox.data;
		infobox.name 			= name 		|| infobox.name 		|| "tf_infobox";
		infobox.content		= content	|| infobox.content	|| "";
		infobox.args 			= args 		|| infobox.args 		|| {};
		
		infobox.args.event 		= args.event 				|| false;
		infobox.args.titlebar	= args.titlebar			|| infobox.args.titlebar	|| false;
		infobox.args.vertical	= !!args.vertical		|| infobox.args.vertical	|| false;
		infobox.args.nocache	= !!args.nocache		|| infobox.args.nocache		|| false;
		infobox.args.sticky		= !!args.sticky 		|| infobox.args.sticky 		|| false;
		infobox.args.absolute	= !!args.absolute 	|| infobox.args.absolute	|| false;
		infobox.args.fixed		= args.fixed 				|| infobox.args.fixed			|| false;
		infobox.args.width		= args.width 				|| infobox.args.width			|| false;
		infobox.args.minheight= args.minheight		|| infobox.args.minheight	|| false;
		infobox.args.height		= args.height 			|| infobox.args.height		|| false;
		infobox.args.loading	= args.loading 			|| infobox.args.loading  	|| false;
		infobox.args.bgcolor	= args.bgcolor 			|| infobox.args.bgcolor  	|| false;
		infobox.args.font			= args.font 				|| infobox.args.font    	|| false;
		infobox.args.activecss= args.activecss 		|| infobox.args.activecss	|| false;
		infobox.args.classname= args.classname		|| infobox.args.classname	|| false;
		infobox.args.center		= args.center				|| infobox.args.center		|| false;
		infobox.args.resize		= args.resize				|| infobox.args.resize		|| false;
		infobox.args.zindex		= args.zindex		 		|| infobox.args.zindex		|| 1001;
		infobox.args.delay		= args.delay		 		|| infobox.args.delay			|| 250;
		infobox.args.margin		= args.margin		 		|| infobox.args.margin		|| 0;
		infobox.args.tailcss	= args.tailcss 			|| infobox.args.tailcss		|| 'tf_infobox_tail';
		infobox.args.tailsrc	= args.tailsrc 			|| infobox.args.tailsrc		|| infobox.args.tailcss;
		infobox.args.label		= args.label 				|| infobox.args.label  		|| "";
		infobox.args.id				= args.id			 			|| infobox.args.id  			|| 'tf_infobox_' + infobox.name;
		infobox.args.border		= args.border 			|| infobox.args.border  	|| "page.tfinfobox";
		infobox.args.animation= args.animation 	  || infobox.args.animation	|| "";
		infobox.args.hideonclick   = args.hideonclick   || false;
		infobox.args.killscroll    = args.killscroll    || false;
    infobox.args.ajaxmethod    = args.ajaxmethod    || "GET";		
		infobox.args.fullscreen    = args.fullscreen    || infobox.args.fullscreen     || false;
		infobox.args.resizeclose   = args.resizeclose   || infobox.args.resizeclose	  || false;
		infobox.args.show_callback = args.show_callback || infobox.args.show_callback  || false;
		infobox.args.hide_callback = args.hide_callback || infobox.args.hide_callback  || false;
		infobox.args.margin        = args.margin        || infobox.args.margin		      || 0;
		infobox.args.reposition    = args.reposition   === false ? false : true;
		infobox.args.tail          = args.tail         === false ? false : true;
		infobox.args.scrollTop     = args.scrollTop    === false ? false : true;
		infobox.args.lightbox      = args.lightbox     === true  ? 'tf_infobox_lightbox' : (args.lightbox)	? args.lightbox	: false;
		
		if (!update) {
			infobox.elements = {};
			infobox.elements.container = document.createElement('DIV');
			infobox.elements.container.id = infobox.args.id;
			
			if (infobox.args.classname)
				infobox.elements.container.className = infobox.args.classname;
			
			infobox.elements.container.style.position = "absolute";
			infobox.elements.container.style.zIndex = infobox.args.zindex;
			
			if (infobox.args.font)
				infobox.elements.container.style.fontFamily = infobox.args.font;
				
			if (infobox.args.tail) {
				infobox.elements.tail = document.createElement(infobox.args.tailsrc == 'div' ? 'DIV' : 'IMG');
				infobox.elements.tail.className = infobox.args.tailcss;
				infobox.elements.tail.style.zIndex = infobox.args.zindex;
				
				if (infobox.args.tailsrc != 'div') infobox.elements.tail.src = '/images/misc/nothing.gif';
				
				if (infobox.args.bgcolor)
					infobox.elements.tail.style.backgroundColor = infobox.args.bgcolor;
			}
			
			this.infomap[infobox.name] = this.infoboxes.length;
			this.infoboxes.push(infobox);
		}
		
		if (thefind.utils.isTrue(infobox.args.titlebar))
			infobox.args.titlebar = "page.tfinfobox.closebutton";
		
		var eventobj = (infobox.args.event == "mouseout") 
			? infobox.alternate = infobox.elements.container 
			: (infobox.parent)
				? infobox.parent
				: document.body;
		
		if (infobox.args.event) 
			thefind.func.bind(eventobj, infobox.args.event, this);
		
		if (infobox.args.event == "mouseover") 
			thefind.func.bind((infobox.parent || eventobj), "mouseout", this);
		
		if (infobox.args.killscroll) 
			thefind.func.bind(eventobj, "scroll", this);
		
    if (infobox.args.resizeclose || infobox.args.resize)
			thefind.func.bind(window, "resize", this);
    
		return infobox;
	}
	
	this.handleEvent = function(event) {
		event = event || window.event;
		target = event.target || event.srcElement;
		
    //console.log(event.type, event.target);
		switch (event.type) {
			case "resize":   this.resize(target,event); break;
			case "click":    this.toggle(target,event); break;
			case "mouseover":this.toggle(target,event); break;
			case "mouseout": this.toggle(target,event); break;
      case "scroll":   event.preventDefault(); break;
		}
		
		return false;
	}
	
	this.resize = function(target, event) {
		if (this.current) {
			if (this.current.args.resizeclose) 
				this.hide();
			else if (this.current.args.resize)
				this.position(this.current);
		}
	}
	
	this.show = function(infobox, content, parent, ignore_current, tail_anchor) {
		if (thefind.timing) thefind.timing.log(true);
		infobox = this.infoboxes[this.infomap[infobox]] || infobox;
    if (typeof search != 'undefined' && search.SearchParams && search.SearchParams.view)
  		infobox.viewmode = search.SearchParms.view;
		
		if (content)
			infobox.elements.content = content;
		
		if (parent) 
			infobox.parent = parent;
		
    if (!thefind.tplmgr || !infobox) 
			return;
		
		if (tail_anchor)
			infobox.elements.tail_anchor = tail_anchor;
		
		if (infobox.args.sticky) 
			this.sticky = true;
		
		if (!ignore_current) 
			this.current = infobox;
		
		if (!infobox.elements.content || infobox.args.nocache) {
			infobox.elements.content = (infobox.args.titlebar) 
				? this.template(thefind.tplmgr,infobox.args.titlebar,{ name: infobox.name, label: infobox.args.label }) 
				: '';
			
			if (infobox.args.ajax) {
				this.ajax(infobox.content,infobox.data,infobox);
				var oldcontent = infobox.elements.content;
				infobox.elements.content += (infobox.args.loading) 
					? this.template(thefind.tplmgr,infobox.args.loading) 
					: '<p id="tf_ajax_spinner" align="center">'
						+ '<img src="/images/misc/ajax-loader-transparent.gif">'
						+ '</p>';
				
			} else { 
				this.cont(this.template(thefind.tplmgr,infobox.content,infobox.data),infobox);
			}
		}
		
		if (infobox.args.border == 'div') {
			infobox.elements.border = infobox.elements.content;
		} else {
			infobox.elements.border = this.template(thefind.tplmgr,infobox.args.border,infobox.elements);
		}
		
		if (infobox.args.lightbox) {
			if (!infobox.lightbox)
				infobox.lightbox = document.getElementById('#tf_lightbox_shade') || document.createElement('div');
			
			if (infobox.lightbox.id != 'tf_lightbox_shade') {
				infobox.lightbox.id = 'tf_lightbox_shade';
				document.body.appendChild(infobox.lightbox);
			}
			
			thefind.utils.elementAddClass(infobox.lightbox,infobox.args.lightbox);
			
			if (typeof $TF == 'function') 
				$TF(infobox.lightbox).bgiframe();
		}
		
		if (infobox.args.lightbox || infobox.args.hideonclick) {
			(function(self) {
				thefind.func.bind(document.documentElement, 'mousedown', function(event) { 
					if (!self.is_inside(infobox, event.target || event.srcElement)) {
						thefind.infobox.hide(infobox.name); 
					}
				});
			})(this);
		}
		
		infobox.elements.container.style.visibility = 'hidden';
		
    if (infobox.args.absolute) 
      document.body.appendChild(infobox.elements.container);
		else 
      infobox.parent.insertBefore(infobox.elements.container,infobox.parent.firstChild);
		
		thefind.func.ie6_purge(infobox.elements.container);
    infobox.elements.container.innerHTML = infobox.elements.border;
		
    this.execute_scripts(infobox.elements.container);
		
		if (infobox.args.show_callback)
			infobox.args.show_callback();
		
		if (oldcontent) 
			infobox.elements.content = oldcontent;
		
		if (infobox.args.activecss)
			thefind.utils.addClass(infobox.parent,infobox.args.activecss);
		
		//$TF(infobox.parent).addClass(infobox.args.activecss);
		if (typeof $TF != 'undefined')
      $TF(infobox.elements.container).bgiframe();
		
		this.position(infobox);
		infobox.elements.container.style.visibility = 'visible';
		infobox.visible = true;
	}
	
	this.cont = function(data,infobox) {
		if (typeof data["infobox.content"] != 'undefined')
      data = data["infobox.content"];
    
    if (typeof data == 'string') {
  		infobox.elements.content += data;
			
			if (infobox.args.border == 'div') {
				infobox.elements.border = infobox.elements.content;
			} else {
				infobox.elements.border = this.template(thefind.tplmgr,infobox.args.border,infobox.elements);
	  	}
			
			thefind.func.ie6_purge(infobox.elements.container);
		  infobox.elements.container.innerHTML = infobox.elements.border;
			
  		var	spinner = document.getElementById('tf_ajax_spinner');
	  	if (spinner) {
				thefind.func.ie6_purge(spinner);
 		  	spinner.parentNode.removeChild(spinner);
			}
			
			
      //this.execute_scripts(infobox.elements.container);
			
      if (typeof $TF != 'undefined')
  			$TF(infobox.elements.container).bgiframe();  // IE6 combobox see-thru fix
			
			if (infobox.args.reposition)
        (function(self) { 
					// FIXME - timeout is used to work around the CSS loading delay
	  			setTimeout(function() { self.position(infobox,true); }, 100);
        })(this);
    }
		
		if (infobox.args.reposition)
			this.position(infobox);
	}
	
	this.ajax = function(url, data, infobox) {
		(function(self) {
			ajaxlib.Queue({ 
				method: infobox.args.ajaxmethod,
				url: url, 
				args: thefind.utils.encodeURLParams(data), 
				callback: function(html) {
					self.cont(html,infobox);
				}
			});
		})(this);
	}
	
	this.template = function(tplmgr, name, vars) {
		vars = vars || {};
    var template;
		
		if (tplmgr.HasTemplate(name)) 
			template = tplmgr.GetTemplate(name, vars);
		
		return template || '';
	}
	
	this.nuke = function(infobox) {
		if (this.current == this.infoboxes[this.infomap[infobox]])
			delete this.current;
		
		delete this.infoboxes[this.infomap[infobox]];
		delete this.infomap[infobox];
	}

	this.hide = function(infobox) {
		infobox = !infobox ? this.current : (this.infoboxes[this.infomap[infobox]] || null);
    
    if (!infobox && this.current)
      infobox = this.current;
    else if (!infobox)
      return;
    
    try {
      if (infobox.args.absolute) {
				thefind.func.ie6_purge(infobox.elements.container);
        document.body.removeChild(infobox.elements.container);
      } else {
				thefind.func.ie6_purge(infobox.elements.container);
        infobox.parent.removeChild(infobox.elements.container);
			}
		} catch (e) { }
		
    delete this.current;
    
    if (infobox) {
      if (infobox.animation)
        infobox.animation = false;
      
      if (infobox.args.fullscreen)
        document.body.style.overflow = '';
      
  		if (infobox.args.sticky) this.sticky = false;
      
  		if (infobox.viewmode && search && search.SearchParms.view != infobox.viewmode)
	  		search.SearchParms.view = infobox.viewmode;
      
  		if (infobox.args.activecss)
	  		thefind.utils.elementRemoveClass(infobox.parent,infobox.args.activecss);
      
      if (infobox.args.lightbox && infobox.lightbox) {
        thefind.utils.elementRemoveClass(infobox.lightbox,infobox.args.lightbox);
				(function(self) {
					thefind.func.unbind(document.documentElement, 'mousedown', function(event) { 
						if (self.current && !self.is_inside(self.current, event.target || event.srcElement)) 
							thefind.infobox.hide(); 
					});
				})(this);
			}
      
			if (infobox.args.hide_callback)
				infobox.args.hide_callback();
    }
		
		infobox.visible = false;
	}
	
	this.position = function(ib, it) {
		var ib = this.infoboxes[this.infomap[ib]] || ib,
        c = ib.elements.container;
		
    if (ib.args.width) c.style.width = ib.args.width;
		//if (ib.args.height) c.style.height = ib.args.height;
    
		var	p   = ib.parent,
        ie  = thefind.browser.type == 'msie',
        ie7 = ie && thefind.browser.version <= 7,
        d   = thefind.func.dimensions,
				dw  = d(window),
				dp  = d(p),
				dc  = d(c),
				to  = 0,
				left, top;
		
		if (thefind.utils.isNull(ib.paddingTop) || thefind.utils.isNull(ib.paddingLeft)) {
			ib.paddingTop	= (c.offsetTop	- p.offsetTop)		|| 0; 
			ib.paddingLeft	= (c.offsetLeft	- p.offsetLeft)	|| 0;
		}
		
		if (ib.args.fullscreen) {
			var st = thefind.browser.type != 'safari' ? thefind.func.get_scroll(1) : 0,
      top = st;
      left = ib.animation ? 0 : dw.w;
      
    } else if (ib.args.center) {
			top = (dw.h >> 1) - (dc.h >> 1) + thefind.func.get_scroll(1);
			left = (dw.w >> 1) - (dc.w >> 1);
		} else if (ib.args.vertical) { // popup is vertical
			if (ib.args.absolute) {
				// popup appended to document
				
			} else {
				// popup appended to parent - should work for up or down vertical menus
				top = ((dp.y + (dp.h >> 1)) > (dw.h >> 1)) 
					? -(dc.h + ib.paddingTop) - ib.args.margin 
					: (dp.h - ib.paddingTop) - ib.args.margin;
				
				left = -((dc.w - dp.w) >> 1);
				
				// behind left screen edge
				if ((dp.x + left) < 0)
					left = left - (to = (dp.x + left) - 0);
				
				// beyond right screen edge
				if (((dp.x + left + 20) + dc.w) > dw.w)
					left = -((dp.x + dc.w) - dw.w + (ie ? 14 : 29));
			}
			
			if (ie7 && ib.childWidth) {
				top += 1;
				left -= ib.childWidth;
			}
		} else { // popup is horizontal
			if (ib.args.absolute) {
				var st = thefind.func.get_scroll(1),
            im = parseInt(ib.args.margin),
            ta = ib.elements.tail_anchor;
				
				// popup is appended to document
				left = ((dp.x + (dp.w >> 1)) > (dw.w >> 1)) 
					? dp.x - dc.w - im
					: dp.x + dp.w + im;
				
				top = (dp.y + (dp.h / 2)) - (dc.h / 2);
				
				if (ie7 && ib.args.scrollTop)
					top += st;
				
        // below screen bottom
				if (top + dc.h > dw.h + st)
					top -= (top + dc.h) - (dw.h + st);
				
        // above screen top
				if (top < st)
					top += st - top;
				
				// adjust if fixed position
				if (ib.args.fixed)
          if (fo = document.getElementById(ib.args.fixed))
            if (fo.style.position == "fixed")
              top += st;
        
        // makes sure container does not go below or above tail anchor
				if (ta) {
					var	is = ie7 ? st : 0,
              dt = d(ta),
              hh = dt.h / 1,
              ys = dt.y + is + hh,
              ty = dt.y + (dt.h / 4) + is;
					
					left = (dt.x + (dt.w >> 1) > dw.w >> 1) 
						? dt.x - dc.w - im
						: dt.x + dt.w + im;
					
					if (top > ty) 
						top = ty;
					
					if (top + dc.h < ys)
						top = ys - dc.h;
				}
			} else { // popup is appended to parent
				top = -(dc.h >> 1);
				left = ((dp.x + (dp.w >> 1)) > (dw.w >> 1)) 
					? -dc.w 
					: dp.w;
				
				// below screen bottom - this logic needs fixin'
				//if (((dp.y - top) + dc.h) > dw.h) 
				//	top = -((dp.y + dc.h) - dw.h);
				
				// above screen top
				if ((dp.y + top) < 0)
					top = 0;
			}
		}
		
		if (ib.args.fullscreen) {
      document.body.style.overflow = 'hidden';
			c.style.top = top + 'px';
			c.style.left = left + 'px';
			c.style.height = dw.h + 'px';
			c.style.width = dw.w + 'px';		
      if (!ib.animation) {
        ib.animation = true;
        $TF(c).animate({ left: 0 });
      }
    } else if (ib.args.absolute) {
			c.style.top = top + 'px';
			c.style.left = left + 'px';
		} else {
			c.style.marginTop = top + 'px';
			c.style.marginLeft = left + 'px';
		}
		
		if (ib.args.tailsrc == 'div')
			to = left;
		
		if (ib.args.tail && (!ib.args.center && !ib.args.fullscreen)) 
			this.tail(ib, c, dc, dp, dw, to);
	}
	
	this.set_tail_class = function(img, ts, o) {
		var classes = [ 'left', 'right', 'up', 'down' ];
		
		for (var i=0; i<classes.length; i++)
			if (classes[i] != o)
				thefind.utils.removeClass(img, ts + '_' + classes[i]);
		
		if (!thefind.utils.hasClass(img, ts + '_' + o))
			thefind.utils.addClass(img, ts + '_' + o);
	}
	
	this.tail = function(ib, c, dc, dp, dw, to, it) {
		var img = ib.elements.tail,
        ts  = ib.args.tailsrc,
        tc  = ib.args.tailcss,
				p   = ib.parent,
        d   = thefind.func.dimensions,
				dw  = d(window),
				dp  = d(ib.elements.tail_anchor || p),
				dc  = d(c),
				top, left;
		
		if (ib.args.vertical) {
      var iw  = img.offsetWidth,
          ih  = img.offsetHeight;
			
      if ((dp.y + (dp.h >> 1)) > (dw.h >> 1)) {
				this.set_tail_class(img, tc, 'down');
				top = dc.h - 9;
				left = (dc.w >> 1) - (iw >> 1) - 9 + to;
			} else {
				this.set_tail_class(img, tc, 'up');
				top = -ih + 1;
				left = (dc.w >> 1) - (iw >> 1) - 9 + to;
			}
      
     	if (ts == 'div') {
        img.style.width = dp.w - 2 + 'px';
        left = Math.abs(to + 1);
        top += 7;
      }
		} else {
			if ((dp.x + (dp.w >> 1)) > (dw.w >> 1)) {
				this.set_tail_class(img, tc, 'right');
				top = dp.y - dc.y + (dp.h >> 1) - (16 >> 1);
				left = dc.w - (ib.name != "product_infocard" ? 1 : 11);
			} else {
				this.set_tail_class(img, tc, 'left');
				top = dp.y - dc.y + (dp.h >> 1) - (16 >> 1);
				left = '';
			}
			
			// adjust for position:fixed scrollTop
			if (ib.args.absolute && ib.args.fixed)
        if (fo = document.getElementById(ib.args.fixed))
          if (fo.style.position == "fixed") 
            top += thefind.func.get_scroll(1);
		}
		
		if (!ib.args.absolute && thefind.browser.type == 'msie' && thefind.browser.version <= 7 && ib.childWidth)
			left -= ib.childWidth;
		
		if (!(!ib.args.vertical && it)) {
      img.style.marginTop = (top) ? (top + 'px') : '';
      ib.elements.container.style.minHeight = (top) ? (top + 'px') : '';
    }
    
		if (!(ib.args.vertical && it)) 
			img.style.marginLeft = (left) ? (left + 'px') : '';
		
		ib.elements.container.insertBefore(img, ib.elements.container.firstChild);
	}
	
	this.target = function(target, type) {
		var	original = target,
				infobox, parent, i;
		
		for (i=0; i<this.infoboxes.length; i++) {
			infobox = this.infoboxes[i];	
			parent = infobox.parent;
			target = original;
			
			while (target) {
				if (target == infobox.elements.container && type == 'click')
					return false;
				
				if (parent == target || infobox.alternate == target) 
					return infobox;
				
				target = target.parentNode;
			}
		}
		
		return false;
	}
	
	this.is_inside = function(infobox, element) {
		var	infobox = this.infoboxes[this.infomap[infobox]] || infobox,
				container = infobox.elements.container;
		
		while (element) {
			if (element == container || element == infobox.parent)
				return true;
			
			element = element.parentNode;
		}
		
		return false;
	}
	
  this.execute_scripts = function(element) {
    var scripts = element.getElementsByTagName("SCRIPT");
		
    if (scripts.length > 0) {
      for (var j = 0; j < scripts.length; j++) {
        if (typeof scripts[j].text == 'string') {
          var text = scripts[j].text;
          try { eval(text); }
					catch(e) { }
        } //else if (scripts.src) {        }
      }
    }
  }
	
	this.toggle = function(target, event) {
		var infobox = this.target(target,event.type);
		if (!infobox) 
			return;
		
		if (event.type == 'mouseover' || event.type == 'mouseout') {
			if (this.sticky || (event.type == 'mouseover' && infobox == this.current)) 
				return;
			
			var related = event.relatedTarget || event.toElement;
			
			while (related) {
				if (related == infobox.parent || related == infobox.elements.container) 
					return;
				
				try { 
					related = related.parentNode; 
				} catch(e) { 
					console.log('thefind.infobox.toggle():',e.message,related);
					break;
				}
			}
		}
		
		if (infobox != this.current) {
			if (this.current) 
				this.hide(this.current);
			
			this.show(infobox);
		} else {
			this.hide(this.current);
		}
		
    event.preventDefault();
    event.stopPropagation();
	}
	
	return this;
});

thefind.add('infobox', new thefind.func.infobox());

var objInfoBox;

function hideByClassName(hideClass, show) {
  if (!show) {
    var toHide = thefind.utils.getElementsByClassName(document, "*", hideClass);
    for (var i = 0; i < toHide.length; i++) {
      toHide[i].style.visibility = "hidden";
    }
  } else {
    var toHide = thefind.utils.getElementsByClassName(document, "*", hideClass);
    for (var i = 0; i < toHide.length; i++) {
      toHide[i].style.visibility = "visible";
    }
  }
}

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 = thefind.func.dimensions(window);
  lightboxShade.style.display = "block";
  lightboxContainer.style.display = "block";
	$TF(lightboxShade).bgiframe();
	$TF(lightboxContainer).bgiframe();
  //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";
	$TF(lightbox).bgiframe();
  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";
}
thefind.add('panel', function(options) {
  this.options = options;
  this.panels = [];
  this.panelmap = {};

	this.add = function(name, args, data, content, parent) {
    if (!this.panelmap[name]) {
			this.panelmap[name] = this.panels.length;
			this.panels.push(args || {});
    }
		
		this.Init(name, args);
  }

  this.Init = function(name, args) {
    var panel = this.panels[this.panelmap[name]] || null;
		
    if (args) {
			if (args.id)
				panel.element = $TF("#"+args.id);
			
			panel.items = {};
			if (args.cfg && args.cfg.items) {
				$TF.each(args.cfg.items, function(k, v) {
					panel.items[k] = new thefind.panel.add_item(k, v, panel);
				});
			}
			
			if (panel.cfg.navigation == "true") {
				panel.container = document.getElementById(panel.cfg.targetid);
				this.lis = $TF('div.tf_utils_panel_' + name + ' ul li');;
				this.select_item(0);
				
				for (var item in panel.items) {
					var	element = panel.items[item].element;
					
					if (typeof element == 'object' && element.length > 0) {
						thefind.func.bind(element[0], 'click', this);
						element[0].onselectstart = function() { return(false); };
					}
				}
				
				this.item = this.get_item(panel, $TF('div.tf_utils_panel_' + name + ' ul li.selected')[0]);
			}
			
			panel.content = {};
		}
	}
	
	this.handleEvent = function(event) {
		event = event || window.event;
		target = event.target || event.srcElement;
		
		switch (event.type) {
			case "click": 
				this.click(event, target); 
				break;
		}
	}
	
	this.click = function(event, target) {
		while (target && target.nodeName != 'LI') 
			target = target.parentNode;
		
		if (!target || $TF(target).hasClass('tf_utils_state_disabled')) 
			return;
		
		// find the proper panel for event and item for target
		for (var key in this.panelmap) {
			var	panel	= this.panels[this.panelmap[key]],
					item	= this.get_item(panel, target);
			
			if (item)
				break;
		}
		
		event.preventDefault();
		event.stopPropagation();
		if (item.name == this.item.name)
			return;

    if (typeof pandoraLog=='object') pandoraLog.mouseovertype=item.name;
    if (typeof googleAnalytics=='object') {
      googleAnalytics.mouseovertype=item.name;
      googleAnalytics.trackEvent(['popup', 'tab', googleAnalytics.mouseovertype]);
    }
		this.select_item(target);
		
		// tab fade-in effect
		$TF(panel.container).css({ opacity: 0 }).animate({ opacity: 1 }, 'slow').animate({ opacity: 'auto' }, 0);
		
		// cache content of tab for later retrieval
		if ($TF('img.tf_results_ajax_spinner',panel.container).length == 0) // kludgy - dont save content if content still loading
			panel.content[this.item.name] = panel.container.innerHTML;
		
		this.item = item;
		
		// if cached copy exists use that
		if (panel.content[item.name]) 
			return panel.container.innerHTML = panel.content[item.name];
		
		if (!panel.container.style.minHeight)
			panel.container.style.minHeight = panel.container.offsetHeight + 'px';
		
		panel.container.innerHTML = '<p style="padding: 1em"><img style="margin: 0 auto; display:block;" src="/images/misc/ajax-loader-transparent.gif" title="Loading..."></p>';
		
		// Merge args from both the panel and any specified contentcomponentargs
		var urlargs = {};
		
		if (typeof panel.args == 'object') 
			for (var k in panel.args) 
				if (panel.args.hasOwnProperty(k)) 
					urlargs[k] = panel.args[k];
		
		if (typeof item.args.contentcomponentargs == 'object') 
			for (var k in item.args.contentcomponentargs) 
				if (item.args.contentcomponentargs.hasOwnProperty(k)) 
					urlargs[k] = item.args.contentcomponentargs[k];
		
		urlargs['targetid'] = panel.cfg.targetid;
		
		// ajax-fetch tab content
		ajaxlib.Queue({
			url: item.args.contentcomponent, 
			args: thefind.utils.encodeURLParams(urlargs)
		});
	}
  
	this.select_item = function(num) {
		var	num = num || 0,
				li = typeof num == 'number' ? this.lis[num] : num;
		
		if ($TF(li).hasClass('tf_utils_state_disabled'))
			return;
		
		if (this.li) 
			$TF(this.li).removeClass('selected');
		
		$TF(li).addClass('selected');
		
		return this.li = li;
	}
	
  this.set_args = function(panelname, args) {
		var panel, item;
		
  	if (panel = this.panels[this.panelmap[panelname]]) {
      for (var key in args) 
        arraySet(panel.args, key, args[key]);
			
			for (var item_key in panel.items) {
				item = panel.items[item_key];
				if ((item.args.disableiffalse && !thefind.utils.isTrue(args[item.args.disableiffalse])) || (item.args.disableiftrue && thefind.utils.isTrue(args[item.args.disableiftrue])) || (item.args.disableifempty && thefind.utils.isEmpty(args[item.args.disableifempty]))) {
					$TF(item.element[0]).addClass('tf_utils_state_disabled');
          
          if(item.args.disabledtype)
  					$TF(item.element[0]).addClass('tf_utils_state_disabled_'+item.args.disabledtype);
        }
			}
		}
  }
	
	this.get_item = function(panel, target) {
		for (var key in panel.items) {
			var	item = panel.items[key],
					element = item.element[0];
			
			if (target == element) 
				return item;
		}
		
		return false;
	}
	
  this.add_item = function(name, args, data, content) {
    this.name = name;
    this.args = args || {};
    this.panel = data;
		
    this.init = function() {
      if (!this.panel) 
				return;
			
			this.element = $TF("ul.tf_utils_panel_content li#" + this.panel.id + "_" + this.name);
			
			if (this.args.contentcomponent && this.element.length > 0) {
				var panelname = this.panel.name.replace(/\./g, "_") + "_" + this.name;
				
				thefind.infobox.add(
					panelname, 
					{
						width:		this.args.contentwidth		|| '20em',
						border:		this.args.contentborder	|| "page.tfinfobox",
						titlebar:	this.args.contenttitle		|| true,
						label:		this.args.contentlabel		|| false,
						loading:	this.args.contentloading	|| false,
						lightbox: 'tf_infobox_lightbox',
						border:		'div',
						classname:'tf_myfinds_infobox_popup',
						activecss:'tf_myfinds_infobox_selected',
						bgcolor:	"white",
						event:		"click",
						tailsrc:	"div",
            fullscreen: this.args.fullscreen || false,
            absolute:   this.args.absolute || false,
            animation:  this.args.animation || '',
						vertical:	true,
						nocache:	true,
						resize:   true,
						ajax:			true
					},
					this.args.contentcomponentargs || null,
					"/" + this.args.contentcomponent.replace(/\./, "/"),
					this.element[0]
				);
			}
    }
		
    this.init();
  }
});

thefind.add('panel', new thefind.func.panel());
tr_size 		=	thefind.func.log_size;
TFHtmlUtils	= thefind.utils;
addEvent 		= thefind.func.bind;
removeEvent = thefind.func.unbind;
isTrue 			= thefind.utils.isTrue;
isNull 			= thefind.utils.isNull;
isEmpty 		= thefind.utils.isEmpty;

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

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

function myfindsShowEmailForm(emailContent) {
  showLightBox(null,'35em');

  var target = document.getElementById("myfindsSendEmailToEmail");
  if (target) {
    if (target.value.length > 0) {
      var newtarget = document.getElementById("myfindsSendEmailToEmail");
      if (newtarget) {
        try {
          newtarget.focus();
        } catch(e) { }
      }
    } else { 
      try {
        target.focus();
      } catch(e) { }
    }
  }
  var emailInputBox = document.getElementById("myfindsSendEmailMessage");
  if (emailInputBox && emailContent)
    emailInputBox.value = emailContent;

}
function myfindsHideEmailForm() {
  hideLightBox();
}

function TFHtmlUtilsInterstitial(args) {
  this.Init = function(args) {
    this.interstitialurl = args.interstitialurl;
    this.buyurl = args.buyurl;
    this.obj = args.obj;
    this.callback = args.callback;
    this.delay = args.delay || 1000;
    this.lightboxcontent = args.lightboxcontent;

    if (this.lightboxcontent) {
      showLightBox(null, '13em');
      $TF("#tf_lightbox_content").html(this.lightboxcontent);
    }

    if (this.interstitialurl) {
      this.iframe = document.createElement("IFRAME");
      if (this.iframe) {
        this.iframe.className = "tf_utils_interstitial_loader";
        this.iframe.src = this.interstitialurl;
        $TF(this.iframe).bind("load", this, function(ev) { ev.data.handleCallback(ev); });
				
        document.body.appendChild(this.iframe);
      }
    }
    (function(self) {
			self.delaytimer = setTimeout(function() { 
				self.handleCallback(); 
			}, self.delay);
		})(this);
	}

  this.handleCallback = function(ev) {
    if (this.callback && typeof this.callback == "function") {
      this.callback.apply(this.obj, [ev]);
    } else if (this.buyurl) {
      this.location.href = this.buyurl;
    }

    if (this.delaytimer) {
      clearTimeout(this.delaytimer);
      this.delaytimer = false;
    }
  }
  /*
  this.Init = function(args) {
    this.interstitialurl = args.interstitialurl;
    this.buyurl = args.buyurl;
    if (this.interstitialurl) {
      this.iframe = document.createElement("IFRAME");
      if (this.iframe) {
        this.iframe.className = "tf_utils_interstitial_loader";
        this.iframe.src = this.interstitialurl;
        var self = this;
        document.body.appendChild(this.iframe);
      }
      this.location.href = this.buyurl;
    }
  }
  */
  this.Init(args);
}

function TFHtmlUtilsCoremetrics() {
  this.params = new Array();
  this.extras = new Array();
  this.create = function(tagtype) {
    var ret = "";
    if (typeof(cmDisabled)!="undefined" && cmDisabled=='0' && this.params.length) {
      if (typeof(cmExploreEnabled)!='undefined' && cmExploreEnabled && this.extras.length) {
        this.params.push(this.extras.join("-_-"));
      }
      ret = window['cmCreate'+tagtype+'Tag'].apply(this, this.params);
      if (tagtype=="ShopAction9") ret += cmDisplayShop9s();
    }
    return ret;
  }
}

function TFHtmlUtilsPandoraLog() {
  this.mouseovertype = "";
}

function TFHtmlUtilsGoogleAnalytics(args) {
  this.GAalerts = Number(args.GAalerts);
  this.trackingcode = args.trackingcode;
  this.cobrand = args.cobrand;
  this.query = args.query;
  this.pagegroup = args.pagegroup;
  this.pagetype = args.pagetype;
  this.status = args.status;
  this.total = args.total;
  this.category = args.category;
  this.subcategory = args.subcategory;
  this.city = args.city;
  this.state = args.state;
  this.country = args.country;
  this.pagenum = args.pagenum;
  this.filters = args.filters;
  this.version = args.version;
  this.store_name = args.store_name;
  this.alpha = args.alpha;
  this.clickoutsource = 0;
  this.myfindspanel = '';
  this.mouseovertype = '';
  this.mouseovereventenable = 1;
  this.pageTracker = _gat._getTracker(this.trackingcode);
  this.pageTracker._setCookieTimeout("172800"); // campaign tracking expiration 2 days

  var self = this;
  var ignoredOrganics=['www.thefind.com', 'thefind', 'thefind.com', 'the find', 'glimpse', 'glimpse.com', 'www.glimpse.com', 'local.thefind.com', 'green.thefind.com', 'ww1.glimpse.com', 'shoptrue.com', 'shoptrue', 'coupons.thefind.com', 'shop.glimpse.com', 'ww1.thefind.com', 'www.shoptrue.com', 'reviews.thefind.com', 'visual.thefind.com', 'prices.thefind.com'];
  $TF.each(ignoredOrganics, function() {self.pageTracker._addIgnoredOrganic(this)});
  var domainName = document.domain.match(/(\.(.+)\.com$)/gi)[0]; 
  //console.log(domainName)
  if (this.cobrand=='local' || this.cobrand=='greenshopping' || this.cobrand=='visualbeta' || this.cobrand=='coupons' || this.cobrand=='thefind' || this.cobrand=='thefindww1' || this.cobrand=='reviews' || this.cobrand=='prices') {
    this.pageTracker._setDomainName(domainName); // set to '.thefind.com' or '.dev.thefind.com'
    this.pageTracker._setAllowLinker(true);
    this.pageTracker._setAllowHash(false);
  }else if (this.cobrand=='glimpse' || this.cobrand=='glimpseww1' || this.cobrand=='glimpseshop') {
    this.pageTracker._setDomainName(domainName); //set to '.glimpse.com'
    this.pageTracker._setAllowLinker(true);
    this.pageTracker._setAllowHash(false);
  }else if (this.cobrand=='shoptrue') {
    this.pageTracker._setDomainName(domainName); //set to '.shoptrue.com'
    this.pageTracker._setAllowLinker(true);
    this.pageTracker._setAllowHash(false);
  }
  // attach event handlers to various static links
  $TF("a.tf_search_item_link.tf_search_item_productimage_link").click(function () {if (!self.clickoutsource) self.clickoutsource = 1}); // product image
  $TF("a.tf_search_item_link.tf_seeit strong img").click(function () {if (!self.clickoutsource) self.clickoutsource = 2}); // merchant logo
  $TF("a.tf_search_item_link.tf_seeit").click(function () {if (!self.clickoutsource) self.clickoutsource = 3}); // VisitSite button
  $TF("a.tf_search_item_link.tf_seeit strong").click(function () {if (!self.clickoutsource) self.clickoutsource = 4}); // intervening blankspace
  $TF(".search_anchor_relatedqueries").each(function(n) {$TF(this).click(function() {self.trackEvent(['search', 'related_search', n+1])})});
  $TF(".search_anchor_hotsearches").each(function(n) {$TF(this).click(function() {self.trackEvent(['links', self.pagetype, 'hot_searches', n+1])})});
  $TF(".tf_info_iphonedownload").click(function() {self.trackEvent(['promo', 'bottom', 'iPhoneApp'])});
  $TF(".tf_user_feedback_link").each(function(n) {$TF(this).click(function() {self.trackEvent(['links', self.pagetype, 'user_feedback', n+1])})});
  $TF(".tf_about_results_link").each(function(n) {$TF(this).click(function() {self.trackEvent(['links', self.pagetype, 'about_these_search_results', n+1])})});
  $TF(".link_icon_discover_same_product").each(function(n) {$TF(this).click(function() {self.trackEvent(['discover', 'same_product', self.category])})});
  $TF(".link_icon_discover_similar_product").each(function(n) {$TF(this).click(function() {self.trackEvent(['discover', 'similar_product', self.category])})});
  
	delete self;
	
	if (this.GAalerts) {
    $TF('body').append(
      '<div id="ga_tagbox" style="position:fixed;left:0;top:0;border:1px dotted black;padding:5px;background-color:#eef;text-align:left;display:none"></div>'
    );
    $TF('#ga_tagbox').css('opacity', 0.9).click(function() {$TF(this).css('display', 'none')});
  }

  this.displayTag = function(content) {
    $TF('#ga_tagbox').append(content+'<br \/>').css('display', 'block');
  };

  this.updatePageParameters = function(args) {
    this.pagenum = any(args['filter[pagenum]'], args['page'], "1");
    this.filters = args['brand']?'1':'0';
    this.filters += args['color']?'1':'0';
    this.filters += Number(args['coupons'])?'1':'0';
    this.filters += Number(args['local'])?'1':'0';
    this.filters += Number(args['green'])?'1':'0';
    this.filters += Number(args['marketplaces'])?'1':'0';
    this.filters += (args['filter[price][min]']||args['filter[price][max]']||args['price'])?'1':'0';
    this.filters += Number(args['sale'])?'1':'0';
    this.filters += args['store']?'1':'0';
    this.filters += args['freeshipping']?'1':'0';
  };

  this.trackPageview = function() {
    var status = this.status;
    var total = this.total;
    var pagegroup = this.pagegroup;
    var pagetype = this.pagetype;
    var query = this.query.replace(/&/g, "+");
    var errorPages = {
      'B1':'noresults',
      'B2':'noorganicresults',
      'B3':'noresults',
      'B4':'noresultscurrentmall',
      'B5':'partialresults',
      'S1':'serverexception',
      '404':'error_404' };
    $TF.each(errorPages, function(k,v) {
      if (k==status && (status!='B3' || total=='0')) {
        query = pagetype+"-"+query;
        pagegroup = "error";
        pagetype = v;
      }
    });
    if (this.pagetype=='error_404') this.query = '?page='+document.location.href  + '&from=' + document.referrer;
    //TODO!!: check above format with Srilatha -- does not report properly
    var pageurl = 'virt_'+pagegroup
                + '/'+this.cobrand
                + '/'+pagetype;
    switch (this.pagetype) {
      case 'coupons_index':
        break;
      case 'coupons_browsemap':
        pageurl += '/'+this.alpha;
        break;
      case 'coupons_store':
      case 'store':
        pageurl += '/'+this.category
                + '/'+this.subcategory
                + '/?qry='+this.store_name
                + '&flt='+this.filters
                + '&pgn='+this.pagenum
                + '&ver='+this.version;
        break;
      default:
        pageurl += '/'+this.category
                + '/'+this.subcategory
                + '/?qry='+query
                + '&flt='+this.filters
                + '&pgn='+this.pagenum
                + '&ver='+this.version;
        break;
    }
    if (this.GAalerts) this.displayTag('trackPageview('+pageurl+')');
    try {
      this.pageTracker._trackPageview(pageurl);
    } catch (err) {if (this.GAalerts) this.displayTag("trackPageview Error: "+err.description)}
  };

  this.trackEvent = function(args) {
    switch (args.length) {
      case 2:
        if (this.GAalerts) this.displayTag('trackEvent('+args[0]+','+args[1]+')');
        try {
          this.pageTracker._trackEvent(args[0], args[1]);
        } catch (err) {if (this.GAalerts) this.displayTag("trackEvent Error: "+err.description)}
        break;
      case 3:
        if (this.GAalerts) this.displayTag('trackEvent('+args[0]+','+args[1]+','+args[2]+')');
        try {
          this.pageTracker._trackEvent(args[0], args[1], args[2]);
        } catch (err) {if (this.GAalerts) this.displayTag("trackEvent Error: "+err.description)}
        break;
      case 4:
        if (this.GAalerts) this.displayTag('trackEvent('+args[0]+','+args[1]+','+args[2]+','+args[3]+')');
        try {
          this.pageTracker._trackEvent(args[0], args[1], args[2], Number(args[3]));
        } catch (err) {if (this.GAalerts) this.displayTag("trackEvent Error: "+err.description)}
        break;
    }
  };

  this.trackClickout = function(args) {
    this.trackEvent([args.event[0], args.event[1], args.event[2], this.clickoutsource]);
    this.clickoutsource=0;
    this.myfindspanel='';
    var orderID = Math.floor(Math.random()*1000000000000);
    if (this.GAalerts) {
      this.displayTag('addTrans('+orderID+','+args.trans[0]+','+args.trans[1]+',"","",'+this.city+','+this.state+','+this.country+')');
      this.displayTag('addItem('+orderID+','+args.item[0]+','+args.item[1]+','+args.item[2]+','+args.item[3]+','+args.item[4]+')');
    }
    try {
      this.pageTracker._addTrans(orderID, args.trans[0], args.trans[1], "", "", this.city, this.state, this.country);
      this.pageTracker._addItem(orderID, args.item[0], args.item[1], args.item[2], args.item[3], args.item[4]);
      this.pageTracker._trackTrans();
    } catch (err) {if (this.GAalerts) this.displayTag("trackTrans Error: "+err.description)}
  };
};

function indexOf(array, object) {
	if (typeof array == 'string')
		array = array.split("");
	
	for (var i=0; i<array.length; i++) {
		if (array[i] === object) {
			return i;
		}
	}
	
	return -1;
}

thefind.add('timing', new function() {
	this.init = function() {
		this.l = [];
		this.i = 0;
	}
	
	this.log = function(do_clear) {
		if (do_clear)
			this.init();
		
		var	i = this.i,
				l = this.l;
		
		l[i] = new Date();
		l[i].ms = (l[i].getSeconds() * 1000) + l[i].getMilliseconds();
		
		this.i++;
	}
	
	this.print = function(log, do_alert) {
		if (log)
			this.log();
		
		var	l = this.l,
				debug = 'Delay[';
		
		for (var i = 0; i < this.i; i++)
			if (i > 0) 
				debug += (l[i] - l[(i-1)]) + 'ms : ';
		
		debug += 'total(' + (l[l.length-1] - l[0]) + 'ms)]';
		
		if (do_alert)
			alert(debug);
		else
			console.log(debug);
  }
	
	this.init();
});

function changeStringArrayProperty(string,delimiter,property,value) {
	var array = string.split(delimiter), parm, ret = '';
	
	for (var i=0; i<array.length; i++) {
		parm = array[i].split('=');
		
		if (parm.length < 2)
			continue;
		
		if (parm[0] && parm[0] == property)
			parm[1] = value;
		
		ret += (ret ? '&' : '') + parm[0] + '=' + parm[1];
	}
	
	return ret;
}

function html_entity_decode(s) {
	var t=document.createElement('textarea');
	t.innerHTML = s;
	var v = t.value;
	return v;
}

function queueXHR(parms) {
	var urlargs = null;
	ajaxlib.Queue({method:'POST', url:wwwroot + '/myfinds.fhtml?' + parms, args: urlargs}, false);
	if (ajaxlib.xmlhttpReady())
		ajaxlib.Go();
}

function forEach(obj, func) {
	if (typeof obj.length != 'undefined') for (var i = 0; i < obj.length; func(i, obj[i++]));
	else for (var i in obj) func(i, obj[i]);
}

function curvyInit(el) {
  $TF(el).corner();
}

function fixSuckerFish() {
	$TF(document).ready(function() { $TF('.tf_search_item .tf_util_hover').sfHover(); });
}

function htmlentities (string, quote_style) {
	// http://kevin.vanzonneveld.net
	// +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	// +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	// +   improved by: nobbler
	// +    tweaked by: Jack
	// +   bugfixed by: Onno Marsman
	// +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	// -    depends on: get_html_translation_table
	// *     example 1: htmlentities('Kevin & van Zonneveld');
	// *     returns 1: 'Kevin &amp; van Zonneveld'
	// *     example 2: htmlentities("foo'bar","ENT_QUOTES");
	// *     returns 2: 'foo&#039;bar'

	var histogram = {}, symbol = '', tmp_str = '', entity = '';
	tmp_str = string.toString();
	
	if (false === (histogram = get_html_translation_table('HTML_ENTITIES', quote_style))) {
			return false;
	}
	
	for (symbol in histogram) {
			entity = histogram[symbol];
			tmp_str = tmp_str.split(symbol).join(entity);
	}
	
	return tmp_str;
}

function get_html_translation_table(table, quote_style) {
	// http://kevin.vanzonneveld.net
	// +   original by: Philip Peterson
	// +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	// +   bugfixed by: noname
	// +   bugfixed by: Alex
	// +   bugfixed by: Marco
	// +   bugfixed by: madipta
	// %          note: It has been decided that we're not going to add global
	// %          note: dependencies to php.js. Meaning the constants are not
	// %          note: real constants, but strings instead. integers are also supported if someone
	// %          note: chooses to create the constants themselves.
	// %          note: Table from http://www.the-art-of-web.com/html/character-codes/
	// *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
	// *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}
	
	var entities = {}, histogram = {}, decimal = 0, symbol = '';
	var constMappingTable = {}, constMappingQuoteStyle = {};
	var useTable = {}, useQuoteStyle = {};
	
	useTable      = (table ? table.toUpperCase() : 'HTML_SPECIALCHARS');
	useQuoteStyle = (quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT');
	
	// Translate arguments
	constMappingTable[0]      = 'HTML_SPECIALCHARS';
	constMappingTable[1]      = 'HTML_ENTITIES';
	constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
	constMappingQuoteStyle[2] = 'ENT_COMPAT';
	constMappingQuoteStyle[3] = 'ENT_QUOTES';
	
	// Map numbers to strings for compatibilty with PHP constants
	if (!isNaN(useTable)) {
			useTable = constMappingTable[useTable];
	}
	if (!isNaN(useQuoteStyle)) {
			useQuoteStyle = constMappingQuoteStyle[useQuoteStyle];
	}

	if (useTable == 'HTML_SPECIALCHARS') {
			// ascii decimals for better compatibility
			entities['38'] = '&amp;';
			if (useQuoteStyle != 'ENT_NOQUOTES') {
					entities['34'] = '&quot;';
			}
			if (useQuoteStyle == 'ENT_QUOTES') {
					entities['39'] = '&#039;';
			}
			entities['60'] = '&lt;';
			entities['62'] = '&gt;';
	} else if (useTable == 'HTML_ENTITIES') {
			// ascii decimals for better compatibility
		entities['38']  = '&amp;';
			if (useQuoteStyle != 'ENT_NOQUOTES') {
					entities['34'] = '&quot;';
			}
			if (useQuoteStyle == 'ENT_QUOTES') {
					entities['39'] = '&#039;';
			}
		entities['60']  = '&lt;';
		entities['62']  = '&gt;';
		entities['160'] = '&nbsp;';
		entities['161'] = '&iexcl;';
		entities['162'] = '&cent;';
		entities['163'] = '&pound;';
		entities['164'] = '&curren;';
		entities['165'] = '&yen;';
		entities['166'] = '&brvbar;';
		entities['167'] = '&sect;';
		entities['168'] = '&uml;';
		entities['169'] = '&copy;';
		entities['170'] = '&ordf;';
		entities['171'] = '&laquo;';
		entities['172'] = '&not;';
		entities['173'] = '&shy;';
		entities['174'] = '&reg;';
		entities['175'] = '&macr;';
		entities['176'] = '&deg;';
		entities['177'] = '&plusmn;';
		entities['178'] = '&sup2;';
		entities['179'] = '&sup3;';
		entities['180'] = '&acute;';
		entities['181'] = '&micro;';
		entities['182'] = '&para;';
		entities['183'] = '&middot;';
		entities['184'] = '&cedil;';
		entities['185'] = '&sup1;';
		entities['186'] = '&ordm;';
		entities['187'] = '&raquo;';
		entities['188'] = '&frac14;';
		entities['189'] = '&frac12;';
		entities['190'] = '&frac34;';
		entities['191'] = '&iquest;';
		entities['192'] = '&Agrave;';
		entities['193'] = '&Aacute;';
		entities['194'] = '&Acirc;';
		entities['195'] = '&Atilde;';
		entities['196'] = '&Auml;';
		entities['197'] = '&Aring;';
		entities['198'] = '&AElig;';
		entities['199'] = '&Ccedil;';
		entities['200'] = '&Egrave;';
		entities['201'] = '&Eacute;';
		entities['202'] = '&Ecirc;';
		entities['203'] = '&Euml;';
		entities['204'] = '&Igrave;';
		entities['205'] = '&Iacute;';
		entities['206'] = '&Icirc;';
		entities['207'] = '&Iuml;';
		entities['208'] = '&ETH;';
		entities['209'] = '&Ntilde;';
		entities['210'] = '&Ograve;';
		entities['211'] = '&Oacute;';
		entities['212'] = '&Ocirc;';
		entities['213'] = '&Otilde;';
		entities['214'] = '&Ouml;';
		entities['215'] = '&times;';
		entities['216'] = '&Oslash;';
		entities['217'] = '&Ugrave;';
		entities['218'] = '&Uacute;';
		entities['219'] = '&Ucirc;';
		entities['220'] = '&Uuml;';
		entities['221'] = '&Yacute;';
		entities['222'] = '&THORN;';
		entities['223'] = '&szlig;';
		entities['224'] = '&agrave;';
		entities['225'] = '&aacute;';
		entities['226'] = '&acirc;';
		entities['227'] = '&atilde;';
		entities['228'] = '&auml;';
		entities['229'] = '&aring;';
		entities['230'] = '&aelig;';
		entities['231'] = '&ccedil;';
		entities['232'] = '&egrave;';
		entities['233'] = '&eacute;';
		entities['234'] = '&ecirc;';
		entities['235'] = '&euml;';
		entities['236'] = '&igrave;';
		entities['237'] = '&iacute;';
		entities['238'] = '&icirc;';
		entities['239'] = '&iuml;';
		entities['240'] = '&eth;';
		entities['241'] = '&ntilde;';
		entities['242'] = '&ograve;';
		entities['243'] = '&oacute;';
		entities['244'] = '&ocirc;';
		entities['245'] = '&otilde;';
		entities['246'] = '&ouml;';
		entities['247'] = '&divide;';
		entities['248'] = '&oslash;';
		entities['249'] = '&ugrave;';
		entities['250'] = '&uacute;';
		entities['251'] = '&ucirc;';
		entities['252'] = '&uuml;';
		entities['253'] = '&yacute;';
		entities['254'] = '&thorn;';
		entities['255'] = '&yuml;';
	} else {
			throw Error("Table: "+useTable+' not supported');
			return false;
	}
	
	// ascii decimals to real symbols
	for (decimal in entities) {
			symbol = String.fromCharCode(decimal);
			histogram[symbol] = entities[decimal];
	}
	
	return histogram;
}

/* Return value of multilevel object element if defined at all levels, else return null (without trapping error)
 * args:
 * obj -- multilevel object name
 * element -- 'quoted' object element (as string)
 */
function arrayGet(obj, element) {
	var ptr = obj;
	var x = element.split(".");
	for (var i = 0; i < x.length; i++) {
		if (ptr==null || (typeof ptr[x[i]] != 'array' && typeof ptr[x[i]] != 'object' && i != x.length-1)) {
			ptr = null;
			break;
		}
		ptr = ptr[x[i]];
	}
	return (typeof ptr == "undefined" ? null : ptr);
}

/* Sets value in a multilevel object element 
* args:
* obj -- multilevel object
* element -- 'quoted' object element (as string)
*/
function arraySet(obj, element, value) {
	var ptr = obj;
	var x = element.split(".");
	for (var i = 0; i < x.length - 1; i++) {
		if (ptr==null || (typeof ptr[x[i]] != 'array' && typeof ptr[x[i]] != 'object' && i != x.length-1)) {
			ptr = null;
			break;
		}
		ptr = ptr[x[i]];
	}
	if (typeof ptr == "object") {
		ptr[x[x.length-1]] = value;
	}
}

/* Return first non-empty value from list of args, or null if all are empty
* Empty string, null and undefined are considered 'empty' and skipped over
* Numeric 0 is considered non-empty and returned
*/
function any() {
	var arg;
	for (var i=0; i<arguments.length; i++) {
		if (((arg=arguments[i]) !== null) && (arg !== "") && (typeof arg !== "undefined")) return arg;
	}
	return null;
}

thefind.utils.fixEvent.preventDefault = function() {
  this.returnValue = false;
}

thefind.utils.fixEvent.stopPropagation = function() {
  this.cancelBubble = true;
}

function setOpacity(obj,value) {
  obj.style.opacity=value/10;
  obj.style.filter='alpha(opacity='+value*10+')';
}

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));
}

/*
 * 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,
			inputs = form.getElementsByTagName('input'),
			checkboxes = new Array();
	
	for (i=0; i<inputs.length; i++) 
		if (inputs[i].type == 'checkbox')
			inputs[i].checked = state;
}

function escapeHTML(str) {
   var div = document.createElement('div');
   var text = document.createTextNode(str);
   div.appendChild(text);
   return div.innerHTML;
};

function getChildContentByClassName(parent, className, attrname) {
  if (parent && className) {
    var ret = null;
    tmp = thefind.utils.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;
}

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

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

function setFeedbackFormType(type) {
  var formIntro = document.getElementById("feedbackIntro");
  var formContentsQuery = document.getElementById("feedbackFormContentsQuery");
  var formContentsGeneral = document.getElementById("feedbackFormContentsGeneral");

  if (type) {
    formIntro.style.display = "none";
    if (type == "query") {
      formContentsQuery.style.display = "block";
      formContentsGeneral.style.display = "none";
    } else if (type == "general") {
      formContentsQuery.style.display = "none";
      formContentsGeneral.style.display = "block";
    }
  } else {
    formIntro.style.display = "block";
    formContentsQuery.style.display = "none";
    formContentsGeneral.style.display = "none";
  }
}

function resetMyfinds() {
  var emailbutton = document.getElementById('myfindsEmailButton');
	
  if (emailbutton) {
    emailbutton.src = "/images/buttons/buttonShareItems_off.png";
    var link = document.getElementById("tf_myfinds_saved");
		
    if(link) {
      var inputs = link.getElementsByTagName('input');
      var checkboxes = new Array();
			
      for (i = 0; i < inputs.length; i++) {
        var input = inputs[i];
				
        if (input.type == 'checkbox')
          input.checked = false;
      }
    }
  }
}

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 focus(id) {
  var target = document.getElementById(id); 
	
  if (target)
    try {
      target.focus();
    } catch(e) { }
}

function focusError(classname) {
  if (classname)
    var target = thefind.utils.getElementsByClassName(document, "*", classname);
	
  if (target[0])
    try {
      target[0].focus();
    } catch(e) { }
}

function fixPNG() {
  if (thefind.browser.type == "msie" && thefind.browser.version <= 6) {
    //FIXME this breaks fixpng, I'm commenting it out, if this breaks other things... well, if you happen to see this comment maybe it will inspire you to try uncommenting out the line below to see if that has an effect -- mac daddy
    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')";
      }
    }
  }
}

Array.prototype.inArray = function (value) {
		// Returns true if the passed value is found in the
		// array.  Returns false if it is not.
    for (var i = 0; i < this.length; i++) {
			// Matches identical (===), not just similar (==).
			if (this[i] === value) {
				return true;
			}
    }
		
    return false;
};
/*
 * ContextMenu - jQuery plugin for right-click context menus
 *
 * Author: Chris Domigan
 * Contributors: Dan G. Switzer, II
 * Parts of this plugin are inspired by Joern Zaefferer's Tooltip plugin
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Version: r2
 * Date: 16 July 2007
 *
 * For documentation visit http://www.trendskitchens.co.nz/jquery/contextmenu/
 *
 */

(function($) {

 	var menu, shadow, trigger, content, hash, currentTarget;
  var defaults = {
    menuStyle: {
      listStyle: 'none',
      padding: '1px',
      margin: '0px',
      backgroundColor: '#fff',
      border: '1px solid #999',
      width: '100px'
    },
    itemStyle: {
      margin: '0px',
      color: '#000',
      display: 'block',
      cursor: 'default',
      padding: '3px',
      border: '1px solid #fff',
      backgroundColor: 'transparent'
    },
    itemHoverStyle: {
      border: '1px solid #0a246a',
      backgroundColor: '#b6bdd2'
    },
    eventPosX: 'pageX',
    eventPosY: 'pageY',
    shadow : true,
    onContextMenu: null,
    onShowMenu: null
 	};

  $.fn.contextMenu = function(id, options) {
    if (!menu) {                                      // Create singleton menu
      menu = $TF('<div id="jqContextMenu"></div>')
               .hide()
               .css({position:'absolute', zIndex:'500'})
               .appendTo('body')
               .bind('click', function(e) {
                 e.stopPropagation();
               });
    }
    if (!shadow) {
      shadow = $TF('<div></div>')
                 .css({backgroundColor:'#000',position:'absolute',opacity:0.2,zIndex:499})
                 .appendTo('body')
                 .hide();
    }
    hash = hash || [];
    hash.push({
      id : id,
      menuStyle: $.extend({}, defaults.menuStyle, options.menuStyle || {}),
      itemStyle: $.extend({}, defaults.itemStyle, options.itemStyle || {}),
      itemHoverStyle: $.extend({}, defaults.itemHoverStyle, options.itemHoverStyle || {}),
      bindings: options.bindings || {},
      shadow: options.shadow || options.shadow === false ? options.shadow : defaults.shadow,
      onContextMenu: options.onContextMenu || defaults.onContextMenu,
      onShowMenu: options.onShowMenu || defaults.onShowMenu,
      eventPosX: options.eventPosX || defaults.eventPosX,
      eventPosY: options.eventPosY || defaults.eventPosY
    });

    var index = hash.length - 1;
    $TF(this).bind('contextmenu', function(e) {
      // Check if onContextMenu() defined
      var bShowContext = (!!hash[index].onContextMenu) ? hash[index].onContextMenu(e) : true;
      if (bShowContext) display(index, this, e, options);
      return false;
    });
    return this;
  };

  function display(index, trigger, e, options) {
    var cur = hash[index];
    content = $TF('#'+cur.id).find('ul:first').clone(true);
    content.css(cur.menuStyle).find('li').css(cur.itemStyle).hover(
      function() {
        $TF(this).css(cur.itemHoverStyle);
      },
      function(){
        $TF(this).css(cur.itemStyle);
      }
    ).find('img').css({verticalAlign:'middle',paddingRight:'2px'});

    // Send the content to the menu
    menu.html(content);

    // if there's an onShowMenu, run it now -- must run after content has been added
		// if you try to alter the content variable before the menu.html(), IE6 has issues
		// updating the content
    if (!!cur.onShowMenu) menu = cur.onShowMenu(e, menu);

    $.each(cur.bindings, function(id, func) {
      $TF('#'+id, menu).bind('click', function(e) {
        hide();
        func(trigger, currentTarget);
      });
    });

    menu.css({'left':e[cur.eventPosX],'top':e[cur.eventPosY]}).show();
    if (cur.shadow) shadow.css({width:menu.width(),height:menu.height(),left:e.pageX+2,top:e.pageY+2}).show();
    $TF(document).one('click', hide);
  }

  function hide() {
    menu.hide();
    shadow.hide();
  }

  // Apply defaults
  $.contextMenu = {
    defaults : function(userDefaults) {
      $.each(userDefaults, function(i, val) {
        if (typeof val == 'object' && defaults[i]) {
          $.extend(defaults[i], val);
        }
        else defaults[i] = val;
      });
    }
  };

})(jQuery);

$TF(function() {
  $TF('div.contextMenu').hide();
});
	
	/*
	 *	jquery.suggest 1.1 - 2007-08-06
	 *	
	 *	Uses code and techniques from following libraries:
	 *	1. http://www.dyve.net/jquery/?autocomplete
	 *	2. http://dev.jquery.com/browser/trunk/plugins/interface/iautocompleter.js	
	 *
	 *	All the new stuff written by Peter Vulgaris (www.vulgarisoip.com)	
	 *	Feel free to do whatever you want with this file
	 *
	 */
	
	(function($) {

		$.suggest = function(input, options) {
	
			var loadingText = "Loading...";
			var loading = [];
			loading[loading.length]=loadingText;
			
			var $input = $(input).attr("autocomplete", "off");
			var $results = $(document.createElement("ul"));

			var timeout = false;		// hold timeout ID for suggestion results to appear	
			var prevLength = -1;			// last recorded length of $input.val()
			var cache = [];				// cache MRU list
			var cacheSize = 0;			// size of cache in chars (bytes?)
			$results.addClass(options.resultsClass).appendTo('body');
		  
			// used so that the input.js can hook in -lazarus
			this.results = $results[0];
			this.show_suggest = suggest;
			this.hidden = false;
			
			resetPosition();
			$(window)
				.load(resetPosition)		// just in case user is changing size of page while loading
				.resize(resetPosition);
			
			$input.blur(function() {
				setTimeout(function() { 			
						//console.log('hide',$results,$results[0],$results[0].style.display);
						$results.hide() 
				}, 200);
			});
			
			// I really hate browser detection, but I don't see any other way
			if ($.browser.mozilla)
				$input.keypress(processKey);	// onkeypress repeats arrow keys in Mozilla/Opera
			else
				$input.keydown(processKey);		// onkeydown repeats arrow keys in IE/Safari
			
			(function(self) {
				$TF($input[0].form).submit(function() { 
					self.hidden = true; $results.hide(); 
				});
			})(this);
			
			function resetPosition() {
				// requires jquery.dimension plugin
				var offset = $input.offset();
				$results.css({
					top: (offset.top + input.offsetHeight) + 'px',
					left: offset.left + 'px'
				});
			}
			
			
			function processKey(e) {
			(function(self) {
				// handling up/down/escape requires results to be visible
				// handling enter/tab requires that AND a result to be selected
				if ((/^(27|38|40|9)$/.test(e.keyCode) && $results.is(':visible')) 
					|| (/^(13|9)$/.test(e.keyCode) && getCurrentResult())) {
		      
					switch(e.keyCode) {
						case 38: // up
							self.index = -1;
							prevResult();
							break;
						
						case 40: // down
							self.index = -1;
							nextResult();
							break;
						
						case 9:  // tab completion -lazarus
							self.index = self.index > self.items.length-2 ? 0 : self.index;
							
							var index = self.index >= 0 ? self.index : 0,
									suggested = self.items[index],
									input_value = $input.val(),
									admin = ($input[0].id == 'tf_admin_cobrand_add_key');
							
							if (!suggested)
								break;
							
							if (self.index == -1) 
								if ($currentResult = getCurrentResult())
									$currentResult.removeClass(options.selectClass);
							
							// if in admin panel, use awesome tokenized tab completion -lazarus
							if (admin) {
								var	input_parms = input_value.split('.'),
										suggest_parms = suggested.split('.');
								
								if (!input_parms[input_parms.length-1]) {
									// last token is empty, user rejected suggestion.  suggest alternatives.
									var	current = input_parms[input_parms.length-2],
											tmp = '';
									
									for (var i=0; i<input_parms.length-2; i++) 
										tmp += input_parms[i] + '.';
									
									if (!self.matches || self.matches.length == 0) {
										// rebuild alternative suggestions list
										var matches = [],
												si = 0,
												item;
										
										while (1) {
											if (index + 1 >= self.items.length) {
												index = 0;
												self.index = 0;
											} else {
												index = index + 1;
											}
											
											if (index == self.index)
												break;
											
											item = self.items[index]
											
											var rgexp = new RegExp('^' + tmp, 'i');
											if (rgexp.test(item)) {
												var split = item.split('.'),
														candidate = split[input_parms.length-2],
														newrgexp = new RegExp('^' + self.last_input, 'i');
												
												if (indexOf(matches,candidate) < 0 && newrgexp.test(tmp + candidate))
													matches.push(candidate);
											}
										}
										
										self.matches = matches;
									}
									
									if (self.matches.length > 0) {
										// use the next suggestion in the alternative suggestions list
										self.match_index = self.match_index+1 >= self.matches.length ? 0 : self.match_index+1;
										suggested = tmp + self.matches[self.match_index] + '.';
									} else {
										var shpadoinkle = true;
									}
								} else {
									// suggest most likely token based on the input's last token
									var rgexp = new RegExp('^' + input_value, 'i');
									if (!rgexp.test(suggested)) {
										// this ensures the suggested suggestion starts with the input_value
										while (!rgexp.test(suggested)) {
											index++;
											
											if (index >= self.items.length) {
												suggested = self.items[index = 0];
												break;
											}
											
											suggested = self.items[index];
										}
										
										suggest_parms = suggested.split('.');
									}
									
									var	end_parm = input_parms[input_parms.length-1],
											suggested = '',
											parm;
									
									if (input_parms.length > suggest_parms.length)
										return;
									
									for (var i=0; i<input_parms.length; i++) 
										suggested += suggest_parms[i] + '.';
									
									self.last_input = input_value;
								}
							} else {
								// not in admin panel, highlight the next entry
								nextResult();
							}
							
							if (suggested) {
								if (suggested != input_value)
									$input[0].value = suggested;
								else if (self.index < 0)
									$input[0].value = suggested;
								else if (!admin)
									$input[0].value = self.items[++index];
								
								self.index = index;
								if (shpadoinkle) return;
								else break;
							}
							
							if (admin) break;
							else return;
							
						case 13: // return
							self.hidden = true;
							selectCurrentResult();
							$results.hide();
							break;
						
						case 27: //	escape
							$results.hide();
							break;
						
					}
		      
					if (e.preventDefault)
		        e.preventDefault();
					
					if (e.stopPropagation)
		        e.stopPropagation();
					
					e.cancelBubble = true;
					e.returnValue = false;
					
				} else if ($input.val().length != prevLength) {
					self.hidden = false;
					if (timeout) 
						clearTimeout(timeout);
					
					timeout = setTimeout(suggest, options.delay);
					prevLength = $input.val().length;
					
					if(prevLength == 0) 
						prevLength = -1;
				}
			})(this);
			}
			
			
			function suggest() {
			(function(self) {
				self.index = 0;
				self.matches = [];
				self.match_index = 0;
				
				var q = $.trim($input.val());
        //FIXME setting width of suggest.  the +4 is to make up for input padding, not a good way to do this although it works.
				$results.width($input.width()+47);
				if (q.length >= options.minchars) {
					cached = checkCache(q);
					if (cached) {
						if (!self.hidden)
							displayItems(cached['items']);
					} else {
						//displayItems(loading);
						$.get(options.source, {q: q}, function(txt) {
							//$results.hide();
							if (!self.hidden && txt.length > 2) {
				 				var items = parseTxt(txt, q);
								displayItems(items);
								addToCache(q, items, txt.length);
							}
						});
					}
				} else {
          /*
          var test = {"qpm":["test","test2","test3"]};
          displayItems(test);
          console.log(100);
          */
					$results.hide();
				}
			})(this);
			}
			
			function checkCache(q) {
				for (var i = 0; i < cache.length; i++)
					if (cache[i]['q'] == q) {
						cache.unshift(cache.splice(i, 1)[0]);
						return cache[0];
					}
				
				return false;
			}
			
			function addToCache(q, items, size) {
				while (cache.length && (cacheSize + size > options.maxCacheSize)) {
					var cached = cache.pop();
					cacheSize -= cached['size'];
				}
				
				cache.push({
					q: q,
					size: size,
					items: items
				});
				
				cacheSize += size;
			}
			
			function displayItems(items) {
			(function(self) {
				if (!items)
					return;

				self.items = [];
				
				if (items) 
					for (var key in items) 
						for (var i=0; i<items[key].length; i++) 
							if (items[key][i])
								self.items.push(items[key][i].replace(/<\/?[^>]+(>|$)/g, ""));
				
				if (!items.myfinds && !items.qpm) {
					$results.hide();
					return;
				}
				var html = ''; //'<li class="ac_noselect">No suggestions found.</li>';
				for (var i = 0; i < items.length; i++) {
					var delimiterIndex = isDelimiter(items[i]);
					if (delimiterIndex >= 0){
						html += '<li class="' + options.listDelimitersClass[delimiterIndex] +'"></li>';	
					} else {
						html += '<li>' + items[i] + '</li>';
          }
        }
        if (items.myfinds) {
          html += '<li class="ac_label ac_noselect ac_myfinds"><div class="ac_title">my searches</div></li>';
				  for (var i = 0; i < items.myfinds.length; i++) {
						html += '<li class="ac_myfavorites">' + items.myfinds[i] + '</li>';
          }
          if (items.qpm) {
            html += '<li class="ac_noselect ac_divider"></li>';
            html += '<li class="ac_label ac_noselect ac_suggested"><div class="ac_title">suggested searches</div></li>';
          }
        }
        if (items.qpm) {
          var show_from_qpm = 7;
          if (items.qpm.length <= 7)
            show_from_qpm = items.qpm.length;
				  for (var i = 0; i < show_from_qpm; i++) {
						html += '<li class="ac_suggestions">' + items.qpm[i] + '</li>';
          }
        }
        /*
        if(items.qpm == "")
          html += '<li class="ac_noselect">No suggestions found.</li>';
        */
				
				$results.html(html).show();
				
				// help IE6 users if possible
				if (typeof $TF != 'undefined')
					$TF($results).bgiframe();
        
				var hide_box = false;
        if(items.qpm && items.qpm == "")
          hide_box = true;
        if(items.myfinds && items.myfinds == "" && hide_box)
          hide_box = true;
        if(hide_box)
				  $results.html(html).hide();

				if (options.listPostProcess) {
					options.listPostProcess.apply();
				}
				
				$results
					.children('li')
					.mouseover(function() {
						$results.children('li').removeClass(options.selectClass);
            if(!$(this).hasClass("ac_noselect"))
						  $(this).addClass(options.selectClass);
					})
					.click(function(e) {
            if(!$(this).hasClass("ac_noselect")) {
  						e.preventDefault(); 
	  					e.stopPropagation();
		  				selectCurrentResult();
            }
					});
			})(this);
			}

			function isDelimiter(token) {
				var index = -1;
				for (var i = 0; i < options.listDelimiters.length; ++i) {
					if (options.listDelimiters[i] == token) {
						index = i;
						break;
					}
				}
				return index;
			}
			
			function parseTxt(txt, q) {
				var items = [];
				
				var items = [];
        var items = thefind.JSON.parse(txt);
        if (items) {
          for (var k in items) {
            for (var i = 0; i < items[k].length; i++) {
              items[k][i] = htmlentities(items[k][i]).replace(
                new RegExp('\\b'+q, 'ig'), 
                function(q) { return '<span class="' + options.matchClass + '">' + q + '</span>' }
              );
            }
          }
        }

        /*
				var tokens = txt.split(options.delimiter);
				
				// parse returned data for non-empty items
				for (var i = 0; i < tokens.length; i++) {
					var token = $.trim(tokens[i]);
					if (token) {
						token = token.replace(
							new RegExp(q, 'ig'), 
							function(q) { return '<span class="' + options.matchClass + '">' + q + '</span>' }
							);
						items[items.length] = token;
					}
				}
				*/			
				return items;
			}
			
			function getCurrentResult() {
				if (!$results.is(':visible'))
					return false;
				
				var $currentResult = $results.children('li.' + options.selectClass);
				
				if (!$currentResult.length)
					$currentResult = false;
					
				return $currentResult;
			}
			
			function selectCurrentResult() {
				$currentResult = getCurrentResult();
				
				if ($currentResult) {
					$input.val($currentResult.text());
					$results.hide();
					
					if (options.onSelect)
						options.onSelect.apply($input[0]);
				}
			}
			
			function nextResult() {
				$currentResult = getCurrentResult();
				
				if ($currentResult) {
					$currentResult
						.removeClass(options.selectClass);
					
					var next = $currentResult.next();
          while(next.hasClass('ac_noselect'))
            next = next.next();
					if (!next.length) {
						next = $results.children('li:first-child');
            while(next.hasClass('ac_noselect'))
              next = next.next();
          }
					
					next.addClass(options.selectClass);
				} else {
          var first = $results.children('li:first-child')
          while(first.hasClass('ac_noselect'))
            first = first.next()
          first.addClass(options.selectClass);
				}
			}
			
			function prevResult() {
				$currentResult = getCurrentResult();
				
				if ($currentResult) {
					$currentResult.removeClass(options.selectClass);
          var prev = $currentResult.prev();
          while(prev.hasClass('ac_noselect'))
            prev = prev.prev();
          
          prev.addClass(options.selectClass);
				} else {
          /*
          var last = $results.children('li:last-child')
          while(last.hasClass('ac_noselect'))
            last = last.prev();
          last.addClass(options.selectClass);
          */
					$results.children('li:last-child').addClass(options.selectClass);
				}
			}
			
			return this;
		}
		
		$.fn.suggest = function(source, options) {
		
			if (!source)
				return;
		
			options = options || {};
			options.source = source;
			options.delay = options.delay || 100;
			options.resultsClass = options.resultsClass || 'ac_results';
			options.selectClass = options.selectClass || 'ac_over';
			options.matchClass = options.matchClass || 'ac_match';
			options.minchars = options.minchars || 2;
			options.delimiter = options.delimiter || '\n';
			options.onSelect = options.onSelect || false;
			options.maxCacheSize = options.maxCacheSize || 65536;
			options.listDelimiters = options.listDelimiters || Array(";;");
			options.listDelimitersClass = options.listDelimitersClass || Array("ac_delimiter");
			options.listPostProcess = options.listPostProcess || false;
			
			var suggestObj;
			this.each(function() {
				suggestObj = new $.suggest(this, options);
			});
			
			return suggestObj;
			
		};
		
	})(jQuery);
	
thefind.add('suggest', function(options) {
  $TF(function() {
  	$TF("#inputbox").suggest("/search/suggest?spellcheck="+spelling, {
			delay: 200,
			minchars: 1,
			listDelimiters: Array("**", "<;", ";;", ";>"),
			listDelimitersClass: Array("ac_spellcheck", "ac_start", "ac_split", "ac_end"),
			listPostProcess: function() { 
				$TF(".ac_spellcheck").html("the correct spelling goes here"); 
				$TF(".ac_split").replaceWith("<div>-----------------------</div>");
				$TF(".ac_start").replaceWith(""); 
				$TF(".ac_end").replaceWith(""); 
			},
			onSelect: function() {
				alert("you selected " + this.value)
			}
		});
	});
/*
  var spacePosition = [];
  var wordList = [];
  var spellingmap = new Object();
  var http_request = false;
  
  correctArrays = function(inputLength) {
    while( (spacePosition.length > 0) && (spacePosition[spacePosition.length -1] >= inputLength - 1) ) {
	spacePosition.pop();
	wordList.pop();
    }
  }
  
  callYahoo = function(url, incorrectWord) {
    try {
      netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
    } catch (e) {
      alert("permission UniversalBrowserRead denied");
    }
    if (window.XMLHttpRequest) {
     http_request = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        http_request = new ActiveXObject("Microsoft.XMLHTTP");
    }
    http_request.onreadystatechange = handleyahooreply(incorrectWord);
    http_request.open('GET', url, true);
    http_request.send(null);
  }
  
  handleyahooreply = function(incorrectWord) {
    if (http_request.readyState == 4) {
      if (htt_request.status == 200) {
	spellingmap[incorrectWord] = http_request.responseText;
      }
    }
  }
  
  appid = "YahooDemo"; 
  if ((spelling == 1) && (appid != null)) {
    $TF("#inputbox").bind("keyup", function (ev) {
  	var inputstring = $TF("#inputbox").val();
	var inputLength = inputstring.length;
	if ( ev.which ==32) {
	  if ((inputLength > 1) && (inputstring[inputLength -2] != " ") ){
	    //console.log(inputstring);
	    correctArrays(inputLength);
	    wordList = inputstring.split(" ");
	    wordList.pop(); // remove the extra "" element
	    spacePosition = [];
	    pos = 0;
	    for (i=0; i<wordList.length; ++i) {
	      pos += wordList[i].length;
	      spacePosition.push(pos);
	      ++pos;
	      if (typeof(spellingmap[wordList[i]]) == "undefined") {
	        //this word is not in the spelling map
		callYahoo("http://search.yahooapis.com/WebSearchService/V1/spellingSuggestion?appid="+appid+"&query="+wordList[i], wordList[i]);
		spellingmap[wordList[i]] = "correct this";
	      }
	    }
	    //$TF("#inputbox").val("right spell");
	    console.log(spacePosition);
	    console.log(wordList);
	    console.log(spellingmap);
	  }
	}
	else {
	  //check the spacePosition array
	  correctArrays(inputLength);
	}	
    });
  }
  */
  /*
  var ta = document.getElementById('ta').contentWindow.document;
  ta.designMode = "on";
  try {
    ta.execCommand("undo", false, null);
  } catch(e) {
    //console.log(e);
  }
  ta.execCommand("contentReadOnly", false, false);
  ta.execCommand("backcolor", false, "#000033");
  //console.log(ta);
  */
  
  $TF("#searchbutton").bind("click", function (ev) {} );
});
function TFSearchInput(parent, args) {
  this.parent = parent;
  this.form = null;
  this.input = null;
	this.ajax = (args.ajax) ? true : false;
	this.padding = 0;
	this.args = args;

  this.init = function(args) {
    this.form = document.getElementById(args.id);
		
    if (this.form) {
      this.input = $TF(this.form).find("input.tf_search_input_element")[0];
			
			this.universal_header_init(args);
			
			addEvent(this.input.form, "submit", this);
			
			var	parent = input = this.input,
          suggest_active = args.suggest && args.suggest == 1;
			
      if (suggest_active)
        $TF(input).css({ 
          color: '#fff'
        });
			
			(function(self) {
        if (suggest_active) {
					while (parent.tagName != 'FORM') {
            if (parent.tagName == 'BODY')
              break;
            
            parent = parent.parentNode;
          }
 					
					if (parent && parent != self.input) {
						self.padding_method = thefind.browser.type == 'msie' || thefind.browser.type == 'safari';
						$TF(parent).addClass('tf_suggest');
						
						var suggestdiv = self.suggestdiv = $TF('div.tf_suggest', parent)[0];
            
						addEvent(suggestdiv, 'mouseup', self);
						addEvent(suggestdiv, 'mousedown', self);
						addEvent(suggestdiv, 'mouseout', self);
						
						var delay = thefind.browser.type != 'msie'
							? 1
							: thefind.browser.version == 8 
								? 500 
								: 1000;
						
						setTimeout(function() {
              self.suggest_opening_animation();
						}, delay);
					}
        }
				
        $TF(document).ready(function() {
          if (typeof $TF.suggest == 'function')
            self.suggestObj = $TF(self.input).suggest("/search/suggest.js?spellcheck=" + 0, {
              delay: 100,
              minchars: 1,
              onSelect: function() { 
                self.form.submit();
                self.suggest_animation();
              }
            });
        });
				
				if (self.input && args.autofocus) {
					$TF(document).ready(function() {
						// try/catch needed to prevent IE element not focusable fatal error
						try { self.input.focus(); }
						catch (e) { } 
					});
				}
			})(this);
    }
  }
  
  this.SetQuery = function(query) {
    //this.parent.ExecuteSearch({query:query});
  }
	
  this.ValidQuery = function(query) {
    return (query.replace(/^\s*/, "").replace(/\s*$/, "").length > 0);
  }
	
	this.universal_header_init = function(args) {
		this.types = args['types'] || [];
		this.universal_header_types = $TF('ul.tf_search_input_types li', this.form);
		this.universal_header_targets = {};
		
		for (var i=0; i<this.universal_header_types.length; i++) {
			var	li = this.universal_header_types[i];
					link = li.getElementsByTagName('A'),
					label = link[0].innerHTML;
			
			if (thefind.utils.hasClass(li, 'tf_universal_header_selected')) {
				this.type = li;
				
				if (link.length > 0)
					thefind.page_type = label;
			}
			
			this.universal_header_targets[label] = li;
			
			addEvent(this.universal_header_types[i], "click", this);
		}
	}
	
	this.universal_header_change = function(target, nosubmit) {
		var	target = typeof target == 'string' ? this.universal_header_targets[target] : target;
		
		if (!target)
			return;
		
		var	value = this.input ? this.input.value : '',
				link = thefind.utils.getFirstChild(target, 'A'),
				type = link.innerHTML.toLowerCase(),
				href = link.href.split('=')[0],
				newaction = "";
		
		if (thefind.utils.hasClass(target, 'tf_universal_header_selected'))
			return this.input.focus();
		
		thefind.utils.addClass(target, 'tf_universal_header_selected');
		thefind.utils.removeClass(this.type, 'tf_universal_header_selected');
		
		if (this.types[type]) {
			if (this.types[type].domain) 
				newaction = this.types[type].domain;
			
			newaction += (this.types[type].action ? this.types[type].action : "/" + type);
		} else {
			newaction = "/" + type;
		}
		
		this.form.action = newaction;
		this.type = target;
		
		if (value) {
			if (!nosubmit) {
        this.suggest_animation();
        this.form.submit();
      }
    } else {
			if (this.args.updateaction == 1) {
				this.input.focus();
				this.suggest_opening_animation();
			} else
				return false;
		}
		
		return true;
	}

  this.handleEvent = function(event) {
		var	event = event || window.event,
				target = event.srcElement || event.target;
		
    switch (event.type) {
			case "click":
				while (target && target.nodeName != 'LI')
					target = target.parentNode;
				
				if (this.universal_header_change(target)) 
					event.preventDefault();
				
				break;
			
			case "mouseout":
				$TF(target).removeClass('tf_button_down');
				
				break;
      
			case "mouseup":
				if (this.suggestObj.results.style.display == 'block') {
					this.input.focus();
					this.input.blur();
				} else {
					this.input.focus();
					this.suggestObj.show_suggest();
				}
				
				$TF(target).removeClass('tf_button_down');
				
				break;
      
			case "mousedown":
				$TF(target).addClass('tf_button_down');
				
				break;
      
			case "submit":
				if (this.input) {
					var	smartmap = document.getElementById('tf_search_filters_toggle_localsmartmap_input');
					
					/*
					savefilters = document.getElementById('tf_search_input_savefilters_checkbox'),
					
					if (!savefilters || savefilters.checked) {
						event.preventDefault();
						this.suggest_shimmy_animation();
						
						thefind.func.ajax_submit({
							parms: {
								page: 1,
								query: this.input.value
							}
						});
						
						this.SetQuery(this.input.value);
						
					} else 
					*/
					if (args.ajax && (!smartmap || smartmap.checked)) {
						search.args.query = this.input.value;
						
						tfLocalSearch.ClearMarkers();
						tfLocalSearch.AjaxInputRequest(this.input.value,event.target);
						
						event.preventDefault();
					} else if (!this.ValidQuery(this.input.value)) {
						$TF(this.input).addClass("tf_util_form_error");
						
						this.input.focus();
						this.input.select();
						
						event.preventDefault();
					} else {
						if ($TF(this.input).hasClass("tf_util_form_error"))
							$TF(this.input).removeClass("tf_util_form_error");
						
						this.suggest_animation();
						this.SetQuery(this.input.value);
					}
				}
				
				break;
    }
  }
	
  this.suggest_shimmy_animation = function() {
		if (!this.suggestdiv) 
			return;
		
    $TF(this.suggestdiv).animate({
      paddingLeft: (0 - this.padding + .8) + 'em'
    }, 250, "elasin").animate({
      paddingLeft: this.padding + 'em'
    }, 250, "elasout");
  }
	
  this.suggest_opening_animation = function() {
		if (!this.suggestdiv) 
			return;
		
    $TF(this.input).css({
      color: '#000',
    	textIndent: '.1em',
      paddingLeft: '.3em'
    });
    
    if (this.padding_method) {
      $TF(this.input).animate({
        paddingLeft: '1.9em',
        paddingRight: '0em'
      }, 600, "bounceout");
    } else {
      $TF(this.input).animate({
        textIndent: '1.6em'
      }, 600, "bounceout");
    }
    
    $TF(this.suggestdiv).css({
      width: '0'
    }).animate({
      width: '23px',
      opacity: 1
    }, 600, "bounceout");
  }
	
	this.suggest_animation = function() {
		if (!this.suggestdiv) 
			return;
		
		var	l = this.input.value.length,
				ls = l ? (1.6 / (l - 1)) : 0;
		
		// without the paddingRight it shrinks the input
		if (this.padding_method) {
			this.padding = .4;
			$TF(this.input).animate({ 
				paddingLeft: this.padding + 'em',
				paddingRight: '1.6em'
			}, 600, "bounceout");
		} else if (thefind.iphone) {
			this.input.style.webkitTransition = 'all 600ms ease-out';
			this.input.style.textIndent = '0.1em';
		} else {
			$TF(this.input).animate({ 
				textIndent: '.1em' 
			}, 600, "bounceout");
		}
		
		if (thefind.iphone) {
			this.suggestdiv.style.webkitTransition = 'all 600ms ease-out';
			this.suggestdiv.style.webkitTransform = 'translateX(17em)'; // Move half as far on the iphone
			this.suggestdiv.style.opacity = '0';
		} else {
			$TF(this.suggestdiv).animate({ 
				marginLeft: '34em', 
				opacity: 0 
			}, 600, "easeout");
		}
	}

  this.init(args);
}
thefind.add('ajax_back_button', function(search, args) {
	this.search = search;
	this.enabled = args.enabled || false;
	this.cacheable = args.cacheable || false;
	this.hash = '';
	this.responses = {};
	this.exclude = [
		'filter[categoryorder]','filter[qpcookie]','filter[ddkey]','filter[groupid]','filter[localshoppingdistance]','location',
		'settings[search.pagesize.base]','ddkey','query','sname','count','view','cobrand', 'filter[query]'
	];
	
  this.init = function() {
		if (this.enabled && thefind.browser.type == 'msie' && thefind.browser.version <= 7) {
			this.iframe = document.createElement('iframe');
			this.iframe.name = 'tf_iframe_backbutton_fix';
			this.iframe.style.display = 'none';
			
			if (window.location.protocol == 'https:')
				this.iframe.src = '/blank.fhtml';
			
			document.body.appendChild(this.iframe);
			this.update_iframe(window.location.hash.replace(/#/g, "") || '');
		}
  }
	
	this.load = function(hash) {
		if (!(response = this.responses[hash]) || !this.enabled)
			return false;
		
		ajaxlib.processResponse(response[0], response[1], response[2], true);
		return true;
	}
	
	this.add = function(dom, docroot, obj) {
		if (this.enabled && this.cacheable && this.hash)
			this.responses[this.hash] = [ dom, docroot, obj ];
	}
	
	this.check = function() {
		if (!this.enabled) 
			return clearInterval(thefind.checkHash);
		
		var hash = (this.iframe) 
			?	this.iframe.contentWindow.document.body.innerHTML.replace(/&amp;/g, '&')
			:	window.location.hash.replace(/#/g, "");
		
		if (hash != this.hash) 
			this.run(this.hash = hash);
	}

	this.run = function(hash) {
		var	parms = hash.split('&'),
				tmp = (parms[indexOf(parms, 'local')] != 1)
			? ['filter[localshoppingdistance]','filter[user_location]','location']
			: [];
		
		for (var key in this.search.SearchParms) {
			if (indexOf(this.exclude, key) >= 0)
				continue;
			
			delete this.search.SearchParms[key];
		}
		
		for (var i=0; i<parms.length; i++) {
			var parm = parms[i].split('=');
			
			if (parm[0] && parm[1]) {
				this.search.setParm(parm[0], parm[1]);
				
				if (parm[0] == 'store')
					var stores = parm[1].split(',');
			}
		}
		
		if (this.iframe) 
			window.location.hash = hash.replace(/#/g, "");
		
		var	pagenum = this.search.SearchParms['page'] || 0;
		
		thefind.func.set_pagination(pagenum, this.search);
		
		if (!this.search.SearchParms.local && typeof thefind.local != 'undefined')
			this.search.setParm('local',0);
		else if (thefind.local && thefind.local.storelist && stores) {
			$TF("input:checkbox:checked", thefind.local.storelist.listul).each(function(k,checkbox) { 
				if (indexOf(stores, checkbox.value) < 0)
					checkbox.checked = !checkbox.checked;
			});
		}
		
		if (!this.load(hash)) {
			(function(self) {
				$TF(document).ready(function() {
					thefind.func.ajax_submit({ 
						search: self.search, 
						ignore_hash: true 
					});
				});
			})(this);
		}
	}
	
	this.update = function(parms) {
		if (!this.enabled) 
			return;
		
		var	hash = '',
				rem$ = function(str) {
					var split$ = str.split('$');
					
					return (split$.length > 1) 
						? split$[1] 
						: split$[0];
				},
				key,parm,split,price,value,oldprice;
		
		for (var key in parms) {	
			if (indexOf(this.exclude, key) >= 0)
				continue;
			
			split = key.split('[');
			parm = (split.length > 1) ? split[1].substr(0,split[1].length-1) : key;
			value = parms[key];
			
			if (parm != 'user_location' && !(parm == 'pagenum' && parseInt(value) == 1) && (key && value))
				hash += key+'='+value+'&';
		}
		
		if (!parms.local && thefind.local)
			hash += "local=0&";
		
		hash = hash.substr(0,hash.length-1);
		
		if (hash && hash != this.hash) {
			this.hash = hash;
			
			if (thefind.browser.type == "msie" && thefind.browser.version < 8) {
				var	timer = setTimeout(function() {
					window.location.hash = hash;
				}, 1);
			} else
				window.location.hash = hash;
		}
		
		if (this.iframe) 
			this.update_iframe(hash);
	}
	
	this.update_iframe = function(hash) {
		this.iframe.contentWindow.document.open();
		this.iframe.contentWindow.document.write('<body>' + hash + '</body>');
		this.iframe.contentWindow.document.close();
	}
	
	this.init();
});

thefind.add('search', function(name, args, options) {
	this.name = name;
	this.bindings = {};
	this.request = {};
	this.SearchParms = {};
	this.SearchParms.sname = name;
	this.options = options || {};
	this.args = args || {};
	this.response;
	this.persist;
	this.id;
	this.back_button = this.options.back_button || {};
	this.urlhash = this.back_button.enabled || false;
	this.replace = {
		'filter[localshopping]':'local',
		'filter[store]':				'store',
		'filter[color]':				'color',
		'filter[pagenum]':			'page'
	};
	
  this.Init = function(args) {
    if (arrayGet(args, 'id') != null)
      this.id = args.id;
		
		if (typeof thefind.ajax_back_button == 'undefined')
			thefind.add('ajax_back_button', new thefind.func.ajax_back_button(this, this.back_button));
		
    this.SetRequest(args);
  }
	
  this.Bind = function(type, placement, args, id, data, relatedchildren) {
    if (!type || !placement)
      return false;
		
    if (typeof this.bindings[type] == "undefined")
      this.bindings[type] = {};
		
		switch (type) {
			case "input":
				this.bindings[type][placement] = new TFSearchInput(this, args);
				break;
			case "info":
				this.bindings[type][placement] = new TFSearchInfo(this, args);
				break;
			case "filters":
				this.bindings[type][placement] = new thefind.func.filters(this, args, placement);
				break;
			case "results":
				this.bindings[type][placement] = new thefind.func.product_list(id, args, data, relatedchildren);
				break;
		}
		
    return this.bindings[type][placement];
  }

  this.SetRequest = function(args) {
    if (args && typeof args == "object") {
      this.request.query = args.query;
      this.request.filter = args.filter;
      this.request.settings = args.settings;
      this.request.extrafilters = args.extrafilters;
      this.id = args.id;
    }
  }
	
  this.ApplyFilter = function(filter, args) {
    this.request.filter[filter] = args;
  }

	this.RebuildSearchParms = function(form) {
		var querykey = this.options.querykey || "query";
		
		if (this.args.query)
			this.SearchParms[querykey] = this.args.query;
		
    // FIXME - quick-and-dirty hack for visual search pagination.  We should revisit this entirely at some point.
		if (this.args && this.args.extrafilters && this.args.extrafilters.hidden && this.args.extrafilters.hidden.ddkey)
			this.SearchParms.ddkey = this.args.extrafilters.hidden.ddkey;
		
		this.StringifyObjectProperties('filter',this.args.filter,this.SearchParms);
		
		if (!form || typeof form.elements == 'undefined') 
			return this.SearchParms;
		
    for (var i=0; i<form.elements.length; i++) {
      element = form.elements[i];
      var name = element.name;
			
      if (name.length > 0 && name != "undefined" && element.value != "undefined" && !element.disabled) {
        switch (element.type) {
					case "checkbox":
						if (element.checked) {
							var filtername = (indexOf(element.name,'[') < 0)
								? element.name
								: element.name.split('[')[1].split(']')[0];
							
							if (filtername == 'store' || filtername == 'brand') {
								for (var key in this.bindings['filters']) {
									var filter = this.bindings['filters'][key]['filters'];
									
									if (filter) {
										for (var jskey in filter) {
											if (jskey == filtername) {
												if (!filter[jskey].checked) 
													filter[jskey].checked = [];
												
												filter[jskey].checked.push(element.value);
											}
										}
									}
								}
							}
							
							var length = name.length;
							var brackets = name.substring(length-2, length);
							if (brackets == '[]')
								name = name.substring(0,length-2);
							
							if (typeof this.SearchParms[name] != 'object') 
								this.SearchParms[name] = [];
							
							this.SearchParms[name].push(element.value);
						}
						break;
          case "radio":
						if (element.checked) this.setParm(name, element.value);
						break;
					default:
						this.setParm(name, element.value.replace(/\+/g, "%2B"));
						break;
				}
			}
    }
		
		// converts arrays in SearchParms into comma-seperated strings
		for (var key in this.SearchParms) {
			if (typeof this.SearchParms[key] == 'object') {
				var	arr = this.SearchParms[key], 
						s = '', 
						i;
				
				for (i=0; i<arr.length; i++) 
					s += arr[i]+',';
				
				this.setParm(key, s.substr(0,s.length-1));
			}
		}
		
    return this.SearchParms;
	}

	this.StringifyObjectProperties = function(type, array, source) {
		var value;
		
		for (var key in array) {
			value = array[key];
			switch(typeof value) {
				case 'object': 
					for(var index in value) 
						if (typeof value[index] != 'function' && typeof value[index] != 'object')
							this.setParm(type+'['+key+']['+index+']', value[index]);
					
					break;
				default:
					if ((key == 'localshopping' && typeof this.SearchParms.local != 'undefined')
					|| (key == 'pagenum' && this.SearchParms.page != "undefined"))
						break;
					
					this.setParm(type+'['+key+']', value);
					break;
			}
		}
		
		return true;
	}

  this.GetURL = function(extra, ignore) {
    var url = "",
				utils = utils || new TFHtmlUtils();
    
		if (this.request.query)
      url += "/qq-" + utils.FriendlyURLEncode(this.request.query);
		
    if (this.request.filter) {
      var filter = this.request.filter;
			
      $TF.each(filter, function(k, obj) {
        if (!ignore || !ignore.inArray(k)) {
          url += "/filter." + k + "-" + utils.FriendlyURLEncode(decodeURIComponent(filter[k])); 
        }
      });
    }
		
    if (extra) { 
      $TF.each(extra, function(k, v) {
				// replaces / with ? for homepage  -lazarus
        url += (!url ? "?" : "/") + k + "-" + utils.FriendlyURLEncode(v);
      });
    }
		
    return url;
  }
	
	this.getBindings = function(type, name) {
		var matches = [];
		
		for (var tkey in this.bindings[type]) 
			for (var pkey in this.bindings[type][tkey].filters) 
				if (pkey == name)
					matches.push(this.bindings[type][tkey].filters[pkey])
		
		return matches;
	}
	
	// generates URL directly to current search with all search parms
	this.generate_url = function(exclude) {
		var	href	= window.location.href.split('#'),
				url		= href[0],
				ptmp	= url.split('?'),
				utmp 	= ptmp[0],
				parm	= ptmp.length > 1 ? ptmp[1].split('&') : '',
				hash	= href.length > 1 ? href[1].split('&') : '',
				array = {},
				parms = '',
				exclude = exclude || {},
				stmp = [],
				func = function(inArray) {
					for (var i=0; i<inArray.length; i++) {
						stmp = inArray[i].split('=');
						if (!exclude[stmp[0]])
							array[stmp[0]] = stmp[1];
					}					
				};
		
		func(parm);
		func(hash);
		
		this.url = ptmp[0];
		
		for (var key in array) 
			parms += (parms?'&':'?') + key + '=' + array[key];
		
		return this.url += parms;
	}
	
	this.setParm = function(name, value) {
		name = this.replace[name] || name;
		
		switch (name) {
			case 'filter[price][max]':
				var min = this.SearchParms['filter[price][min]'] || 0;
				
				name = 'price';
				value = min + '-' + value;
				
				delete this.SearchParms['filter[price][min]'];
				break;
		}
		
		this.SearchParms[name] = value;
		return name;
	}
	
	this.removeFilters = function(aFilterList) {
		for (var i=0; i<aFilterList.length; i++) {
			filter = aFilterList[i];
			filter_alt = 'filter[' + filter + ']';
			
			if (!thefind.utils.isNull(this.SearchParms[filter]))
				delete this.SearchParms[filter];
			
			if (!thefind.utils.isNull(this.SearchParms[filter_alt]))
				delete this.SearchParms[filter_alt];
		}
	}
	
	this.fSuccess = function(element) {
		if (element) {
      this.resultboxes = [element];
    } else {
      var rp = this.getActiveBindings(this.bindings.results);
      
			this.resultboxes = [];
      
			for (var i = 0; i < rp.length; i++)
        this.resultboxes.push(this.bindings.results[rp[i]].container[0]);
    }
		
		for (var k=0; k<this.resultboxes.length; k++) {
			var results = this.resultboxes[k];
			
			if (results.id == "tf_search_results_searchproduct")
				continue;
			
			var	loadingdiv = document.createElement('DIV'),
					results = results.parentNode;
			
			loadingdiv.className 	= 'tf_search_results_resubmitting';
			loadingdiv.innerHTML 	= '<p><img class="tf_results_ajax_spinner" src="/images/misc/ajax-loader-transparent.gif"></p>';
			
			if (!results)
				continue;
			
			results.insertBefore(loadingdiv, results.firstChild);
			
			loadingdiv.style.width = results.offsetWidth + 'px';
			loadingdiv.style.height = results.offsetHeight + 'px';
		}
		
		try {
			var self = this;
			
			return function(html) {
				self.PopulateResults(html);
			};
		} finally {
			delete self;
		}
	}
	
	this.PopulateResults = function(data) {
    if (typeof googleAnalytics != 'undefined') {
      googleAnalytics.status = data.googleanalytics.status;
      googleAnalytics.total = data.googleanalytics.total;
      googleAnalytics.trackPageview();
    }
		
    if (typeof quantserve == "function") {
      _qpixelsent=""; // kludge - trick quantcast into sending another pixel for this 'same' page
      quantserve();
    }
		
    if (data['search.request'])
      this.SetRequest(data['search.request']);
	}
	
	this.grabFile = function(sURL, fSuccess) {
		var element = thefind.file_utils.get('javascript',sURL);
		
		if (typeof element == 'object' && typeof fSuccess == 'object')
			$TF(element).ready(fSuccess);
		
		return element;
	}
	
	this.ExecuteScripts = function(element) {
		var scripts = element.getElementsByTagName("SCRIPT");
		
		if (scripts.length > 0)
			for (var i=0; i<scripts.length; i++) 
				if (typeof scripts[i].text == 'string')
					eval(scripts[i].text);
	}
	
  this.ExecuteSearch = function(options) {
		// If options.form is a reference to the TFContentUtils object, Use <script> method
		if (typeof TFContentUtils == 'object' && options.form instanceof TFContentUtils)
			return this.grabFile(options.url, options.success);
		
  	options.url = options.url || this.options.url || "";
		
		// Remove filters from parms
		if (options.remove)
			this.removeFilters(options.remove);
		
		if (!this.SearchParms['local']) {
			this.removeFilters(['filter[user_location]','filter[localshoppingdistance]','filter[location]','location']);
		}
		
		// Try our best to reproduce the original search parms
		var	parms = this.RebuildSearchParms(options.form),
				placements = '',
				oParms = {};
		
		// Prevents price from being applied if not used
		if (typeof parms.price != 'undefined' && !thefind.price_on)
			delete parms.price;
		
		options.caller = options.caller || this;
		options.success = options.success || this.fSuccess(options.element);
		
		// Additional parms to be fed, if any
		if (parms)
			for (var key in parms)
				oParms[key] = (key == 'query') ? escape(parms[key]) : parms[key];
		
		if (options.parms) {
			for (var key in options.parms) {
				key = this.setParm(key, options.parms[key]);
				oParms[key] = (key == 'query') ? escape(this.SearchParms[key]) : this.SearchParms[key];
			}
		}
		
		// Update URL hash with filter information
		if (this.urlhash && thefind.utils.isNull(options.ignore_hash))
			thefind.ajax_back_button.update(oParms);
		
		// Placement args tell the server what components to grab data for
		if (!options.placements) {
			var	br = this.bindings.results,
					rp = '';
			
			// we generate the results placements programatically
			// filters are hardcoded for the time being
      rp = this.getActiveBindings(br);
			options.placements = {
				'search.info': 'top',
				'search.filters': 'right,input.search.header.bottom,subheader_bottom',
				'search.results': rp.join(','),
				'page.ads': 'right_middle'
			};
      
    }
		
		if (typeof options.placements == 'object') 
			for (var key in options.placements) 
				placements += '&placements[' + key + ']=' + options.placements[key];
		
		// Do not update the following excluded filters
		if (typeof options.exclude == 'string' || !thefind.utils.isNull(this.SearchParms.location)) {
			var exclude = '&placementoptions[search.filters][right][excludefilters]=';
			
			if (typeof options.exclude == 'string')
				exclude += options.exclude;
			
			if (options.exclude != 'store' && !thefind.utils.isNull(this.SearchParms.location)) 
				exclude += (typeof options.exclude == 'string' ? ',' : '') + 'store';
		}
		
		if (typeof COMSCORE != 'undefined')
			COMSCORE.beacon({ c1: 2, c2: 6309012, c3: "", c4: "", c5: "", c6: "", c15: "" });
		
		if (typeof googleAnalytics != 'undefined') 
			googleAnalytics.updatePageParameters(oParms);
		
		var parms = (typeof oParms == "string" 
			? oParms 
			: thefind.func.stringify_url_parms(oParms));
		
		if (placements)
			parms += placements;
		
		if (exclude)
			parms += exclude;
		
		options.parms = parms;
		
		// FIXME - make this work in IE6, for now it is disabled in IE6
		/*
		if (typeof this.savefilters == 'undefined' && thefind.browser.type+thefind.browser.version != 'msie6') {
			this.savefilters = document.getElementById('tf_search_input_savefilters') || false;
			
			if (this.savefilters)
				this.savefilters.style.visibility = 'visible';
		}
		*/
		
		this.SubmitQuery(options);
		
		return true;
  }
	
	this.SubmitQuery = function(options) {
		ajaxlib.Queue({
			url: options.url, 
			args: options.parms, 
			callback: [ 
				options.caller, 
				options.success 
			],
			failurecallback: [ 
				options.caller, 
				function() { 
					console.log('Results Failure:  Try again'); 
				} 
			],
			timeoutcallback: [ 
				options.caller, 
				function() { 
					console.log('Results Timed Out:  Try again'); 
				} 
			]
		});
	}
	
  this.getActiveBindings = function(br) {
    var rp = [];
    
		for (var p in br) {
      var	ro = br[p].args.options,
          ex = arrayGet(ro, "exclude"),
          ax = ex ? arrayGet(ex, "ajax") : false;
			
      if (!isTrue(ax))
        rp.push(p);
    }
    
		return rp;
  }
	
  this.Init(args);
});

thefind.add('stringify_url_parms', function(parms) {
  var value,ret = '';
  
  for (var key in parms) {
    value = parms[key];
    ret += key + '=' + value + '&'; 
  }
  
  return ret.substr(0,ret.length-1);
});

thefind.add('ajax_submit', function(args) {
	var args = args || {};
	
	args.search = args.search || search || thefind.getSearchObj();
	
	return (args.search)
		? args.search.ExecuteSearch(args)
		: false;
});

thefind.add('scroll_results', function() {
  /* meh -Lazarus
	var	elementid = "tf_container", // FIXME - this should come from the config
			results = document.getElementById(elementid),
			newtop = (results && results.offsetTop > 4)
				? (results.offsetTop - 5)
				: 0;
	*/
	var	scroll = thefind.func.get_scroll(1),
			newtop = document.getElementById('tf_content').offsetTop - 5;
	
	if (scroll > newtop) {
    if (thefind.iphone) {
      thefind.iphone.utils.scrollToY(0);
    } else {
  		$TF(window).scrollTo({ top: newtop }, 0);
    }
  }
});

thefind.add('snap_resize', function(element, args) {
	this.args = args;
	this.ul = element;
	this.r = 0;
	this.x = 0;	
	this.l = 20; // this needs to default to the config search.pagesize
	this.f = true;
	this.mincolumns		= 1;
	this.maxcolumns		= parseInt(args.maxcolumns)	|| 99;
	this.skinny_min		= parseInt(args.mincolumns)	|| 3;
	this.skinny_on		= parseInt(args.autohide) 	|| false;
	this.method				= args.method	|| 'snap';
	this.big_filters	= true;
	this.ie6 = thefind.browser.type + thefind.browser.version == "msie6";
	
	this.init = function() {
		this.id = args.container;
		this.div = document.getElementById(this.args.container);
		this.resultsdiv = $TF('div.tf_layout_column_main')[0];
		
		if (!this.div || !this.ul)
			return;
		
		this.li = thefind.utils.getOnly(this.ul, 'LI');
		this.parent = this.ul.parentNode;
		
		if (!this.li || this.li.length < 1) 
			return;
    
		this.startx = this.li[0].offsetLeft;
		this.cellWidth = this.li.length > 1
			? this.li[1].offsetLeft - this.startx
			: this.li[0].offsetWidth;
		
		if (this.method == 'resize')
			this.method_resize_init();
		else
			this.method_snap_init();
		
		if (!this.args.watch || this.args.watch == 'window') {
			this.watch = document.body;
			addEvent(window, 'resize', this);
		} else {
			this.watch = document.getElementById(this.args.watch);
			addEvent(this.watch, 'resize', this);
		}
		
		if (this.skinny_on)
			if (this.method != 'resize')
				this.method_snap();
	}
  
  this.resize = function(ul) {
		this.ul = ul;
		this.li = thefind.utils.getOnly(this.ul, 'LI');
		
    if (this.method == 'resize')
      this.method_resize();
    else
      this.method_snap();
  }
	
	this.method_resize_init = function() {
		this.get_columns();
		this.method_resize(this.curcolumns);
	}
	
	this.method_snap_init = function(snap) {
		this.set_filter_width();
		this.cw = thefind.func.dimensions(window).w - (this.ie6?20:0);
		
		var realwidth = this.get_columns();
		
		if (!realwidth) 
			return;
		
		this.bodyWidth = realwidth + this.filterwidth + (this.ie6?4:1);
		this.div.style.width = this.bodyWidth + 'px';
	}

	this.method_resize = function(c, init) {
		var	of = this.big_filters,
				mc = this.mincolumns,
				xc = this.maxcolumns,
        sm = this.skinny_min,
        so = this.skinny_on,
				cw = this.cellWidth,
        li = this.li,
				
        w = this.ul.offsetWidth,
				c = Math.floor(w / cw),
				c = c > xc ? xc : c,
				c = c < mc ? mc : c,
				f = c > (sm - (of ? 1 : 0));
		
		delete this.timer;
    
		if (f != of && so && !init && !this.ie6) 
			return this.resize_filters(f);
		
    var	o = thefind.browser.type != 'msie' 
					? 0 : thefind.browser.version == 6 ? .4 : .1,
				
        p = (100 / c) - o;
    
		for (var i = 0; i < li.length; i++)
			li[i].style.width = p + '%';
		
		this.simple_ragged_edge_fix(this.curcolumns = c);
	}
	
	this.method_snap = function(init) {
    if (typeof this.watch != 'object')
      return;
    
		var	ww = this.watch.offsetWidth - (this.ie6?20:0),
				of = this.big_filters,
				fw = this.filterwidth,
				mc = this.mincolumns,
				xc = this.maxcolumns,
				cc = this.curcolumns,
        sm = this.skinny_min,
				ah = this.skinny_on,
				bw = this.bodyWidth,
				cw = this.cellWidth,
				fd = this.filterdiv,
				
				x = Math.floor((ww - bw) / cw),
				x = (xc && (cc + x) > xc) ? (xc - cc) : x,
				f = ww > fw + (sm * cw),
				w;
		
		if (f != of && fd && ah && !init && !this.ie6) 
			return this.resize_filters(f, fd);
		
		x += (x + cc > mc) 
			? 0 : (mc - (x + cc));
		
		w = bw + (x * cw);
		
		if (w != this.w) {
			$TF(this.div).animate({ 
				width: w + 'px' 
			}, 'fast', "easeout");
			
			this.w = w;
		}
		
		this.simple_ragged_edge_fix(cc + x);
	}
	
	this.resize_filters = function(show, fd, init) {
		this.big_filters = show;
		
		var	rd = this.resultsdiv,
				cd = this.contentdiv ? this.contentdiv : this.contentdiv = rd.parentNode;
		
		if (show) {
			delete thefind.autohide;
			
			$TF(cd).removeClass('tf_layout_size_narrow');
			$TF(cd).addClass('tf_layout_size_wide');
			
			if (this.method != 'resize') {
				this.curcolumns--;
				this.bodyWidth += this.fwidth - this.fdwidth;
			}
		} else {
			thefind.autohide = true;
			
			$TF(cd).removeClass('tf_layout_size_wide');
			$TF(cd).addClass('tf_layout_size_narrow');
			
			if (this.method != 'resize') {
				this.curcolumns++;
				
				if (!this.fdwidth) 
					this.fdwidth = fd.offsetWidth;
				
				if (!this.fwidth)
					this.fwidth = fd.offsetWidth;
				
				this.bodyWidth -= this.fwidth - this.fdwidth;
			}
		}
		
		if (this.method == 'resize' && !init)
			this.method_resize(null, true);
		else
			this.method_snap();
	}
	
	this.simple_ragged_edge_fix = function(cc) {
		if (!cc || !this.parent)
			return;
		
		if (!this.ul.parentNode) {
			this.ul = this.parent.getElementsByTagName('UL')[0];
			this.li = $TF('li.tf_search_item', this.ul);
			this.r = 0;
		}
		
		var	li = this.li,
				ol = this.l,
				or = this.r,
				ox = this.x,
				l  = li.length,
				x  = cc * Math.floor(l / cc),
				r  = l - x,
				i;
		
		if (r != or) {
			for (i = l - 1; i > l - or - 1; i--)
				li[i].style.display = 'block';
			
			if (thefind.pagecount == 1) {
				x = ol;
			} else {
				for (i = 1; i <= r; i++) 
					li[l - i].style.display = 'none';
				
				x = cc * Math.floor(ol / cc);
			}
			
			if (x != ox) {
				this.x = x;
				search.SearchParms['settings[search.pagesize.base]'] = x;
				
				$TF.ajax({ 
					url: '/search/settings', 
					type: "POST", 
					cache: false,	
					data: { 
						'settings[search.pagesize.base]': x 
					} 
				});
			}
		}
		
		this.r = r;
	}
	
	this.get_columns = function() {
		for (var i=1,li,x; i<this.li.length; i++) {
			li = this.li[i];
			x = li.offsetLeft;
			
			if (x == this.startx) { 
				this.curcolumns = (i > this.maxcolumns ? this.maxcolumns : i);
				if (this.curcolumns < this.mincolumns)
					this.curcolumns = this.mincolumns;
				
				var realwidth = this.cellWidth * this.curcolumns; 
				break; 
			}
		}
		
		return realwidth;
	}
	
	this.set_filter_width = function() {
		var placements = [ '.tf_layout_column_right', '.tf_layout_columns_left' ];
		
		for (var i=0; i<placements.length; i++) 
			if (this.filterdiv = $TF(placements[i],this.div)[0])
				break;
		
		if (this.filterdiv) {
			if (this.filterwidth = $TF(this.filterdiv).width())
				this.filterwidth += 10;
			
			if (this.filterwidth < 150)
				this.skinny_on = false;
		} else {
			this.filterwidth = 10;
		}
	}
	
	this.handleEvent = function(event) {
		var	event = event || window.event,
				target = event.srcElement || event.target;
		
		switch (event.type) {
			case "click":
				this.mincolumns = 0;
				this.resize();
				this.mincolumns = parseInt(this.args.mincolumns) || 3;
				
				break;
			
			case "resize":
				if (this.method == 'resize') {
					if (!this.timer) {
						(function(self) {
							self.timer = setTimeout(function() {
								self.method_resize();
							},100);
						})(this);
					}
				} else {
					var w = thefind.func.dimensions(window).w;
					
					if (w != this.cw)
						this.method_snap();
					
					this.cw = w;
				}
				
				break;
		}
	}
	
	if (this.method == 'resize') {
		switch (thefind.browser.type) {
			case 'safari':
        (function(self) {
					$TF(document).ready(function() { 
						self.init();
					});
				})(this);
					
				break;
			
			default:
				this.init();
				
				break;
		}
	} else {
		(function(self) {
			$TF(document).ready(function() { 
				self.init();
			});
		})(this);
	}
});
thefind.add('filters', function(parent, args, placement) {
	this.search = parent;
	this.args = args;
	this.filters = [];
	this.placement = placement;
	
	this.Init = function(args) {
		this.id = args.id;
		this.filters = args.filters;
		this.form = document.getElementById(this.id);
		this.ajax = arrayGet(this.args.options,"ajax");
		
		thefind.func.bind(this.form, "submit", this);
		
		for (var name in this.filters)
			if (!thefind.utils.isNull(this.filters[name]))
				this.InitFilter(name, this.filters[name]);
		
		if (arrayGet(this.args, "options.autoscroll.enabled") == 1 && thefind.browser.type != "msie")
			$TF(window).bind("scroll", this, this.HandleScroll);
	}

	this.InitFilter = function(name, filter) {
		var element = $TF("li#tf_search_filters_" + this.placement.replace(/\./g, "_") + "_" + filter.type + "_" + name);
		
		filter.search = this.search;
		filter.formid = this.id;
		
		var type = (name == "pagination")
			? "pagination"
			: (filter.type) 
				? filter.type
				: '';
		
		if (element && thefind.func[type]) {
			if (typeof filter.options != 'undefined')	 {
				var collapsible = !!filter.options.collapsible;
				
				if (collapsible || this.args.options.style == 'accordion') 
					thefind.accordion.add(filter, element);
			}
			
			this.filters[filter.name] = new thefind.func[type](filter, element, this);
		}
	}
	
	this.handleEvent = function(event) {
		var	target = event.target || event.srcElement;
		
		switch (event.type) {
			case "submit": this.HandleSubmit(event,target); break;
		}
		
		event.preventDefault();
	}
	
	this.HandleSubmit = function(event, target) {
		// Local smartmap fix for 2.1
		var checkbox = checkbox = $TF('#tf_search_filters_toggle_localsmartmap_input',target);
		
		if (checkbox && checkbox.length > 0) {
      if (checkbox[0].checked) {
        search.args.query = target['query'].value;
        thefind.local.ClearMarkers();
        thefind.local.AjaxInputRequest(search.args.query,target);
        event.preventDefault();
        return false;
      }
      
      $TF(target).submit();
    }
	}

	this.ValidateFilters = function() {
		var ret = true;
		$TF.each(this.filters, function(k,v) {
			if (typeof v.isApplicable == "function") {
				ret &= v.isApplicable();
			}
		});
		
		return ret;
	}
  
	this.HandleScroll = function(event) {
		var autoscroll = arrayGet(event.data.args, "options.autoscroll");
		
		if (autoscroll != null && autoscroll.enabled == 1 && typeof autoscroll.tiedto != 'undefined') {
			if (typeof event.data.element == 'undefined')
				event.data.element = (this.topelement) 
					? this.topelement 
					: this.topelement = $TF("#"+event.data.id);
			
			if (typeof event.data.autoscrolltiedelement == 'undefined')
				event.data.autoscrolltiedelement = (this.tiedelement) 
					? this.tiedelement
					: this.tiedelement = $TF(autoscroll.tiedto);
				
			var	topelement = event.data.element,
				tiedelement = event.data.autoscrolltiedelement;
				
			if (topelement.length > 0) {
				var	tmp = tiedelement[0].offsetTop,
						bottom = tmp + tiedelement[0].offsetHeight - topelement[0].offsetHeight,
						scroll = window.scrollY || document.documentElement.scrollTop,
						position = "static",
						top = 0,
						margintop = 0;
				
				if (!this.owidth) 
					this.owidth = topelement[0].offsetWidth;
				
				if (scroll > tmp && window.scrollY < bottom) {
					position = "fixed";
				} else if (scroll >= bottom && bottom > 0) {
					position = "static";
					top = 0;
					margintop = tiedelement[0].offsetHeight - topelement[0].offsetHeight;
				}
				
				if (top == this.otop && position == this.oposition) 
					return;
				
				topelement.css({
					position: this.oposition = position, 
					top: (this.otop = top) + "px", 
					width: this.owidth + "px",
					'margin-top': (this.omargin = margintop) + "px"
				});
			}
		}
	}
	
	this.progress = function(mode, total) {
		switch (mode) {
			case 'init':
				if (total) {
					
				}
				
				break;
			case 'pause':
				break;
			case 'resume':
				break;
		}
	}
	
  this.Init(args);
});

thefind.add('accordion', function() {
	this.accordions = {};

	this.handleEvent = function(event) {
		var	target = event.target || event.srcElement;
		
		switch (event.type) {
			case "click": this.toggle(target); break;
		}
		
		event.preventDefault();
	}
	
	this.add = function(filter, element) {
		var	element = element[0],
				accordion = {};
		
		if (!element || !filter) 
			return;
		
		accordion.name = filter.name;
		accordion.collapsed = (!filter.options.collapsed || filter.options.collapsed == "false" || filter.options.collapsed == "0") ? false : true;
		accordion.parent = element;
		accordion.target = element.getElementsByTagName('H2')[0];
		accordion.div = element.getElementsByTagName('DIV')[0];
		
		thefind.func.bind(accordion.target, "click", this);
		
		if (this.accordions[element.id]) {
			for (var key in this.accordions[element.id])
				if (!accordion[key])
					accordion[key] = this.accordions[element.id][key];
			
			this.set_initial_height(accordion);
			return this.accordions[element.id] = accordion;
		} else {
			this.accordions[element.id] = accordion;
		}
		
		var oldheight = element.offsetHeight-2;
		
		element.style.height = '';
		accordion.height = element.offsetHeight;
		element.style.height = oldheight+ 'px';
		
		if (thefind.autohide)
			return;
		
		$TF(accordion.parent).css({ height: '' });
		
		this.set_initial_height(accordion);
	}
	
	this.set_initial_height = function(accordion) {
		if (accordion.collapsed) {
			if (accordion.target) {
				$TF(accordion.parent).css({ 
					height: accordion.target.offsetHeight - 1 + 'px' 
				});
			}
			$TF(accordion.parent).addClass('tf_filters_closed');		
			$TF(accordion.parent).removeClass('tf_filters_open');		
		} else {
			$TF(accordion.parent).addClass('tf_filters_open');
			$TF(accordion.parent).removeClass('tf_filters_closed');		
		}
	}
	
	this.toggle = function(target) {
		if (thefind.autohide)
			return;
		
		var original = target;
		
		while (target) {
			if (typeof this.accordions[target.id] != 'undefined') 
				var key = target.id;
			
			target = target.parentNode;
		}
		
		if (!key)
			return;
		
		while (original) {
			if (this.accordions[key].target == original) 
				var match = this.accordions[key];
			
			original = original.parentNode;
		}
		
		if (!match) 
			return;
		
		height = (match.collapsed) ? match.height : match.target.offsetHeight-1;
		easing = (match.collapsed) ? 'fast' : 'fast';
		if (!match.collapsed) 
			match.height = match.parent.offsetHeight-2;
		
		if (match.collapsed) {
			$TF(match.parent).removeClass('tf_filters_closed');
			$TF(match.parent).addClass('tf_filters_open');
		} else {
			$TF(match.parent).removeClass('tf_filters_open');
			$TF(match.parent).addClass('tf_filters_closed');
		}
		
		$TF(match.parent).animate({ 
			height: height + 'px' 
		}, easing);
		
		match.collapsed = !match.collapsed;
	}
});

thefind.add('accordion', new thefind.func.accordion());

thefind.add('set_pagination', function(pagenum, searchObj) {
	var	pagenum = pagenum || 1,
			searchObj = searchObj || search,
			paginations = searchObj.getBindings('filters', 'pagination');
	
	if (pagenum == this.pagenum)
		return;
	
	if (!pagenum || pagenum < 2) 
		searchObj.removeFilters([ 'page' ]);
	else 
		searchObj.setParm('page', pagenum);
	
	search.SearchParms.page = pagenum;
	for (var i=0; i<paginations.length; i++)
		this.pagenum = paginations[i].setPage(pagenum);
});

thefind.add('set_max_pagination', function(maxpages, searchObj) {
	var	maxpages = (!maxpages) 
				? 1 
				: (maxpages > 50) 
					? 50 
					: maxpages,
			searchObj = searchObj || search,
			paginations = searchObj.getBindings('filters', 'pagination');
	
	for (var i=0; i<paginations.length; i++)
		paginations[i].setMaxPages(maxpages);
	
	thefind.pagecount = maxpages;
});

thefind.add('pagination', function(filter, element) {
	this.filter = filter;
	this.element = element[0];
	this.ajax = (arrayGet(this.filter.options,"ajax") != 0) ? 1 : 0;
	
	this.init = function() {
		if (!this.ajax) 
			return false;
		
		this.ul = this.element.getElementsByTagName('UL')[0];
		
		if (!this.ul) 
			return false;
		
		this.current = (this.getCurrentPage()) 
			? this.getCurrentPage() 
			: 1;
		
		var alinks = $TF('a[name~="pagination_'+filter.placement+'"]');
		for (var i = 0; i < alinks.length; i++) 
			thefind.func.bind(alinks[i].parentNode, "click", this);
		
		this.alinks = alinks;
		if (!this.maxpages && thefind.pagecount)
			this.maxpages = thefind.pagecount;
		
		this.current = this.getCurrentPage();
		this.name = 'pagination_'+filter.placement+'_';
		
		if (thefind.pagecount) {
			this.render(this.current);
		}
	}
	
	this.handleEvent = function(event) {
		var event = event || window.event,
				target = event.srcElement || event.target;
		
		if (target.tagName == 'LI') 
			target = target.getElementsByTagName('A')[0];
		
		switch (event.type) {
			case "click":
        if (target.name) {
  				var tn = target.name.split('_');
	  			var num = tn[3];
		  		var placement = 'paginate_'+tn[1]+'_'+tn[2];
			  	if (typeof googleAnalytics=='object') 
				  	googleAnalytics.trackEvent(['results_page', placement, num]);
        }
				
				thefind.func.set_pagination(num);
				thefind.func.scroll_results();
				thefind.func.ajax_submit();
				
				event.preventDefault();
				event.stopPropagation();
				break;
		}
	}
	
	this.render = function(pagenum) {
		var	ul = this.element.getElementsByTagName('UL')[0],
				max = this.maxpages;
		
		if (!ul)
			return;
		
		thefind.func.ie6_purge(ul);
		ul.innerHTML = '';
		
		if (max == 1)
			return;
		
		this.alinks = [];
		this.min = pagenum - 4;
		this.max = pagenum + 4;
		
		if (this.min < 1) 
			this.min = 1;
		
		if (this.max > max) 
			this.max = max;
		
		if (pagenum > 1) 
			this.addLI(ul,pagenum-1,'< Previous','tf_search_pagination_previous');
		
		if (this.min > 1)
			this.addLI(ul,false,'... ','tf_search_pagination_more');
		
		for (var i=this.min; i<=this.max; i++) {
			if (i > max) return;
			this.addLI(ul,i);
		}
		
		if (i < max) 
			this.addLI(ul,false,'... ','tf_search_pagination_more');
		
		if (pagenum < max)
			this.addLI(ul,pagenum+1,'Next >','tf_search_pagination_next');
		
		this.setCurrentPage(pagenum);
	}
	
	this.setMaxPages = function(max) {
		if (max != this.maxpages) {
			this.maxpages = max;
			
			if (!this.current)
				this.current = 1;
			
			this.render(this.current);
		}
	}
	
	this.setPage = function(num) {
		if (num == this.current && this.maxpages == thefind.pagecount)
			return;
		
		switch (num) {
			case 'next':
				num = (num + 1 < this.maxpages) 
					? num + 1 
					: this.maxpages;
				
				break;
			case 'previous':
				num = (num-1 > 0) 
					? num-1 
					: 1;
				
				break;
		}
		
		if (!this.ul || !num || isNaN(num))
			return;
		
		var	num = parseInt(num);
		
		this.render(num);
		
		return num;
	}
	
	this.setCurrentPage = function(pagenum) {
		var newlink = $TF('a[name~="pagination_'+this.filter.placement+'_'+pagenum+'"]')[0];
		
		if (newlink) 
			newlink.parentNode.className = 'tf_search_pagination_current';
		
		this.current = pagenum;
	}
	
	this.showPreviousButton = function() {
		$TF(this.previous).removeClass('tf_search_pagination_hidden');
	}
	
	this.getNumberPosition = function(num,ul) {
		var	links = ul.getElementsByTagName('A'),
				linknum,link,name,i;
		
		for (i=0; i<links.length; i++) {
			link = links[i];
			linknum = parseInt(link.name.split('_')[3]);
			
			if (num == linknum) 
				return i;
		}
	}
	
	this.createPageNumber = function(num,label,css) {
		var newli = document.createElement('LI');
		var label = label || num;//+'&nbsp';
		
		if (css) 
			newli.className = css;
		
		if (num === false) {
			newli.innerHTML = label;
		} else {
			if (!this.url) {
				this.url = search.generate_url({ page: true });
				(function(self) {
					setTimeout(function() { delete self.url; },100);
				})(this);
			}
			
			var	link = document.createElement('A');
			
			newli.appendChild(link);
			link.innerHTML = label;
			var delimeter = (indexOf(this.url,'?') <= 0) ? '?' : '&';
			link.href = this.url + delimeter + 'page=' + num;
			link.name = this.name + num;
			link.rel = 'nofollow';
			addEvent(link.parentNode,"click", this);
			this.alinks[num] = link;
		}
		
		return newli;
	}
	
	this.addPageNumber = function(toggle,ul,remli) {
		var num = (toggle) ? --this.min : ++this.max;
		var newli = this.createPageNumber(num);
		
		thefind.func.ie6_purge(remli);
		ul.removeChild(remli);
		
		if (toggle) {
			this.max--;
			ul.insertBefore(newli,ul.firstChild);			
		} else {
			this.min++;
			ul.appendChild(newli);
		}
	}
	
	this.addLI = function(ul,num,label,css) {
		li = this.createPageNumber(num,label,css);
		ul.appendChild(li);
	}
	
	this.getCurrentPage = function() {
		var SearchParm = arrayGet(filter.search.SearchParms,"filter[pagenum]"),
				SearchArg = arrayGet(filter.search.args.filter,"pagenum"),
				pagenum = (SearchParm)
					? SearchParm
					: (SearchArg)
						? SearchArg
						: 1;
		
		return parseInt(pagenum);
	}
	
	this.init();
});

thefind.add('filtergroup', function(filter, element) { 

});

thefind.add('input', function(filter, element) {
	this.filter = filter;
	this.element = element;
	
	this.init = function() {
		var input = this.element.find("input");
		if (input.length > 0) {
			this.input = input[0];
			addEvent(this.input, "focus", this);
			addEvent(this.input, "blur", this);
		}
	}
	this.handleEvent = function(event) {
		if (event.type == "focus") {
			if ($TF(this.input).hasClass("tf_utils_state_default")) {
				this.input.value = "";
				$TF(this.input).removeClass("tf_utils_state_default");
			}
		} else if (event.type == "blur") {
			if (this.input.value == "" && !$TF(this.input).hasClass("tf_utils_state_default")) {
				$TF(this.input).addClass("tf_utils_state_default");
				this.input.value = this.filter.options.defaultvalue;
			}
		}
	}
	
	this.init();
});


thefind.add('component', function(filter, element) { 

});

thefind.add('list', function(filter, element) {
	this.filter = filter;
	this.element = (element.length >= 1) ? element[0] : element;
	
	if (filter.formid == "tf_search_filters_popup")
		if (filter.name == 'store' || filter.name == 'brand')
			if (element = $TF("#tf_infobox_" + filter.name + "_autohide_popup")[0])
				this.element = element;
	
	this.convert_whitelist_properties = function() {
		var whitelist = this.filter.options.item_whitelist.split(',');
		
		if (this.filter.options.items) {
			for (var i=0; i<this.filter.options.items.length; i++) {
				var	item = this.filter.options.items[i],
						new_item = {};
				
				for (var a=0; a<item.length; a++) {
					new_item[whitelist[a]] = item[a];
				}
				
				this.filter.options.items[i] = new_item;
			}
		}
	}
	
	this.init = function() {
		//if (filter.options.item_whitelist)
		//	this.convert_whitelist_properties();
		
		//console.log(this.filter.name, this.filter);
		var options = this.filter.options, show = options.show;
		
		if (thefind.utils.isNull(options.show))	options.show	= show = {};
		if (thefind.utils.isNull(show.title))		show.title		= 1;
		if (thefind.utils.isNull(show.top))			show.top			= 1;
		if (thefind.utils.isNull(show.checked))	show.checked	= 1;
		if (thefind.utils.isNull(show.more))			show.more			= 1;
		if (thefind.utils.isNull(show.count))		show.count		= 0;
		if (thefind.utils.isNull(show.info))			show.info			= 0;
		if (thefind.utils.isNull(show.all))			show.all			= 0;
		if (thefind.utils.isNull(show.ratings))	show.ratings	= 0;
		
		var filteroptions = { 
			show: {all: 1, label: 1},
			collapsed: 0
		};
		
		var filterlist;
		if (typeof this.filter.options.popupfilters == "string" && this.filter.options.popupfilters.length > 0) {
			filterlist = this.filter.options.popupfilters;
		} else {
			filterlist = "query," + this.filter.name;
		}
		
		if (arrayGet(this.filter.options.show,'local')) {
			this.tabs = document.getElementById('tf_search_filters_list_store_tabs');
			
			if (this.tabs) {
				var lis = this.tabs.getElementsByTagName('li');
				this.control = document.getElementById('tf_search_filters_list_store_control');
				
				for (var i=0; i<lis.length; i++) {
					if (thefind.utils.hasClass(lis[i], 'selected'))
						this.selected = lis[i];
					
					var link = lis[i].getElementsByTagName('a')[0];
					
					if (link) {
						addEvent(link,"click",this);
						if (typeof googleAnalytics=='object') {
							$TF(lis[i]).click(function() {
								var tab = '';
								if (/^All/.test($TF(this).html())) tab= 'All Stores';
								if (/^Local/.test($TF(this).html())) tab= 'Local Stores';
								if (tab) googleAnalytics.trackEvent(['filter', tab, 'tab']);
							});
						}
					}
				}
			}
		}
		
		var pickerfilter = {  
			tracking: {name:this.filter.name}, //will appear in args.tracking.name?
			'search': this.filter.search,
			options: {
				component: "search.filters",
				width: this.filter.options.popupwidth || '20em',
				popuplabel: (arrayGet(this.filter.options,"popuplabel") || false),
				componentargs: {
					filters: filterlist,
					filteroptions: thefind.JSON.stringify(filteroptions),
					placement: this.filter.placement,
					id: "tf_search_filters_popup",     
					targetid: (this.filter.options.targetid) ? this.filter.options.targetid : "infoBoxContent",
					closebutton: false,
					sname: this.filter.search.name
				}
			}
		};
		var pickerlink;
		if (this.filter.options.show.top == true && this.filter.options.show.more == true) {
			pickerlink = $TF('<li><a href="#" class="tf_search_filters_types_list_morelink" name="search_filter_'+this.filter.placement+'_'+this.filter.name+'_more">More...</a></li>');
			$TF(this.element).find("ul").append(pickerlink);
		} else if (this.filter.options.show.top == false || this.filter.options.show.top == 0) {
			var filterlabel = $TF(this.element).find("h2").html();
			if(this.filter.placement != "popup") {
				if (this.filter.name == 'store') {
					pickerlink = this.element;
				} else {
					pickerlink = $TF('<span><a href="#" class="tf_search_filters_types_list_morelink" name="search_filter_'+this.filter.placement+'_'+this.filter.name+'">' + filterlabel + '</a></span>');
					$TF(this.element).find("h2").html(pickerlink);
				}
			}
		}
		
		this.initEvents();
		this.check_previously_checked();
		thefind.func.bind($TF("select.tf_search_filters_list_sort",this.element)[0],"change",this);
		
		if (pickerlink && !$TF(pickerlink).hasClass('tf_infobox_popup'))
			this.picker = new thefind.func.picker(pickerfilter, pickerlink);
	}
	
	this.isApplicable = function() {
		return true;
	}
	
	this.check_previously_checked = function() {
		var values = search.SearchParms[this.filter.name];
		
		if (values) {
			var values = values.split(','), checkbox;
			
			for (var i=0; i<values.length; i++) {
				checkbox = $TF('input[value='+values[i]+']',this.element);
				
				if (checkbox.length > 0) 
					checkbox[0].checked = true;
			}
		}
	}
	
	this.initEvents = function() {
		if (arrayGet(this.filter.options.show,'localtab'))
			return;
		
		var	filter = this.filter;
		
		if (filter.placement == 'popup' && filter.name == 'brand')
			this.element = document.getElementById('tf_search_filters_right_list_brand_container');
		
		if (!!this.filter.options.show.multiselect) {
			(function(self) {
				$TF(self.element).find("input:checkbox").each(function(k, v) {
					addEvent(v.parentNode, "click", self); //(DDW: parentNode is an li element)
				});
			})(this);
		}
	}
	
	this.ajaxlibSubmit = function(filter,targetid) {
		thefind.func.ie6_purge(this.control);
		this.control.innerHTML = '';
		
		var ajaxrequest = {
			method: "GET", 
			url: "/" + "search.filters".replace(".", "/"),
			args: 'closebutton=false'
				+ '&filteroptions={"qid":"' + search.args.id + '"}'
				+ '&filters=query,' + filter
				+ '&id=tf_search_filters_popup'
				+ '&placement=' + filter.placement || 'popup'
				+ '&searchrequest={ "query":"' + search.args.query + '","filter":null }'
				+ '&targetid=' + targetid
		};
		
		ajaxlib.Queue(ajaxrequest); 
		ajaxlib.Go();
	}
	
	this.toggle = function(target) {
		while (target && target.tagName != 'LI') {
			target = target.parentNode;
			
			if (target.tagName == 'LI') 
				break;
		}
		
		if (!$TF(target).is('li.selected')) {
			var element = this.element = this.control.parentNode.parentNode;
			if (target == target.parentNode.getElementsByTagName('li')[0]) {
				this.update_header('Products', true);
				
				thefind.func.set_pagination();
				thefind.func.ajax_submit({ 
					search: search,
					remove: [
						'localshopping',
						'localshoppingdistance',
						'user_location',
						'location',
						'local',
						'store'
					],
					parms: { 
						'local':'0' 
					}
				});
				
				if (element) 
					$TF(element).animate({ height: 24.5+'em' }, "fast");
				
				thefind.func.ie6_purge(this.control);
				this.control.innerHTML = '<p class="tf_search_filters_topstore_spinner"><img src="/images/misc/ajax-loader-transparent.gif" title="Loading..."></p>';
				if (this.innerHTML) {
					//this.control.innerHTML = this.innerHTML;
					this.initEvents();
				}
			} else {
				this.update_header('Local', true);
				
				thefind.func.set_pagination();
				
				thefind.func.ajax_submit({
					search: search,
					remove: [ 'store' ],
					parms: { 'local': '1' }
				});  
				
				if (element) {
					var height = this.oldheight = element.offsetHeight;
					$TF(element).animate({ height: 40.5+'em' }, "fast");
					this.element.style.maxHeight = 'none';
					thefind.func.ie6_purge(this.control);
					this.control.innerHTML = '<p id="tf_ajax_spinner" class="tf_results_ajax_spinner"><img src="/images/misc/ajax-loader-transparent.gif" title="Loading..."></p>';
				}
			}
			$TF(this.selected).removeClass('selected');
			$TF(target).addClass('selected');
			this.selected = target;
		}
	}
	
	this.update_header = function(type, no_submit) {
		var inputs = thefind.search().bindings.input;
		
		for (var input in inputs)
			inputs[input].universal_header_change(type, no_submit);
	}
	
	this.handleEvent = function(event) {
		if (!event) event = window.event;
		var target = this.target = event.srcElement || event.target;
		
		if (target.tagName == 'LABEL') 
			return false; // for some reason LABEL event gets generated twice???
		
		switch(event.type) {
			case 'click': 
				if ($TF(target).hasClass("tf_search_item_actions_savestoreinmyfinds_link") || $TF(target).hasClass("tf_search_item_actions_savebrandinmyfinds_link")) {
					this.handleClickSave(event, target);
					break;
				}
				
				while (target && target.tagName != 'UL') {
					target = target.parentNode;
					if (target.tagName == 'UL') break;
				}
				
				if (target == this.tabs) {
					this.toggle(this.target);
					event.preventDefault();
				} else
					this.handleClick(event,target); 
				
				break;
			case 'change': 
				this.handleChange(target); 
				
				break;
		}
	}
	
	this.handleClickSave = function(event, target) {
		var	name = this.filter.name,
				items = this.filter.options.items,
				action = $TF(target).hasClass("tf_state_selected") ? 'delete' : 'add',
				target_id = target.id.replace(name == 'store' ? /^tf_filter_store_/ : /^tf_filter_brand_/, ""),
				item_id, item, i;
		
		for (i = 0; i < items.length; i++) 
			if ((name == 'store' ? items[i].siteId : items[i].value.replace(" ", "_")) == target_id) 
				item_id = i;
		
		if (item = items[item_id]) {
			(action == 'add')
				? $TF(target).toggleClass("tf_state_selected") 
				: $TF(target).removeClass("tf_state_selected");
			
			url	= "myfindsaction=" + action + "saved" + name	+ "&target=myfindspanel&query=" +	search.args.query + "&" + name + "=" + item.value;
			queueXHR(url + (name == 'store' ? '&storeid=' + item.siteId + '&storecname=' + item.sitecname : ''));
		}
		
		event.preventDefault();
	}
	
	this.handleClick = function(event,ul) {
		var gaFilter = this.filter.name,
				filtername = "filter[" + this.filter.name + "]",
				form = this.target.form,
				checkbox = (this.target.tagName != 'INPUT') 
					? this.target.getElementsByTagName('input')[0] 
					: this.target,
				stores = '',
				name = this.filter.options.argname || 'filter['+(this.filter.name || '')+']';
		
		if ($TF(checkbox).hasClass("tf_search_filters_list_selectall_checkbox")) {
			var inputs = this.element.getElementsByTagName('input');
			if (typeof googleAnalytics!='undefined') googleAnalytics.trackEvent(['filter', gaFilter, '0']);
			$TF("input:checkbox:checked", ul).each(function(v, k) { 
				if (k !== checkbox)
					k.checked = !k.checked; 
			});
			
			thefind.func.set_pagination();
			thefind.func.ajax_submit({
				remove: [ this.filter.name ],
				search: search
			});
			return false;
		}
		
		if (!name) 
			return false;
		
		if (this.timer) 
			clearInterval(this.timer);
		
		var gaCount=0;
		
		(function(self) {
			self.timer = setTimeout(function() {
				$TF("input:checkbox:checked", ul).each(function(v, k) { 
					stores += k.value + ',';
					gaCount++;
				});
				
				var	parms = {},
						args = {
							search: search,
							parms: parms
						};
				
				if (stores.length > 0) {
					args.exclude = name == 'store' ? 'storegroup' : name;
					args.parms[name] = stores.substr(0,stores.length-1);
				} else { 
					args.remove = [ name ];
				}
				if (typeof googleAnalytics!='undefined') googleAnalytics.trackEvent(['filter', gaFilter, gaCount]);
				thefind.func.set_pagination();
				thefind.func.scroll_results();
				thefind.func.ajax_submit(args);
				delete self.timer;
			}, 1750);
		})(this);
		
		if (this.target.tagName != 'INPUT') {
			if (checkbox) 
				checkbox.checked = !checkbox.checked;
		}
	}
	
	this.handleChange = function(target) {
		this.sortBy(target.value);
	}
	
	this.sortBy = function(sortby) {
		var items = this.filter.options.items;
		var sorted = [];
		
		var order = (sortby == "value" ? 1 : -1);
		var numeric = (parseFloat(items[0][sortby]) == items[0][sortby]);
		items.sort(function(a, b) { 
			var ret;
			if (numeric) {
				ret = a[sortby] - b[sortby];
			} else {
				var alower = a[sortby].toLowerCase();
				var blower = b[sortby].toLowerCase();
				if (alower == blower) ret = 0;
				else ret = (alower < blower ? -1 : 1);
			}
			return ret * order;
		});
		
		var containerul = $TF(this.element).find("ul");
		var sortkey = this.filter.options.sortkey || "value";
		var lis = $TF(containerul).find("li input:checkbox");
		var unsortedlis = {};
		lis.each(function(k, v) {
			unsortedlis[v.value] = v.parentNode;
			thefind.func.ie6_purge(v.parentNode);
			v.parentNode.parentNode.removeChild(v.parentNode);
		});
		$TF.each(items, function(k, v) {
			if (unsortedlis[v[sortkey]])
				containerul[containerul.length-1].appendChild(unsortedlis[v[sortkey]]);
		});
	}
	
	this.init();
});

thefind.add('picker', function(filter, element) {
	// COLOR, BRAND, STORE pickers
	this.filter = filter;
	this.element = element;
	
	this.init = function() {
		var args = {}
		args.width		= (this.filter.options.width			? this.filter.options.width		: "20em");
		args.delay		= (this.filter.options.delay 		? this.filter.options.delay		: 0);
		args.sticky		= (this.filter.options.sticky		? this.filter.options.sticky		: true);
		args.absolute	= (this.filter.options.absolute	? this.filter.options.absolute	: true);
		args.close		= true;
		
		// make sure element is the li
		var element = this.element[0];
		while (element) {
			if (element.tagName == 'LI') break;
			element = element.parentNode;
		}
		
		if (element) 
			this.element = [ element ];
		
		if (this.filter.options.content) {
			args.content = this.filter.options.content;
		} else if (this.filter.options.component) {
			args.content = '<img src="/images/misc/ajax-loading-black-on-white.gif" alt="Loading..." class="tf_utils_ajax_loading" />';
			args.ajaxrequest = {
				element: this.element.id, 
				method: "GET", 
				url: "/" + this.filter.options.component.replace(".", "/") 
			};
			args.ajaxrequest.args = (this.filter.options.targetid) ? "targetid=" + this.filter.options.targetid + "&" : "";
			
			var componentargs = this.filter.options.componentargs || {},
					exclude = [ 'filter','settings','extrafilters','filter[categoryorder]','filter[qpcookie]' ];
			if (typeof search != 'undefined') {
				var tmp = {};
				
				for (var key in search.request)
					if (indexOf(exclude,key) < 0) 
						tmp[key] = search.request[key];
				
				for (var key in search.SearchParms)
					if (indexOf(exclude,key) < 0) 
						tmp[key] = search.SearchParms[key];
				
				componentargs.searchrequest = thefind.JSON.stringify(tmp);
			}
			
			if (!thefind.utils.isNull(this.filter.placement)) 
				componentargs.placement = this.filter.placement;
			
			if (componentargs) {
				var glue = "";
				$TF.each(componentargs, function(k, v) {
					args.ajaxrequest.args += glue + k + "=" + v;
					glue = "&";
				});
			}
			
			var inputs = document.getElementsByTagName('input');
			
			for (var i=0; i<inputs.length; i++) 
				var input = inputs[i];
		}
		
		var	filter = this.filter,
				tracking = filter.tracking, 
				id = any(arrayGet(filter.options,"targetid"), arrayGet(filter.options.componentargs,"targetid"), "infoBoxContent"),
				popup = (id == "infoBoxContent") ? true : false,
				obj = (id) ? document.getElementById(id) : false,
				h2 = $TF(this.element).find("H2")[0],
				register_infobox;
		
		if (h2 && popup) 
			thefind.infobox.add(
				(filter.name || arrayGet(tracking,"name")) + '_popup', { 
					event: 			args.event 			|| "click", 
					sticky:		 	args.sticky 		|| false,
					titlebar:		args.close			|| false,
					width: 			args.width 			|| false,
					absolute:		args.absolute		|| false,
					nocache: 		args.nocache		|| true,
					ajax: 			args.ajax				|| true,
					margin: 		args.margin 		|| 20
				},
				args.ajaxrequest.args, 
				args.ajaxrequest.url, 
				h2
			);
		
		(function(self) {
			register_infobox = function(target,name,local) {
				label = arrayGet(self.filter.options,"popuplabel") || filter.name || arrayGet(tracking,"name");
				
				if (local)
					label = arrayGet(self.filter.options,"popuplabel_local") || "Local Stores";
				
				thefind.infobox.add(
					name, { 
						event: 			args.event 			|| "click", 
						sticky:		 	args.sticky 		|| false,
						absolute:		args.absolute		|| false,
						nocache: 		args.nocache		|| true,
						ajax: 			args.ajax				|| true,
						classname:	'tf_infobox_popup',
						width: 			'25em',
						border:			'div',
						scrollTop:	false,
						tail:				false,
						reposition: false,
						resizeclose:true,
						titlebar:		true,
						label: label
					}, 
					liargs, 
					args.ajaxrequest.url, 
					target
				);
			};
		})(this);
		
		var li = $TF('ul.tf_search_filters_autohide_tabs li', this.element)[0];
		var liargs = changeStringArrayProperty(args.ajaxrequest.args,'&','targetid','tf_infoBoxContent');
		
		if (li) {
			register_infobox(li,(filter.name || arrayGet(tracking,"name")) + '_autohide_popup');
			
			if ($TF(li).next().length > 0) {
				liargs += "&sitecfg[search.filters.placements.right.storegroup.filteroptions.store.show.localtab]=1";
				register_infobox($TF(li).next()[0],(filter.name || arrayGet(tracking,"name")) + '_local_autohide_popup',true);
			}
		}
		
		(function(self) {
			$TF(h2).bind("click", self, function(ev) {
				if (!popup && args.ajaxrequest && !thefind.autohide && obj && obj.childNodes.length <= 1) {
					var id = any(arrayGet(self.filter.options, "targetid"), arrayGet(self.filter.options.componentargs, "targetid")),
							el = document.getElementById(id);
					
					args.ajaxrequest.args += "&qid=" + thefind.search().id;
					thefind.func.ie6_purge(el);
					el.innerHTML = '<p id="tf_ajax_spinner" align="center" style="margin-top:5em;"><img class="tf_results_ajax_spinner" src="/images/misc/ajax-loader-transparent.gif" title="Loading..."></p>';
					ajaxlib.Queue(args.ajaxrequest); 
				}
			});
		})(this);
	}
	
	this.init();
});

thefind.add('toggle', function(filter, element) {
	this.filter = filter;
	this.element = element[0];
	
	this.init = function() {
		if (this.element) {
	    //thefind.func.add_location([ '{$city|capitalize}', '{$state|capitalize}' ]);
			this.input = $TF(this.element).find("input[type='checkbox']")[0];
			this.hidden = $TF(this.element).find("input[type='hidden']")[0];
			this.form = this.element;
			
			while (this.form) {
				if (this.form.tagName == 'FORM')
					break;
				
				this.form = this.form.parentNode;
			}
			
			thefind.func.bind(this.input, "click", this);
			
			this.setHiddenState();
		}
	}
	
	this.handleEvent = function(event) {
		if (!event) event = window.event;
		var target = this.target = event.srcElement || event.target;
		
		switch(event.type) {
			case 'click': 
				if (this.filter.options.nosubmit == "1") 
					return false;
				
				this.setHiddenState();

				cm = new TFHtmlUtilsCoremetrics();
				cm.params = [
					(arrayGet(this.filter, "filter.search.request.extrafilters.hidden.log_url") || window.location.href),
					this.filter.formid + '_' + this.filter.name,
					""
				];
				
				cm.create("ManualLinkClick");
				
				var remove = (this.filter.name == "localtoggle")
					? [	
							'localshopping',
							'localshoppingdistance',
							'user_location',
							'location',
							'local'
						]
					: [
							this.filter.name
						];
				
				if (this.filter.options.remove) {
					var removes = this.filter.options.remove.split(',');
					
					for (var a = 0; a < removes.length; a++) {
						var	filters = search.getBindings('filters',removes[a]);
						
						for (var i = 0; i < filters.length; i++) {
							var el = filters[i].element;
							
							$TF("input:checkbox:checked", el).each(function(v,k) { k.checked = !k.checked; });
						}
						
						remove.push(removes[a]);
					}
				}
				
				var args = {
					form: 		this.form,
					exclude:	filter.name == 'store' ? 'storegroup' : filter.name,
					remove:		remove,
					search:		search
				};
				
				thefind.func.set_pagination();
				thefind.func.scroll_results();
				thefind.func.ajax_submit(args);
				
				break;
		}
	}
	
	this.setHiddenState = function() {
		if (this.hidden) {
			if (this.input.checked) {
				this.hidden.disabled = true;
			} else {
				this.hidden.disabled = false;
			}          
		}
	}
	this.init();
});

thefind.add('radio', function(filter, element) {
	this.filter = filter;
	this.element = element;

	this.init = function() {
		var radios = element.find("input[type=radio]");
		for (var i = 0; i < radios.length; i++) {
			addEvent(radios[i], "click", this);
		}
	}

	this.handleEvent = function(ev) {
		ev = thefind.utils.fixEvent(ev);
		var target = (ev.srcElement || ev.target);
		$TF(target.form).submit();
	}

	this.init();
});

thefind.add('select', function(filter, element) {
	this.filter = filter;
	this.element = element;

	this.init = function() {
		if (this.element)
			$TF(this.element).find("select").bind("change", this, function(ev) {
				thefind.func.ajax_submit({ parms: { page: 1 }, form: this.form });
			});
	}
	
	this.init();
});

thefind.add('range', function(filter, element, parent) {
	this.filter = filter;
	this.parent = parent;
	this.element = element[0];
	var element = this.element;
	while (element && element.tagName != 'FORM') 
		element = element.parentNode;		
	
	this.form = element;
	this.h = filter.options.histogram;
	this.browser = thefind.browser.type;
	this.c = thefind.utils.getElementsByClassName(document,'div','tf_priceslider_container')[0];
	this.zoomed = (this.h && (this.h.percentMin) && (this.h.percentMax));
	this.pbbool = true;
	this.sliding = false;
	this.handle = false;
	this.b0rked = false;
	this.pmin = 0;
	this.pmax = 0;
	this.itemcount = 0;
	this.res = 1;
	this.countmax = 0;
	this.color1 = [255,255,255];
	this.color2 = [0,170,0]
	var color = filter.options.color;
	this.color2 = (typeof color == 'array' ? color : (typeof color == 'string' ? hex2rgb(color) : [0,170,0]));
	this.gbda = [];
	this.bucketpos = [];
	this.oldpos = {};
	this.oldpos.l = 0;
	this.oldpos.r = 0;
	this.timer;
	this.handlehalf;
	this.display = true;
	this.lastdraw = 0;
	this.fps = [20, 20, 20, 20, 20];
	this.renderiter = 1;
	this.renderlooplength = 10;
	this.fpson = false;
	this.symbol = any(arrayGet(this, "filter.options.currency.symbol"), "$");
	if (this.symbol == '&pound;') this.symbol = String.fromCharCode(163);

	this.GenBuckets = function(num) {
		this.b0rked = true;
		var countmax = 0;
		if (this.h.buckets)
			for (i=0;this.h.buckets[i];i++) { countmax += this.h.buckets[i][0]; }
		iteration = 1;
		step = (this.h.displayMax - this.h.displayMin) / num;
		countstep = (countmax / num);
		var buckets = [];
		start = this.h.displayMin;
		while(num > 0) {
			end = start + (step);
			count = countstep * iteration;
			var newbucket = [];
			newbucket[1] = Math.round(start);
			newbucket[2] = Math.round(end);
			newbucket[0] = countstep;
			buckets.push(newbucket);
			start = end;
			num--;
			iteration++;
		}
		this.h.buckets = buckets; 
	}
	
	this.Create = function() {
		if (this.fpson) {
			this.log = document.createElement('span');
			this.log.className = "performanceTest";
			document.body.appendChild(this.log);
		}
		if (this.h) {
			if (this.h.count <= 2) 
				this.GenBuckets(10);
			
			scaleRangeIndex = 0;
			
			this.scaleRange = [];
			
			var oldPriceRange = 0;
			
			for (i=0;this.h.buckets[i];i++) {
				var	bucket = this.h.buckets[i]; 
						curPriceRange = bucket[2] - bucket[1];
				
				if (bucket[0] > this.countmax) 
					this.countmax = bucket[0]; 
				
				if (curPriceRange != oldPriceRange) 
					scaleRangeIndex++;
				
				this.scaleRange[scaleRangeIndex] = this.countmax;
				
				var oldPriceRange = curPriceRange;
			}
			
			var	divs = ['pcd','phdmin','phdmax','pbga','pbgs'],
					cn = ['cover','handle','handle','bargraph_area','bargraph_span'],
					ce;
			
			(function(self) {
				ce = function(key, classname) {
					self[key] = document.createElement('div');
					self[key].className = 'tf_priceslider_' + classname;
					self.c.appendChild(self[key]);
				};
			})(this);
			
			for (var i=0; i<divs.length; i++)
				ce(divs[i], cn[i]);
			
			this.pcd.style.background = rgb2hex(this.color1);
			
			// this is the code that used to init from filter_range.tpl
			// price min and max events are handled by handleEvent(). Seems this function no longer needed
			this.googleAnalytics_init();
		}
	}
	
	this.googleAnalytics_init = function() {
		for (var sides=['min','max'], side, i=0; i < sides.length; side = sides[i++])  
			$TF("input.tf_moreoptions_textbox" + side + '_2').change(function() {
				if (typeof googleAnalytics != 'undefined') 
					googleAnalytics.trackEvent(['filter', 'price', side ]); 
			});
	}
	
	this.RenderPrePrep = function(obj) {
		obj.DeleteDivArray(obj.graphbarDivArray, obj.PriceSliderCoverDiv);
		obj.graphbarBucketArray.length = 0;
		obj.graphbarDivArray.length = 0;
		obj.bucketpos.length = 0;
		obj.RenderHistogram(obj.PriceSliderCoverDiv, obj.histogram);
		obj.resizeTimer = null;
	}
	
	this.RenderPrep = function(gc) {
		if (this.zoomed) 
			if ((this.h.percentMin == 0) && (this.h.percentMax == 0))
				this.zoomed = false;
		
		this.sw = gc.offsetWidth - 4;
		
		if (this.zoomed) {
			this.h.displayMin = this.h.buckets[0][1];
			this.h.displayMax = this.getmaxbp();
			var totalmargin = this.sw;
			this.ml = ((totalmargin * (this.h.percentMin/2)) / 100);
			this.mr = ((totalmargin * (this.h.percentMax/2)) / 100);
			for (index=0; index < this.ml; index++) {
				var gb = document.createElement("div");
				gb.className = "tf_priceslider_graph_bar";
				gb.style.width = "1px";
				gb.style.background = rgb2hex(this.color1);
				gc.appendChild(gb);
				this.gbda.push(gb);
			}
			
			this.drawCurtains(this.ml,this.mr); 
			this.showCurtains("visible");
			this.sw = this.sw - (this.ml + this.mr);
		}
	}
	
	this.RenderHistogram = function(gc) {
		this.RenderPrep(gc);
		
		var barw = (this.sw / this.h.buckets.length);
		
		if (barw == Math.floor(barw)) 
			this.res = Math.floor(barw)-1;
		else 
			this.res = Math.floor(barw); 
		
		var	histw = this.h.buckets.length * this.res - 1,
				barw = this.sw / histw,
				barwf = Math.floor(barw),
				barwr = this.sw - histw,
				wstep = histw / barwr,
				wstepf = wstep,
				wstepr = Math.abs(wstep - wstepf),
				totalest = 1,
				ogbp = 0,
				scale = 0,
				left = 1,
				width = gc.offsetWidth-2,
				rangeavg = this.h.absMax / histw;
		
		for (var i in this.h.buckets) {
			if (!this.h.buckets.hasOwnProperty(i)) 
				continue;
			
			var	bucket = this.h.buckets[i],
					pricerange = bucket[2] - bucket[1],
					curNum = bucket[2] - bucket[1];
			
			if (curNum != oldNum) 
				scale++;
			
			var cgbp = ((bucket[0] / this.scaleRange[scale]) * 100);
			
			if (isNaN(cgbp)) 
				cgbp = 100;
			
			var	interval = (ogbp - cgbp) / this.res,
					leftp = 0;
			
			for (gbi=1; gbi <= this.res; gbi++) {
				var	gb = document.createElement("div"),
						percent = (100 / this.h.count) / this.res,
						it = (i * this.res) + gbi,
						barwidth = barwf,
						tmp = totalest * wstep,
						ngbch;
				
				if ((tmp >= it) && (tmp < (it + 1))) {
					totalest++; 
					barwidth++;
				}
				
				cgbp = ogbp - (interval * gbi);
				leftp = (left / width) * 100;
				left += barwidth;
				
				gb.className = "tf_priceslider_graph_bar";
				gb.style.width = (barwidth / (width-3)) * 100 + "%";
				gb.style.left = leftp + '%';
				gb.style.background = rgb2hex(this.BlendColor(cgbp));
				
				var label = this.symbol + parseInt(bucket[1]) + " - " + this.symbol + parseInt(bucket[2]);
				gb.title = label + ": " + parseInt(bucket[0]) + " products";
				gc.appendChild(gb);
				this.gbda.push(gb);
			}
			
			if ((bucket[1] > this.h.displayMin) && (!this.minPos)) 
				this.minPos = i;
			
			if ((bucket[2] > this.h.displayMax) && (!this.maxPos)) 
				this.maxPos = i;
			
			this.bucketpos.push(leftp);
			var	ogbp = cgbp,
					oldNum = curNum;
		}
		
		this.SetDimensions();
	}
	this.SetDimensions = function() {
		var dim = thefind.func.dimensions(this.pcd);
		this.sx = dim.x;
		this.sy = dim.y;
		this.sw = dim.w;
		this.sh = dim.h;
		this.handlew = this.phdmin.offsetWidth;
		this.handleh = this.phdmin.offsetHeight;
		this.handlehalf = this.handlew / 2;
		if (this.minb.value == this.maxb.value) {
			this.SetMinPos(0);
			this.SetMaxPos(99999999);
		}
		else {
			this.SetMinPos(this.minb.value);
			this.SetMaxPos(this.maxb.value);
		}
	}
	this.SetEvents = function(event) {
		addEvent(this.minb, "keyup", this);
		addEvent(this.maxb, "keyup", this);
		addEvent(this.phdmin, "mousedown", this);
		addEvent(this.phdmax, "mousedown", this);
		addEvent(this.pcd, "mousedown", this);
		addEvent(this.pb, "click", this);
		addEvent(this.form, "submit", this);
	}
	
	this.handleEvent = function(event) {
		var event = event || window.event;
				target = event.srcElement || event.target;
		
		switch (event.type) {
			case "click":
				if (this.collapse(target)) return;
				if (this.submitted) return;
				sptbParm1 = this.symbol+this.pmin;
				sptbParm2 = this.symbol+this.pmax;
				if (this.b0rked) {
					if ((this.pmin > this.h.displayMin) && (this.pmax < this.h.displayMax)) {
						sptbParm1 = this.symbol+this.h.displayMin;
						sptbParm2 = this.symbol+this.h.displayMax;
					}
				}
				if (this.h.absMin) {
					sptbParm3 = this.h.absMin;
					sptbParm4 = this.h.absMax;
				} else {
					sptbParm3 = this.h.buckets[0][1];
					sptbParm4 = this.getmaxbp();
				}
				//console.log(sptbParm1+' '+sptbParm2+' '+sptbParm3+' '+sptbParm4+' '+this.h.displayMin+' '+this.h.displayMax+' '+this.h.absMin+' '+this.h.absMax)
				this.SetPriceTxtBox(sptbParm1,sptbParm2,sptbParm3,sptbParm4);
				return true;
			
			case "keyup":
				if (target == this.minb)  {
				   this.SetMinPos(target.value);
				   if (typeof googleAnalytics != 'undefined')
				      googleAnalytics.trackEvent(['filter', 'price', 'min']);
				} else if (target == this.maxb) {
				  this.SetMaxPos(target.value);
				   if (typeof googleAnalytics != 'undefined')
				      googleAnalytics.trackEvent(['filter', 'price', 'max']);
				}
				if (event.keyCode != 13) {
					this.submitFormClearTimer();
					this.submitForm();
				}
				break;
			
			case "resize":
				var thisObj = this;
				if (this.resizeTimer) return true; 
				else this.resizeTimer = setTimeout(function(e) {thisObj.RenderPrePrep(thisObj);},100);
				break;
			
			case "mousedown":
				this.submitFormClearTimer();
				
				var mouse = this.getMouseXY(event);
				if (this.pbbool) { 
					if (thefind.browser.type == 'msie' && thefind.browser.version == '6') this.pb.style.filter = this.pb.style.filter.replace("_off", "_on");
					else this.pb.src = this.pb.src.replace("_off", "_on");
					this.pbbool = false; 
				}
				this.sx = thefind.func.dimensions(this.pcd, true).x;
				this.sw = this.pcd.offsetWidth;
				this.sliding = true; 
				this.minPos = this.phdmin.offsetLeft;
				this.maxPos = this.phdmax.offsetLeft;
				this.handle = (mouse.x - this.sx) < (this.minPos + this.handlehalf + (((this.maxPos + this.handlehalf) - (this.minPos + this.handlehalf)) >> 1));
				
				this.EventMoveSlider(event);
				addEvent(document, "mouseup", this);
				addEvent(document, "mousemove", this);
				this.pbgs.style.visibility = "visible";
				$TF(this.pbgs).fadeIn("fast");
				break;
			
			case "mouseup":
				if (typeof googleAnalytics!='undefined') googleAnalytics.trackEvent(['filter', 'price', 'slider']);
				this.SetPrice(parseInt(this.pmin),parseInt(this.pmax));
				this.EventMoveSlider(event);
				this.sliding = false;
				
				$TF(this.pbgs).fadeOut("slow");
				
				//if (!psFadeObj) { var psFadeObj = new objFader(this.pbgs,10,1,3,100); }
				removeEvent(document, "mousemove",this);
				removeEvent(document, "mouseup",this);
				
				this.parent.progress('init',1250);
				
				this.submitFormClearTimer();
				this.submitForm();
				break;
			
			case "mousemove":
				if (this.sliding) 
					this.EventMoveSlider(event);
				
				break;
			
			case "submit":
				this.submitFormClearTimer();
				this.submitForm(1);
				
				break;
		}
		
		event.preventDefault();
		event.stopPropagation();
	}
	
	this.submitFormClearTimer = function() {
		if (this.timer) {
			//this.parent.progress('pause');
			clearInterval(this.timer);
			delete this.timer;
		}
	}
	
	this.submitForm = function(delay) {
		thefind.price_on = true;
		
		(function(self) {
			self.timer = setTimeout(function() {
				thefind.func.set_pagination();
				thefind.func.scroll_results();
				thefind.func.ajax_submit({
					form: self.form,
					exclude: 'priceanddiscounts',
					search: search
				});
			},delay || 1250);
		})(this);
	}
	
	this.ResizeTextBoxes = function(b,v) {
		o = (b)?this.minbd:this.maxbd;
		o.style.width = v + ".2em";
		
		return v;
	}
	this.EventMoveSlider = function(event) {
		if (!event) event = window.event;
		var mouseX = event.pageX || (event.clientX + document.body.scrollLeft);
		var destination = Math.round(mouseX - this.sx - this.handlehalf);
		if (this.handle == true) {
			this.minPos = this.ValidatePos(destination);
			this.SetHandlePos('min',this.minPos,this.maxPos - this.handlew);
		} else {
			this.maxPos = this.ValidatePos(destination);
			this.SetHandlePos('max',this.maxPos,this.sw - this.handlew);
		}
		this.CenterRangeInfo();
		var min = ((this.minPos+this.handlehalf) / this.sw) * 100;
		var max = ((this.maxPos+this.handlehalf) / this.sw) * 100;
		this.GetRangeInfo(min,max);
		items = addCommas(roundTo(this.itemcount,Math.floor(this.itemcount.toString().length/2)));
		items = (this.iflag)?"<span class='tf_priceslider_thingy'>> </span>"+items:"<span class='tf_priceslider_thingy'>~ </span>"+items;
		this.PrintRangeInfo(this.symbol+addCommas(this.pmin)+" - "+this.symbol+addCommas(this.pmax)+"<br>"+items+" items");
		if (this.fpson) this.RenderFPS();
		event.returnValue = false;
	}
	this.RenderFPS = function() {
		var	d = new Date(),
				delay = 1000 / (array_sum(this.fps) / this.fps.length),
				currms = (d.getSeconds() * 1000) + d.getMilliseconds(),
				timediff = (currms > this.lastdraw ? currms - this.lastdraw : 60000 + currms - this.lastdraw),
				logtxt = "";
		
		if (timediff > delay) {
			logtxt = "fps: " + (array_sum(this.fps) / this.fps.length);
			var	ddone = new Date(),
					donems = (ddone.getSeconds() * 1000) + ddone.getMilliseconds();
			
			targetfps = 1500 / (donems - this.lastdraw);
			if (targetfps != Infinity) {
				this.fps[this.renderiter++] = targetfps;
				if (this.renderiter > this.fps.length) 
					this.renderiter = 0;
			}
			this.lastdraw = donems;
		}
		if (logtxt) this.log.innerHTML = logtxt;
	}
	this.SetHandlePos = function(toggle,pos,altpos) {
		var handle = (toggle=='min')?this.phdmin:this.phdmax;
		posp = (pos / this.sw) * 100;
		if (this.browser == "msie") {
			try { handle.style.left = posp + "%"; }
			catch(e) { handle.style.left = altpos + "px"; }
		} else { handle.style.left = posp + "%"; }
	}
	this.SetMinPos = function(value) {
		if (this.display == 0) return false;
		value += '';
		this.pmin = this.pminsaved = (value.substring(0,1) == this.symbol)?parseInt(value.substring(1)):parseInt(value);
		this.minPos = this.ValidatePos(this.SetPricePos(this.pmin)-this.handlehalf,'min');
		if (((this.minPos < 0) && (this.zoomed)) || (typeof(this.minPos)) == undefined) { this.minPos = this.ml - this.handlehalf; }
		this.SetHandlePos('min',this.minPos,0 - this.handlehalf);
	}
	this.SetMaxPos = function(value) {
		if (this.display == 0) return false;
		value += '';
		this.pmax = (value.substring(0,1) == this.symbol)?parseInt(value.substring(1)):parseInt(value);
		this.maxPos = this.ValidatePos(this.SetPricePos(this.pmax)-this.handlehalf,'max');
		if (typeof this.maxPos == 'undefined') { 
			this.maxPos = (this.sw - this.mr) - this.handlehalf; 
		}
		this.SetHandlePos('max',this.maxPos,this.sw - this.handlehalf);
	}
	this.SetPricePos = function(price) {
		var x = 0;
		for (var i in this.h.buckets) {
			if (price >= this.h.buckets[i][1]) {
				x = this.sw * (this.bucketpos[i] * .01);
				i = this.h.buckets.length+1;
			}
		}
		return x;        
	}
	this.CenterRangeInfo = function() {
		var	debugOffset = this.minPos + this.handlew,
				debugCenter = (this.maxPos + debugOffset) / 2,
				debugWidth = 0;
		
		this.pbgs.style.left = this.sw / 2 - 0 + 'px'; //debugCenter - (debugWidth / 2) + "px";
	}
	this.GetRangeInfo = function(lpos,rpos)  {
		this.pmin = -1;
		this.pmax = 0;
		this.itemcount = 0;
		var i = 0;
		
		while (this.bucketpos[i]) {
			var index = i;
			if ((this.bucketpos[i] >= lpos) && (this.bucketpos[index++] <= rpos)) {
				if (this.pmin == -1) { 
					this.pmin = this.h.buckets[i][1];
					this.bucketmin = i;
				}
				this.itemcount += (isNaN(parseInt(this.h.buckets[i][0])))?0:parseInt(this.h.buckets[i][0]);
				this.pmax = this.h.buckets[i][2]; 
				this.bucketmax = i;
			}
			i++;
		}
		
		if (this.zoomed) {
			maxbp = this.getmaxbp();
			sW = this.sw - this.mr;
			this.iflag = false;
			if ((lpos < this.bucketpos[0]) && (this.ml > 0) && (lpos != this.oldpos.l)) {
				var percent = lpos / (this.ml);
				if (percent > .9999) percent = .9999;
				var np = ((this.h.buckets[0][1] - this.h.absMin) * percent) + this.h.absMin;
				this.pmin = Math.round(np);
				if (lpos <= this.ml) { 
					var lop = lpos;
					this.lcd.style.width = lpos + "px";
				}
				this.iflag = true;
			} else if (lpos > sW && lpos != this.oldpos.l) {
				var percent = Math.abs((sW - lpos) / this.mr);
				percent = 1.0 - percent;
				if (percent > .9999) percent = .9999;
				if (percent < .015) percent = 0;
				var np = this.h.absMax - Math.abs((this.h.absMax - maxbp) * percent.toFixed(2));
				this.pmin = Math.round(np);
				this.iflag = true;
			} else {
				if (lop < this.ml) {
					var lop = this.ml;
					this.lcd.style.width = this.ml + "px";
				}
			}
			if ((rpos > sW) && (this.mr > 0) && (rpos != this.oldpos.r)) {
				var percent = Math.abs((sW - rpos) / this.mr);
				percent = 1.0 - percent;
				if (percent > .9999) percent = .9999;
				if (percent < .015) percent = 0;
				var np = this.h.absMax - Math.abs((this.h.absMax - maxbp) * percent.toFixed(2));
				this.pmax = Math.round(np);
				if (rpos >= (sW - this.mr)) { 
					var rop = rpos;
					this.rcd.style.left = Math.abs(sW - rpos) + "px";
				}
				this.iflag = true;
			} else if (rpos < this.bucketpos[0] && (rpos != this.oldpos.r)) {
				var percent = rpos / (this.ml);
				if (percent > .9999) percent = .9999;
				var np = ((this.h.buckets[0][1] - this.h.absMin) * percent) + this.h.absMin;
				this.pmax = Math.round(np);
				this.iflag = true;
			} else {
				if (rop > sW) {
					rop = sW;
					this.rcd.style.left = 0 + "px";
				}
			}
		}
		return true;
	}
	
	this.PrintRangeInfo = function (txt)  {
		thefind.func.ie6_purge(this.pbgs);
		this.pbgs.innerHTML = txt;
	}
	
	this.getmaxbp = function() {
		for (i=this.h.buckets.length; i>0;i--) {
			try { 
				if (this.h.buckets[i][2])
					return this.h.buckets[i][2];
			} catch(e) {}
		}
	}
	
	this.SetPrice = function(min,max) {
		this.minb.value = this.symbol + parseInt(min);
		this.maxb.value = this.symbol + parseInt(max);
	}
	
	this.SetPriceTxtBox = function(min,max,absMin,absMax) {
		var leftpercent = ((this.minPos + this.handlehalf) / this.sw) * 100,
				rightpercent = ((this.sw - (this.maxPos + this.handlehalf)) / this.sw) * 100,
				minI = document.createElement('input'),
				maxI = document.createElement('input');
		
		minI.className = "tf_moreoptions_textboxmin";
		maxI.className = "tf_moreoptions_textboxmax";
		minI.disabled = "disabled";
		maxI.disabled = "disabled";
		this.minb.style.visibility = "hidden";
		this.maxb.style.visibility = "hidden";
		this.minbd.insertBefore(minI,this.minbd.firstChild);
		this.maxbd.insertBefore(maxI,this.maxbd.firstChild);
		minI.value = min;
		maxI.value = max;
		this.minb.value = min + "." + absMin + "." + Math.round(leftpercent);
		this.maxb.value = max + "." + absMax + "." + Math.round(rightpercent);
		this.submitted = true;
	}
	this.getMouseXY = function(event) {
		var	x = event.pageX || (event.clientX + document.body.scrollLeft),
				y = event.pageY || (event.clientY + document.body.scrollTop);
				
		return { 'x' : x, 'y' : y};
	}
	this.BlendColor = function(percentage) {
		var newColor = new Array();
		for (cIndex=0; cIndex < 3; cIndex++) {
			var step = ((this.color1[cIndex] - this.color2[cIndex]) * (percentage * 0.01));
			newColor[cIndex] = Math.round(this.color1[cIndex] - step); 
		}
		return newColor;
	}
	this.DeleteDivArray = function(array,arrayDiv) {
		for (i=0;array[i];i++) {
			var divCurrent = array[i];
			var divParent = arrayDiv;
			thefind.func.ie6_purge(divCurrent);
			divParent.removeChild(divCurrent);
		}
	}
	this.ValidatePos = function(position,toggle) {
		if (toggle) this.handle = (toggle=='min')?true:false;
		var offset = 0 - this.handlehalf;
		if (position < offset) { position = offset; }
		if (position > (offset + this.sw)) { position = (offset + this.sw); }
		if (this.handle) {
			var border = this.maxPos - this.handlew;
			if (position > border) { position = border; }
		} else {
			var border = this.minPos + this.handlew;
			if (position < border) { position = border; }        
		}
		return position;
	}
	this.showCurtains = function(state) {
		this.lcd.style.visibility = state;
		this.rcd.style.visibility = state;
	}
	this.drawCurtains = function(lpos,rpos) {
		rpos = Math.round(rpos);
		lpos = Math.round(lpos);
		
		if ((!this.lcd) || (!this.rcd)) {
			var	ce = function(classname) {
						element = document.createElement('div');
						element.className = 'tf_priceslider_' + classname;
						
						return element;
					},
					ac = function(parent, element) {
						return parent.appendChild(element);
					},
					lol = [], 
					rol = [],
					lcd = this.lcd	= ce('l_curtain'),
					rcd = this.rcd	= ce('r_curtain'),
					a, b;
			
			for (i=0; i<4; i++) {
				lol.push(ce('l_outlier_' + (i + 1)));
				rol.push(ce('r_outlier_' + (i + 1)));
			}
			
			ac(lol[3], lcd);
			for (a=2; a>=0; ac(lol[a], lol[a-- + 1]));
			ac(this.c, lol[0]);
			
			ac(rol[3], rcd);
			for (a=2; a>=0; ac(rol[a], rol[a-- + 1]));
			ac(this.c, rol[0]);
		}
		
		if (lpos > 4) {
			lol[0].style.width = lpos + "px";
			lol[3].style.width = lpos-3 + "px";
			lcd.style.width = lpos-3 + "px";
		}
		if (rpos > 4) {
			percent = (((this.sw) - rpos) / this.sw) * 100;
			rol[0].style.left = percent + "%";
			rol[0].style.width = rpos + 2 + "px";
			rol[1].style.width = rpos + 1 + "px";
			rol[2].style.width = rpos + "px";
			rol[3].style.width = rpos - 3 + "px";
			rcd.style.width = rpos - 3 + "px";
		}
	}
	this.init = function() {
		if (this.display && this.c) {
			this.c.style.visibility = "visible";
			
			var	pbc = thefind.utils.getElementsByClassName(document,'div','tf_moreoptions_updatebutton_container')[0],
					pcc = this.c.parentNode,
					pc = pcc.parentNode,
					sb = pbc.getElementsByTagName('span')[0],
					modt = thefind.utils.getElementsByClassName(pc,"span", "tf_moreoptions_display_to")[0];	
			
			pbc.style.visibility = "visible";
			this.pb = thefind.utils.getElementsByClassName(pbc,'button','tf_util_button_custom')[0];
			this.c.className = "tf_priceslider_container_2";
			this.c.style.display = "block";
			this.minb = pc.getElementsByTagName('input')[0];
			this.maxb = pc.getElementsByTagName('input')[1];
			this.minbd = this.minb.parentNode;
			this.maxbd = this.maxb.parentNode;
			this.pb = pbc.getElementsByTagName('img')[0];
			
			$TF(pcc).addClass('tf_filters_price_container_show');
			pbc.style.visibility = "hidden";
			pbc.style.display = "none";
			modt.style.display = "none";
			sb.style.display = "none";
			
			this.pb.style.display = "block";
			this.minbd.className = "tf_moreoptions_minbox_2";
			this.maxbd.className = "tf_moreoptions_maxbox_2";
			this.minb.className = "tf_moreoptions_textboxmin_2";
			this.maxb.className = "tf_moreoptions_textboxmax_2";
			this.minb.value = this.symbol + (this.h ? this.h.displayMin : 0);
			this.maxb.value = this.symbol + (this.h ? this.h.displayMax : 0);
			
			this.Create();
			
			if (this.h) {
				this.SetPrice(parseInt(this.h.displayMin),parseInt(this.h.displayMax));
				this.RenderHistogram(this.pcd,this.h);
			}
			
			this.SetEvents();
		}
	}
	
	this.init();
});

thefind.add('color', function(color,target) {
  this.name = 'tf_color_picker_'+target+'_';
  this.color = color || '#808080';
	
	this.color = (search.SearchParms.color) ? '#'+search.SearchParms.color : this.color;
	
  this.colors = [
		[ [0,0,0], [255,207,198], [255,224,196], [255,230,195], [255,239,193], [243,240,198], [222,240,205], [202,235,229], [183,233,247], [184,223,241], [185,218,236], [203,207,230], [214,199,224], [239,207,237], [255,211,241], [255,201,212] ],
		[ [85,85,85], [254,158,133], [255,190,131], [255,204,129], [255,218,125], [228,220,134], [185,221,151], [145,215,194], [99,205,244], [101,189,228], [104,174,216], [143,152,200], [168,137,191], [220,151,217], [255,159,229], [255,141,168] ],
		[ [130,130,130], [247,61,48], [254,141,50], [255,163,48], [255,191,47], [199,193,56], [130,195,74], [45,180,151], [0,169,227], [0,136,207], [0,112,184], [62,73,157], [105,52,141], [189,75,189], [255,87,200], [254,62,117] ],
		[ [175,175,175], [181,64,45], [184,105,46], [186,121,44], [191,141,41], [152,143,50], [103,145,64], [48,136,114], [0,128,167], [0,106,154], [0,90,138], [58,63,119], [84,49,109], [139,63,138], [191,73,154], [183,51,78] ],
		[ [255,255,255], [119,60,43], [121,78,43], [123,86,42], [123,95,39], [101,97,45], [74,97,55], [50,92,82], [6,87,112], [19,77,102], [24,69,95], [52,53,84], [67,45,79], [95,53,95], [125,60,105], [120,47,63] ]
	];
	
	this.init = function() {
		this.create_swatches(this.name + "swatches");
		this.create_slider(this.name + "slider");
		
    if (this.swatchDiv && (this.swatchDiv.style.backgroundColor || this.color)) {
      var	value = this.swatchDiv.style.backgroundColor || this.color,
					rgb;
			
      if (value.charAt(0) == "#") 
        rgb = hex2rgb(value);
      else
        rgb = value.replace("rgb(", "").replace(")", "").split(",");
      
      this.setColor(rgb);
    }
		if (this.activeSwatch)
			thefind.utils.elementAddClass(this.activeSwatch, 'selected');
		
    fixPNG();  
  }
	
	this.create_swatches = function(divName) {
    this.swatchesDiv = document.getElementById(divName);
		thefind.func.ie6_purge(this.swatchesDiv);
    this.swatchesDiv.innerHTML = "";
		
    if (this.swatchesDiv) {
      for (var i = 0; i < this.colors.length; i++) {
        var row = document.createElement("div");
        row.id = divName + i;
        row.className = divName + "Row";
				
        for (var j = 0; j < this.colors[i].length; j++) {
          var	color = rgb2hex(this.colors[i][j]),
							swatch = document.createElement("div");
         
					swatch.id = divName + '_' + i + "_" + j;
          swatch.className = "tf_color_picker_swatch";
          swatch.style.backgroundColor = color;
          swatch.style.left = ((j * 15)) + "px"
          swatch.style.top = ((i * 15)) + "px"
          addEvent(swatch, "click", this);
          row.appendChild(swatch);
					if (color == this.color)
						this.activeSwatch = swatch;
        }
				
				//alert(color+' '+this.color);
        this.swatchesDiv.appendChild(row);
      }
			
      // Create rounded corner images
      var tmp = ['tl', 'tr', 'bl', 'br'];
      for (var i = 0; i < 4; i++) {
        var corner = document.createElement("div");
        corner.id = divName + "corner_" + tmp[i];
        corner.className = "tf_color_picker_swatch_corner tf_color_picker_swatch_corner_" + tmp[i];
        corner.src = "colorPickerSwatchesCorner_corner_" + tmp[i] + ".png";
        this.swatchesDiv.appendChild(corner);
      }
    }
		
		this.checkbox = document.getElementById('tf_filters_color_input');
		if (this.checkbox) 
			addEvent(this.checkbox,'click',this);
  }
	
  this.clearSelected = function() {
		if (this.activeSwatch) 
			thefind.utils.elementRemoveClass(this.activeSwatch, "selected"); 
  }
	
	this.submit = function(args,hex) {
		thefind.func.set_pagination();
		thefind.func.scroll_results();
		thefind.func.ajax_submit(args);
		
		this.checkbox.value = hex;
		return true;
	}
	
	this.halt_event = function(event) {
		event.preventDefault();
		event.stopPropagation();
	}
	
  this.handleEvent = function(event) {
    var	event = event || window.event,
				target = event.srcElement || event.target;
    
		switch (event.type) {
			case 'click':
				if (this.checkbox && target == this.checkbox) {
          if (typeof googleAnalytics=='object')
            googleAnalytics.trackEvent(['filter', 'color', this.checkbox.checked?'check':'uncheck']);
					return (!this.checkbox.checked) 
						? this.submit({ exclude: 'color', remove: [ 'color' ] }, '')
						:	this.submit({ exclude: 'color', parms: { color: this.hex } }, this.hex);
				}
				
				var	nameParts = target.id.split(/_/),
						color = this.colors[nameParts[5]][nameParts[6]];
				
        if (typeof googleAnalytics=='object') 
					googleAnalytics.trackEvent(['filter', 'color', 'check']);
				
				this.hex = rgb2hex(color).split('#')[1];
				this.setColor(color);
				this.submit({ exclude: 'color', parms: { color: this.hex } }, this.hex);
				
				if (this.checkbox) this.checkbox.checked = true;
				this.activeSwatch = target;
				thefind.utils.elementAddClass(target, "selected");
				break;
			
			case 'mousedown':
				this.slider_events(target, event, true);
				break;
			
			case 'mouseup':
				this.slider_events(target, event, false);
				break;
    }
  }

	this.slider_events = function(add) {
		var	events = [ 'mousemove', 'mouseup', 'mouseout' ],
				func = (add) 
					? thefind.func.bind 
					: thefind.func.unbind;
		
		for (var i=0; i<events.length; i++) {
			func(this.sliderDiv, events[i], this);
			func(this.selectedDiv, events[i], this);		
		}
		
		this.dragging = add;
		this.halt_event(event);
		
    if (target.id == this.selectorDiv.id) 
			target = this.sliderDiv;
    
    var x = ((event.clientX || event.pageX) - thefind.func.dimensions(target,true)[0]);
    this.setPosition(x); 
	}

	this.create_slider = function(sliderDivName) {
		var sliderDiv, selectorDiv, swatchDiv, pos;
		
		this.sliderDiv = document.getElementById(sliderDivName);
    this.swatchDiv = document.getElementById(this.name + "selected_swatch");
		
    if (this.sliderDiv && this.sliderDiv.offsetParent) {
      var sliderPos = thefind.func.dimensions(this.sliderDiv,true);
      this.selectorDiv = document.createElement('div');
      this.selectorDiv.id = sliderDivName + "selector";
      this.sliderDiv.offsetParent.appendChild(this.selectorDiv);
      this.selectorDiv.style.top = (this.sliderDiv.offsetTop - ((this.selectorDiv.offsetHeight - this.sliderDiv.offsetHeight) / 2)) + "px"; 
      this.setPosition(this.sliderDiv.offsetWidth / 2);
      this.setColor(this.color);
			
      addEvent(this.sliderDiv, "mousedown", this);
      addEvent(this.selectorDiv, "mousedown", this);
    }
  }
  
  this.setColor = function(rgb) {
		var hexcolor = (typeof rgb == 'string') ? rgb : rgb2hex(this.color = rgb);
    
		if (this.sliderDiv)
			this.sliderDiv.style.backgroundColor = hexcolor;
		if (this.swatchDiv)
			this.swatchDiv.style.backgroundColor = hexcolor;
		
		this.clearSelected();
		this.setPosition(this.sliderDiv.offsetWidth / 2);
		if (this.checkbox && hexcolor != '#808080') this.checkbox.checked = true;
  }
	
  this.setPosition = function(pos) {
		if (this.selectorDiv) {
			var selectorpos = pos - (this.selectorDiv.offsetWidth / 2);
			
			if (selectorpos <= 0) {
				selectorpos = 0;
			} else if ((selectorpos + this.selectorDiv.offsetWidth) >= this.sliderDiv.offsetWidth) {
				selectorpos = this.sliderDiv.offsetWidth - this.selectorDiv.offsetWidth;
			}
			this.selectorDiv.style.left = (selectorpos + this.sliderDiv.offsetLeft) + "px"; 
			this.pos = Math.round((pos / this.sliderDiv.offsetWidth) * 100);
		}
		
    if (this.swatchDiv && rgb2hex(this.getModifiedColor()) != "#NaNNaNNaN" ) 
      this.swatchDiv.style.backgroundColor = rgb2hex(this.getModifiedColor());
  }
	
  this.getModifiedColor = function() {
    var newcolor = [0, 0, 0];
    
    if (this.pos < 50) { // fade to white
      var pos = ((50 - this.pos) * 2) / 100;
      for (var i = 0; i < 3; i++) {
        newcolor[i] = Math.round(this.color[i] + (255 - this.color[i]) * pos);
      }
    } else { // fade to black
      var pos = ((this.pos - 50) * 2) / 100;
      for (var i = 0; i < 3; i++) {
        newcolor[i] = Math.round(this.color[i] - (this.color[i] * pos));
      }
    }
    
    // Validate colors
    for (var i = 0; i < 3; i++) {
      if (newcolor[i] < 0) newcolor[i] = 0;
      if (newcolor[i] > 255) newcolor[i] = 255;
    }
		
    return newcolor;
  }

	this.set_color = function(event, parentElement) {
		var colorStr = rgb2hex(cPicker.color, true);
		var colorSwatch = document.getElementById(this.name+'selected_swatch');
		if (colorSwatch) {
			thefind.utils.elementRemoveClass(colorSwatch, "default");
			colorSwatch.style.backgroundColor = rgb2hex(cPicker.color);
		}
		objInfoBox.Hide(event, parentElement, true);
		var form = document.getElementById('tf_search_filters_left');
		if (form) {
			// hackish way to get the color picker working again
			//var checkbox = document.getElementById('tf_search_filters_picker_color_input');
			var checkbox = document.getElementById('tf_filters_color_input');
			if (!checkbox) {
				checkbox = document.createElement('input');
				checkbox.type = 'checkbox';
				checkbox.name = 'color';
				checkbox.style.display = 'none';
				form.appendChild(checkbox);
			}
			checkbox.value = colorStr;
			checkbox.checked = true; // Somehow in IE, we have to set the checked state AFTER appending to the document
			// linkclick tag for color popup update button
			cm = new TFHtmlUtilsCoremetrics();
			cm.params = [
				form.action,
				"search_filter_left_color_popup_update",
				""];
			cm.create("ManualLinkClick");
			$TF(form).submit();
		}
	}

	this.fix_IE6 = function() {
		var swatch = document.getElementById('moreOptionsFilterColorSwatch');
		
		if (swatch) {
			swatch.id += 'Inner';
			swatch.outerHTML = '<span style="display: inline-block; padding-top: 21px;" id="moreOptionsFilterColorSwatch" class="'+swatch.className+'">'+swatch.outerHTML+'</span>';
			var swatchInner = document.getElementById('moreOptionsFilterColorSwatchInner');
			swatchInner.src = '/images/misc/nothing.gif';
			var swatch = document.getElementById('moreOptionsFilterColorSwatch');
			swatch.style.backgroundColor = swatchInner.style.backgroundColor;
		}
	}
	
	this.init();
});

function fixMoreOptionsColorSwatchIE6() { return true; }

function rgb2hex(color, noHash) {
	var hexcolor = "";
  
	if (!noHash) 
		hexcolor += "#";
  
	for (var i=0; i<3; i++) {
		var tmphex = parseInt(color[i]).toString(16);
		
		if (tmphex.length == 1)
			hexcolor += "0";
		
		hexcolor += tmphex;
	}
	
	return hexcolor;
}

function hex2rgb(color) {
  var rgb = [128, 128, 128];

  if (color.charAt(0) == "#") color = color.substring(1, 7); // ignore #, if applicable
  
	if (color.match(/^[0-9a-f]{6}$/i)) 
    for (var i = 0; i < 3; i ++) 
      rgb[i] = parseInt(color.substring(i*2, (i+1)*2), 16);
	
  return rgb;
}

function rgb2hsv(rgb) {
	var	r = rgb[0] / 255,
			g = rgb[1] / 255,
			b = rgb[2] / 255,
			min = Math.min(r, g, b),
			max = Math.max(r, g, b),
			delta = max - min,
			v = max,
			h, s;

	if (delta == 0) {
		s = h = 0;
	} else {
		s = (max == 0) ? 0 : 1 - (min / max);
		
		if (max == r && g >= b)
			h = (60 * ((g - b) / delta));
		else if (max == r && g < b)
			h= (60 * ((g - b) / delta)) + 360;
		else if (max == g)
			h = (60 * ((b - r) / delta)) + 120;
		else if (max == b)
			h = (60 * ((r - g) / delta)) + 240;
  }

  return {
		h: Math.round(h), 
		s: Math.round(s * 1000) / 1000, 
		v: Math.round(v * 1000) / 1000
	};
}

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 roundTo(n,p) { 
	x = Math.pow(10,p); n = Math.round(n / x) * x; return n; 
}

function PriceGrapher(divname, histogram, currentprice, query) {
  this.preferences = [];

  this.Init = function(divname, histogram, currentprice) {
    this.Create(divname);
    this.SetHistogram(histogram);
    this.SetCurrentPrice(currentprice);
  }

  this.Create = function(divname) {
    this.divname = divname;

    this.preferences.margin = 20;
    this.preferences.border = true;
    this.preferences.numlabelsx = 5;
    this.preferences.numlabelsy = 3;

    this.graphdiv = document.getElementById(divname);

    this.grapharea = document.createElement("DIV");
    this.grapharea.className = "grapharea";
    this.graphdiv.appendChild(this.grapharea);

    this.axes = [];
    this.axes.x = document.createElement("DIV");
    this.axes.x.className = "xaxis";
    this.axes.y = document.createElement("DIV");
    this.axes.y.className = "yaxis";
    this.axes.y.innerHTML = "<label>Items</label>";

    this.graphdiv.appendChild(this.axes.x);
    this.graphdiv.appendChild(this.axes.y);

    this.grapharea.style.height = (this.graphdiv.offsetHeight - this.axes.x.offsetHeight - 3) + "px";
    //this.grapharea.style.width = (this.graphdiv.offsetWidth - (this.axes.y.offsetWidth * 2)) + "px";
  }

  this.SetCurrentPrice = function(currentprice) {
    if (currentprice.length > 0) {
      this.currentprice = parseFloat(currentprice);
    }
  }


  this.SetHistogram = function(histogram) {
    this.Normalize(histogram);
    this.histogram = histogram;
  }

  this.Draw = function() {
    if (this.preferences.numlabelsy > 0) {
      var labellist = document.createElement("OL");
      var labelscale = Math.pow(10, Math.round(this.countmax).toString().length - 2);
      for (var i = 0; i < this.preferences.numlabelsy; i++) {
        var label = document.createElement("LI");
        label.innerHTML = numberFormat(Math.floor((this.countmax * (100 - ((100 / this.preferences.numlabelsy) * i)) / (100 * labelscale)) * labelscale));
        label.style.height = Math.round(this.graphdiv.offsetHeight / (this.preferences.numlabelsy + 1)) + "px";
        labellist.appendChild(label);
      }
      this.axes.y.appendChild(labellist);
      //this.grapharea.style.left = (this.axes.y.offsetWidth) + "px";
    }
    for (var i in this.histogram.buckets) {
      if (!this.histogram.buckets.hasOwnProperty(i)) continue;

      var bucket = this.histogram.buckets[i];
      var graphbar = document.createElement("DIV");
      var fullwidth = (this.grapharea.offsetWidth / this.histogram.count);
      graphbar.className = "graphbar" + (this.currentprice >= bucket[1] && this.currentprice < bucket[2] ? " graphbarcurrent" : "");
      graphbar.id = "graphbar_" + i;
      var scale = 100 / this.histogram.count;

      graphbar.style.left = (scale * (i - 1)) + "%"; 
      graphbar.style.width = (scale - ((scale * (this.preferences.margin / 100)) * 2)) + "%";
      graphbar.style.marginLeft = (scale * (this.preferences.margin / 100)) + "%";
      graphbar.style.height = (this.grapharea.offsetHeight * ((bucket[3] / this.valuemax))) + "px";
      graphbar.style.cursor = 'pointer';
			
			thefind.func.bind(graphbar, "click", function() {
				thefind.func.ajax_submit({ parms: { price: bucket[1] + '-' + bucket[2] } });
			});
			
      if (this.preferences.numlabelsx > 0 && i % Math.ceil(this.histogram.count / this.preferences.numlabelsx) == 0) {
        var label = document.createElement("LABEL");
        label.innerHTML = "$" + parseInt(bucket[1]);
        graphbar.appendChild(label);
      }
      graphbar.title = "$" + parseInt(bucket[1]) + " - $" + parseInt(bucket[2]) + ": " + parseInt(bucket[0]) + " products";
      this.grapharea.appendChild(graphbar);
      
    }
	}

  this.Normalize = function(histogram) {
    this.min = null;
    this.max = null;
    this.valuemax = null;
    this.countmax = null;
    for (var i in histogram.buckets) {
      if (!histogram.buckets.hasOwnProperty(i)) continue;
			
      if (histogram.buckets[i].range)
        histogram.buckets[i].push(histogram.buckets[i][0] / (histogram.buckets[i][2] - histogram.buckets[i][1]));
      else
        histogram.buckets[i].push(histogram.buckets[i][0]);
			
      if (this.min == null || histogram.buckets[i][1] < this.min) this.min = histogram.buckets[i][1];
      if (this.max == null || histogram.buckets[i][2] > this.max) this.max = histogram.buckets[i][2];
      if (this.valuemax == null || histogram.buckets[i][3] > this.valuemax) this.valuemax = histogram.buckets[i][3];
      if (this.countmax == null || histogram.buckets[i][0] > this.countmax) this.countmax = histogram.buckets[i][0];
    }
  }

  this.Init(divname, histogram, currentprice);
}

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 arrayMin(array) {
	var value=ret=0;
	
	for (var i=total=0; i<array.length; i++) {
		value = array[i];
		if (ret == 0 || value < ret) 
			ret = value;
	}
	
	return ret; 
}
function arrayMax(array) {
	var value=ret=0;
	
	for (var i=total=0; i<array.length; i++) {
		value = array[i];
		if (value > ret) ret = value;
	}
	
	return ret; 
}
function arrayAvg(array) { 
	return (arraySum(array) / array.length); 
}
function arraySum(array) {
	for (var i=total=0; i<array.length; i++) total += array[i];
	return total;
}

// ### Product View Infocards ###

thefind.add('product_view', function(args,ulHTML,listHTML,actions,hidden) {
	this.args				= args;
	this.ul					= ulHTML;
	this.item				= listHTML;
	this.actions		= actions;
	this.selected 	= 0;
	this.hidden = hidden;
	
	this.init = function() {
		for (var i=0; i<this.item.length; i++) {
			var item = this.item[i];
			if (this.actions[i]) {
				item.actions = this.actions[i];
				item.actions.links = this.actions[i].getElementsByTagName('A');
			}
			
			item.cssStyle = item.style;
		}
	}

	this.setup = function() {
		var	card, height, saved, item;
		
		for(var i=0; i<this.item.length; i++) {
			item = this.item[i];
			height = item.offsetHeight;
			item.cardheight = height;
			saved = (!saved || height > saved)?height:saved;
			item.display = 'none';
			item.cssStyle.display = item.display;
			
			if (this.actions[i] && this.actions[i].links.length) {
				var	links 	= this.actions[i].links,
						remove 	= item.actions.remove	= links[0] || false,
						first 	= item.actions.first 	= links[2] || false,
						up 			= item.actions.up 		= links[4] || false,
						down 		= item.actions.down 	= links[3] || false,
						last 		= item.actions.last 	= links[5] || false;
				
				var urlparms 	= (first)
					? first.href.split('?')[1]		: (up)
					? up.href.split('?')[1]			: (down)
					? down.href.split('?')[1]		: (last)
					? last.href.split('?')[1]		: (remove)
					? remove.href.split('?')[1]	: false;
				
				if (urlparms) {
					var	parms			= urlparms.split('&');
							list_name	= (typeof parms[0] != 'undefined') 
								? parms[0].split('=')[1] : false,
							list_id		= (typeof parms[2] != 'undefined') 
								? parms[2].split('=')[1] : false;
					
					item.list_id = list_id;
					if (!this.settings)
						this.settings = {};
					
					if (i == 0) this.settings.list_name = list_name;
					
					if (remove)	addEvent(remove	, "click", this);
					if (first)	addEvent(first	, "click", this);
					if (up)			addEvent(up			, "click", this);
					if (down)		addEvent(down		, "click", this);
					if (last)		addEvent(last		, "click", this);
				}
			}
		}
		
		if (thefind.browser.type != 'msie')
			this.ul.style.height = saved - parseInt(this.args.imagesize.split('x')[0]) + 'px';
		
		this.setCard(this.selected);
	}
	
	this.handleEvent = function(event) {
		if (!event) event = window.event;
		this.target = (event.srcElement || event.target);
		event.preventDefault();
		event.stopPropagation();
		
		switch (event.type) {
			case "click": this.handleAction(event);	break;
		}
	}

	this.handleAction = function(event) {
		var parent = this.target.parentNode;
		while (parent.tagName != 'UL')
			parent = parent.parentNode;
		
		var	id = this.indexOf(this.item,parent,'actions'),
				actions = this.item[id].actions;
		
		switch (this.target) {
			case actions.remove:	this.deleteItemPrep(this.item[id],true);							break;
			case actions.first:	this.moveItemPrep(id,0,true,true);											break;
			case actions.up:			this.moveItemPrep(id,(id+1),true,true);								break;
			case actions.down:		this.moveItemPrep(id,(id-1),true,true);								break;		
			case actions.last:		this.moveItemPrep(id,(this.item.length-1),true,true);	break;
		}
	}
	
	this.setCard = function(id) {
		if (this.hidden) 
      return;
		
    var item = this.item[id],
        selected = this.item[this.selected];
    
    if (typeof id == 'number' && item && selected) {
      selected.cssStyle.display = selected.display = 'none';
      item.cssStyle.display = item.display = 'block';
			
      this.selected = id;
		}
	}
	
	this.init();
	this.setup();
});

// ### Product List ###

thefind.add('comparulator', new function() {
	this.init = function(cp, lis, ritems, args) {
		var	//select = document.getElementById('tf_comparulator'),
				search = thefind.search(),
				placements = cp.split(','),
				options = {},
				exclude = {},
				results, items, item, related, key, lp;
		
		/*
		if (!select)
			return;
		
		select.innerHTML = '';
		*/
		
		for (var i=0; i<placements.length; i++) {
			results = search.bindings.results[placements[i]];
			
			if (!results)
				continue;
			
			items = results.items;
			
			for (var q=0; q<items.length; q++) {
				item = items[q];
				related = item.relatedchildren;
				price = item.item.price;
				
				if (!isNull(related) && !isNull(related.summary_lowprices)) {
					lp = related.summary_lowprices;
					type = lp[0].type;
					key = arrayGet(results.args.options.labels, type) || type;
					options[key] = price;
					
					if (this.results)
						for (var x=0; x<lp.length; x++) {
							lptype = lp[x].type;
							
							if (!arrayGet(this, 'results.args.options.labels.' + lptype))
								exclude[lptype] = true;
						}
					
					if (!this.key)
						this.key = key;
				}
			}
			
			if (!this.results)
				this.results = results;
		}
		
		/*
		select.parentNode.style.display = 'block';
		
		for (var key in options) {
			option = document.createElement('option');
			option.innerHTML = key;
			option.value = key;
			select.appendChild(option);
		}
		
		thefind.func.bind(select, 'change', this);
		this.select = select;
		*/
		
		this.lis = lis;
		this.args = args;
		this.items = ritems;
		this.options = options;
		this.exclude = exclude;
		this.change(this.key);
	}
	
	this.change = function(value, nlis, nitems) {
		var	value = value,// || this.select.value,
				lis = this.lis,
				items = this.items,
				options = this.options,
				price = options[value],
				li, item, itemprice, difference, span, label, multitag_skip;
		
		for (var i=0; i<lis.length; i++) {
			li = lis[i];
			itemprice = items[i].item.price;
			difference = (itemprice - price).toFixed(2);
			span = $TF('div.tf_search_item_compare span', li);
			
			if (difference == 0.00) 
				newprice = '';
			else
				newprice = '<strong>$' + Math.abs(difference).toFixed(2) + '</strong>';
			
			moreless = '<strong class="tf_search_item_compare_moreless">';
			moreless += difference > 0 ? 'more'  : 'less';
			moreless += '</strong>';
			
			//thefind.utils.removeClass(span[0], 'tf_search_item_compare_more');
			//thefind.utils.removeClass(span[0], 'tf_search_item_compare_less');
			//thefind.utils.addClass(span[0], 'tf_search_item_compare_' + moreless);
			
			moreless += ' than<br>' + this.key.toLowerCase() + ' price';
			
			span[0].innerHTML = newprice;
			
			if (newprice != '')
				span[0].innerHTML += ' ' + moreless;
      else
        span[1].innerHTML = this.key;
			
			for (var t=0; t<span.length; t++) {
				var	s = span[t], l = s.innerHTML;
				
				if (s && thefind.utils.hasClass(s, 'tf_search_item_compare_tag') && l) {
					if (this.exclude[l] || multitag_skip || arrayGet(this, "results.args.options.labels." + l) == this.key)
						s.innerHTML = '';
					else
						s.innerHTML = arrayGet(this, "results.args.options.labels." + l) || l;
					
					if (this.args.multitag == "0")
						multitag_skip = true;
				}
			}
			
			for (var t=0; t<span.length; t++)
				if (span[t].innerHTML == '' || span[t].innerHTML == ' ')
					span[t].style.display = 'none';
			
			multitag_skip = false;
		}
	}
	
	this.handleEvent = function(event) {
		var	event = event || window.event,
				target = event.srcElement || event.target;
		
		switch (event.type) {
			case "change": this.change(target.value); break;
		}
	}
});

thefind.add('product_list', function(id, args, data, relatedchildren) {
	this.id = id;
  this.args = args || {};
  this.data = data;
	this.items = [];
	this.relatedchildren = relatedchildren;
	
	this.init = function(obj) {
		//thefind.timing.log(true);
		if (!this.id)
			return;
		
		this.ProcessRelatedChildren();
		
		this.container = [ document.getElementById(this.id) ];
		
		if (typeof search != 'undefined' && this.args.placement == 'main') { // make config-driven - need to think on this
			if (!search.SearchParms.count)
				search.SearchParms.count = this.args.count;
			
			if (this.args.view) 
				search.SearchParms.view = this.args.view;
			
			this.args.pagecount = (this.args && this.args.pagecount) 
				? this.args.pagecount
				: 1;
			
			if (this.args.view != 'slideshow') 
				thefind.func.set_max_pagination(this.args.pagecount);
			
			thefind.func.set_pagination(any(arrayGet(search.SearchParms,"page"),arrayGet(search.args.filter,"pagenum"),0));
		}
		
    if (this.container.length > 0) {
			if (this.args.view == 'grid' && !thefind.utils.isNull(this.args.options) && !thefind.utils.isNull(this.args.options.snapresize) && this.args.options.snapresize.enabled == 1) {
        if (thefind.snap_resize) 
					thefind.snap_resize.resize(this.container[0]);
				else
					thefind.add('snap_resize', new thefind.func.snap_resize(this.container[0], this.args.options.snapresize));
			}
			
      this.lis = thefind.utils.getOnly(this.container[0], 'LI');
			
      for (var i=0; i < this.lis.length; i++) 
        this.items[i] = new thefind.func.product_item(i, this.lis[i], this.data[i], this.lists, this.args);
			
			if (this.args.view == 'slideshow' || this.args.view == 'gallery') { 
				var ul 			= document.getElementById(id),
						cards 	= thefind.utils.getOnly(ul, 'LI'),
						links		= $TF('a.tf_search_item_productimage_link', ul),
						images 	= $TF('img.tf_search_item_productimage', ul),
						actions	= $TF('ul.tf_search_item_actions', ul);
				
				if (this.args.hidecards == 'true') 
					this.pview = new thefind.func.product_view(this.args, ul, cards, actions, true);
				else 
					this.pview = new thefind.func.product_view(this.args, ul, cards, actions);
				
				switch (this.args.view) {
					case 'slideshow':
						if (typeof tf_content != 'undefined' && !thefind.utils.isNull(tf_content) && tf_content[this.id] && tf_content[this.id].args.slideshow) 
							this.args.slideshow = tf_content[this.id].args.slideshow;
						
						this.sshow = new TFSlideShow(this.args, ul, images, links, this.pview, this.data);
						
						break;
					
					case 'gallery': 
						this.gallery = new TFGallery(this.args, ul, images, this.pview);
						
						break;
				}
				
				return; 
			}
	  	
      if (this.args.popup == 1) {
				var	events = {
							mouseover: this.args.popup_mouseover ? this.args.popup_mouseover : false,
							//mouseout: this.args.popup_mouseout ? this.args.popup_mouseout : false,
							click: this.args.popup_click ? this.args.popup_click : false
						},
						elements, type;
				
				for (var i=0, li; li = this.lis[i]; i++) {
					for (var type in events) {
						if (!events[type])
							continue;						
						
						elements = thefind.utils.find(events[type], li);
						//elements = $TF(events[type], li);
						
						for (var q=0; q<elements.length; q++)
							addEvent(elements[q], type, this);
					}
					
					// FIXME - fix parent detection for thefind.find();
					addEvent(li, 'mouseout', this);
        }
      }
	  }
		
		var infocard_popup_options = any(arrayGet(this.args.options, 'infocard_popup'), false);
		
		if (typeof thefind.infobox.infomap['product_infocard'] == 'undefined' && infocard_popup_options) 
			thefind.infobox.add('product_infocard', infocard_popup_options);
		
		if (cp = arrayGet(this.args.options,'comparulator'))
			thefind.comparulator.init(cp, this.lis, this.items, this.args);
		
    for (var i=0; i<this.lis.length; i++) {
			var link = thefind.find('a.tf_search_item_aboutstore', this.lis[i]);
			
			if (link.length > 0) {
				link = link[0];
				
				addEvent(link, 'click', this);
			}
		}
		
		//thefind.timing.log();
		//thefind.timing.print();
	}
	
	this.ProcessRelatedChildren = function(key) {
		var	list = this.relatedchildren,
				section, item, sk, c, q, i;
		
		for (var s in list) {
			section = list[s];
			
			if (!section.key) 
				continue;
			
			for (i=0; i<this.data.length; i++) {
				item = this.data[i];
				sk = section.key.split('_');
				c = sk.length > 1
					? item[sk[0]][sk[1]] 
					: item[sk[0]];
				
				if (!item.relatedchildren)
					item.relatedchildren = {};
				
        items = this.relatedchildren[s].items;
        
				o = (items) ? items[c] : null;
				
				if (!o)
					continue;
				
        if (!item.relatedchildren[s])
					item.relatedchildren[s] = [];
        
				for (q=0; q<o.length; q++)
					item.relatedchildren[s].push(o[q]);
			}
		}
	}
	
	this.handleEvent = function(event) {
		if (!event) event = window.event;
		this.target = (event.srcElement || event.target);
		
		switch (event.type) {
      case "click": this.handleClick(event); break;
			case "change": this.comparulator_change(this.target.value); break;
      case "mouseover": this.handlePopup(true, event); break;
      case "mouseout": if (this.current) this.handlePopup(false, event); break;
		}
	}
	
	this.handleClick = function(event) {
    var	target = thefind.utils.getEventTarget(event, "tf_search_item"),
				index = target ? this.getItemNumber(target) : false,
				item = index ? this.items[index] : false;
		
		if (thefind.utils.hasClass(this.target, 'tf_search_item_aboutstore')) {
			
			if (this.about_store_id)
				thefind.infobox.hide("upfront_badge_"+this.about_store_id);
			
			item.toggle_about_store('/search/infobox_aboutstore');
			
			this.about_store_id = item.merchant.uniqsiteid;
		} else if (item) {
			var popup = thefind.infobox.infoboxes[thefind.infobox.infomap['product_infocard']];
			this.current = target;
			
			if (popup.visible)
				thefind.infobox.hide(popup);
			
			item.showPopup(target, 'tf_search_item_productimage', 1000, 5000);
		}
	}
	
	this.handlePopup = function(mouseover,event) {
		if (this.args.popup != 1 || !this.target) 
			return;
		
		if (!mouseover && this.popup_timer)
			clearTimeout(this.popup_timer);
		
		if (this.checkRelated(event, (mouseover ? this.nodeName : 'LI'), mouseover)) 
			return;
		
		var index = (this.nodeName)
			?	this.getItemNumber(this.target)
			: this.getItemNumber(thefind.utils.getEventTarget(event, "tf_search_item"));
		
    if (this.lis[index]) {
			(function(self) {
				$TF(document).ready(function() {
					var item = self.lis[index];
					
					if (mouseover) {
						clearTimeout(self.popup_timer);
						self.popup_timer = setTimeout(function() {
							delete self.popup_timer;
							self.items[index].showPopup(item, 'tf_search_item_productimage', 1000, 5000);
						},750);
						self.current = item;
					} else if (self.current && item == self.current) {
						if (self.popup_timer)
							clearTimeout(self.popup_timer);
						
						self.items[index].hidePopup(item);
						
						delete self.current;
					}
				});
			})(this);
    }
	}

  this.handleSave = function(event) {
    if (event.data) {
      event.data.Save(this.myfinds);
    }
  }

	this.getItemNumber = function(target) {
		for (var num in this.lis){
			if (this.lis[num] == target) 
				return num;
		}
		
		return false;
	}

	// determines if the event triggered from the appropriate element
	this.checkRelated = function(e, n, m) {
		var	t = this.target || e.target,
				r = e.relatedTarget ? e.relatedTarget : m ? e.fromElement : e.toElement;
		
		while (t && t.nodeName != n) 
			t = t.parentNode;
		
 		while (!isNull(r) && r != t && r != document.body && arrayGet(r,'id') != 'tf_infobox') 
 			r = r.parentNode;
		
		return (!isNull(r) && r == t || arrayGet(r,'id') == 'tf_infobox');
	}

  this.init();
});

thefind.add('product_item', function(num, obj, values, lists, args) {
	this.num = num;
	this.obj = obj;
	this.html = arrayGet(values, "html") || {};
	this.complete = false;
	this.item = arrayGet(values, "product") || {};
	this.googleanalytics = values["googleanalytics"];
	this.merchant = values.merchant;
	this.store = arrayGet(values, "store") || {};
	this.saved = arrayGet(values, "saved") || {};
	this.extra = arrayGet(values, "extra") || {};
	this.args = args;
	this.lists = lists;
	this.relatedchildren = values.relatedchildren;
	
  this.init = function() {
    this.initEvents(this.obj);
		
    // If show.friendlyurl is 1, strip out anything after the ? and store it for later use (see openBuyWin function)
    if (this.merchant.buyurl) {
      var buyurlparts = this.merchant.buyurl.split('?');
      
			if (buyurlparts[1]) {
        this.merchant.buyurl_extras = buyurlparts[1];
      } else {
				var	result_view_id = 'FIXME-missing_result_view_id',
						trackingcode = '';
				
				// FIXME - this relies on the global "search" object which is bad bad bad
				if (typeof search != 'undefined' && typeof search.options.result_view_id != 'undefined') {
					result_view_id = search.options.result_view_id;
					trackingcode = search.request.filter['trackingcode'] || '';
				}
				
				this.merchant.buyurl_extras = thefind.utils.encodeURLParams({
					'result_view_id': result_view_id,
					'result_impression_id': this.html.result_impression_id || 'FIXME-missing_result_impression_id',
					'impression_type': this.item.itemtype || '',
					'position': this.item.itemnum,
					'trackingcode': trackingcode
				});
      }
			
      if (this.args.show.friendlyurl == 1) {
        this.merchant.buyurl = buyurlparts[0];
        
				var productlinks = thefind.utils.getAll(this.obj, "a", "tf_search_item_link");
        
				if (productlinks.length > 0)
          for (var i = 0; i < productlinks.length; i++)
            productlinks[i].href = this.merchant.buyurl;
      }
    }
  }
	
  this.initEvents = function(element) {
    $TF(element).bind("click", this, $TF.delegate({
      ".tf_search_item_actions_saveinmyfinds_link": this.handleClick,
      ".tf_search_item_actions_savestoreinmyfinds_link": this.handleClick,
      ".tf_search_item_actions_savebrandinmyfinds_link": this.handleClick,
      ".tf_search_item_actions_flag_link": this.handleClick,
      "a.tf_search_item_actions_emailtofriend_link": this.handleClick,
      "a.tf_search_item_link": this.handleClick,
      "a.tf_utils_link_external": this.handleClick,
      "a.tf_utils_link_offers": this.handleClick,
      ".tf_search_item_clusterlink": this.handleClick,
      ".coupon_item_xml": this.handleClick,
      ".tf_product_info": this.handleClick

    }));
  }
	
	this.toggle_filter_class = function(id, type, check) {
		var	filter = document.getElementById('tf_filter_' + type + '_' + id),
				condition = check
					? (this.saved[type] || thefind.utils.hasClass(filter, "tf_state_selected"))
					: (thefind.utils.hasClass(filter, "tf_state_selected"));
		
		if (!filter)
			return;
		
		if (condition)
			if (!this.popupdiv.find(".tf_search_item_actions_save" + type + "inmyfinds_link").hasClass("tf_state_selected")) {
				this.popupdiv.find(".tf_search_item_actions_save" + type + "inmyfinds_link").toggleClass("tf_state_selected");
				this.saved[type] = true;
			}
		else
			if (this.popupdiv.find(".tf_search_item_actions_save" + type + "inmyfinds_link").hasClass("tf_state_selected")) {
				this.popupdiv.find(".tf_search_item_actions_save" + type + "inmyfinds_link").removeClass("tf_state_selected");
				this.saved[type] = false;
			}
	}
	
  this.showPopup = function(rootElement, anchorClass, popupTrackingDelay, popupMyfindsDelay) {
    if (typeof pandoraLog == 'object') 
			pandoraLog.mouseovertype = "product";
    
		if (typeof googleAnalytics == 'object') 
			googleAnalytics.mouseovertype = "product";
		
		if (thefind.infobox.current && thefind.infobox.current.name == 'product_infocard')
			if (thefind.infobox.is_inside('product_infocard', rootElement))
				return;
			else	
				thefind.infobox.hide(thefind.infobox.current);
		
		if (!this.popuptext) {
			if (!this.complete) 
				this.parseHTML();
			
			var	register_template,
					names = [ 
						"relateditems",	"offers",		"comparebutton",	"localstore",	"prettyprice",
						"description",	"itemtags",	"productactions",	"crosslinks", "offers_local",
						"certifications", "rating"
					];
      
      (function(self) {
				register_template = function(name) {
					thefind.tplmgr.SetFunction("search.item.infobox", name,	function(tpl, obj, args) { 
						return self["show_" + name](args);
					});
				};
			})(this);
			
			for (var i = 0; i < names.length; i++)
				register_template(names[i]);
			
			this.query = search["request"]["query"];
			this.popuptext = thefind.tplmgr.GetTemplate('search.item.infobox', this);
		} else {
			if (this.popupdiv) {
				// popuptext needs to be updated with store filter saved store information
				var	id = this.merchant.uniqsiteid;
				
				this.toggle_filter_class(id, 'store');
				this.toggle_filter_class(id, 'brand');
			}
		}
		
		// look into the json object to get the params for the coremetrics tag
		var itemString = 'tf_search_item_normal_' + this.num,
		
		itemId = itemString.split("_"),
		itemType = itemId[3],
		itemNum = Number(itemId[4]),
		itemObj = null,
		popupParams = {},
		buyItUrlParams = this.item.buyItUrlParams;
		popupParams["delay"] = 850;
		popupParams["closebutton"] = false;
		
		// No CM or Pandora logging for shopbyissue
		if (itemType == "shopbyissue") {
			popupParams["cmJs"] = null;
		} else {
      var result_view_id = 'FIXME-missing_result_view_id';
			
			popupParams["pandoraScript"] = "/product/log.txt";
      popupParams["pandoraParams"] = "?logtype=popups&ddkey=" + this.item.ddkey + "&" + this.merchant.buyurl_extras;
			popupParams["popupTrackingDelay"] = popupTrackingDelay || 0;
			popupParams["item"] = this;
			
			if (this.item.pageType != "myfinds")
				popupParams["popupMyfindsDelay"] = popupMyfindsDelay || 0;
		}
		
		// Despite the popupdiv being stored already, IE seems unable to retrieve it.
		// this hack fix will ensure that the popupdiv is retrieved each time. -Lazarus
		if (!this.popupdiv) {
			this.popupdiv = $TF(this.popuptext);  // wack. -lazarus
			this.popuptext += '</div>';
			
			// popupdiv needs to be updated for  saved product
			if (this.saved.item)
				if (!this.popupdiv.find(".tf_search_item_actions_saveinmyfinds_link").hasClass("tf_state_selected"))
					this.popupdiv.find(".tf_search_item_actions_saveinmyfinds_link").toggleClass("tf_state_selected");
			else
				if (this.popupdiv.find(".tf_search_item_actions_saveinmyfinds_link").hasClass("tf_state_selected")) 
					this.popupdiv.find(".tf_search_item_actions_saveinmyfinds_link").removeClass("tf_state_selected");
			
			var	id = this.merchant.uniqsiteid;
			
			this.toggle_filter_class(id, 'store', true);
			this.toggle_filter_class(id, 'brand', true);
			
			// zoran (product.list.placements.main.infobox.title.link.enabled), etc; 
			if (this.args.infobox) {
				if(this.args.infobox.title.link.enabled) 
					this.popupdiv.find(".tf_search_item_title").wrapInner('<a href="'+this.merchant.buyurl+'" class="tf_search_item_link" target="tf_buyWin"></a>'); 
				
				if(this.args.infobox.price.link.enabled) 
					this.popupdiv.find(".tf_search_item_price").wrapInner('<a href="'+this.merchant.buyurl+'" class="tf_search_item_link" target="tf_buyWin"></a>'); 
			}
		}
		
		var	infobox = thefind.infobox.infoboxes[thefind.infobox.infomap['product_infocard']],
				tail = rootElement.getElementsByTagName('img')[0];
		
		(function(self) {
			infobox.args.show_callback = function() { 
				self.pandora_logging_show(popupParams); 
			};
			
			infobox.args.hide_callback = function() { 
				self.pandora_logging_hide(); 
			};
		})(this);
		
		thefind.infobox.show(
			'product_infocard', 
			this.popuptext, 
			rootElement, 
			false,
			tail
		);
		
		if (typeof googleAnalytics == 'object') {
			$TF("a.tf_util_clear_after.tf_search_item_link").click(function () { 
				googleAnalytics.clickoutsource = 5 
			}); // popup VisitSite button
			
			$TF("a.tf_search_item_link.tf_search_popup_merchant_link").click(function () {
				googleAnalytics.clickoutsource = 6
			}); // popup store link
		}
		
    var infocardargs = {
			ddkey: this.item.ddkey, 
			siteid: this.merchant.uniqsiteid,
			hasoffers: any(arrayGet(popupParams.item.item,"hasoffers"), false)
		};
    
		if (!thefind.utils.isEmpty(popupParams.item.item.hasoffers))
			infocardargs['hasoffers'] = popupParams.item.item.hasoffers;
    
		if (!thefind.utils.isEmpty(popupParams.item.item.reviewquery))
			infocardargs['reviewquery'] = popupParams.item.item.reviewquery;
		
		//console.log(infocardargs);
		//console.log(popupParams.item.item.reviewquery);
		//console.log(thefind.utils.isEmpty(popupParams.item.item.reviewquery));
		
		thefind.panel.set_args('infocard_popup', infocardargs);
		
		this.popup_shown = true;
		this.popup_root = $TF('#tf_infocard_popup_tab_content', infobox.elements.container);
		this.initEvents(this.popup_root);
  }

  this.hidePopup = function(event) {
		var	event = event || window.event,
				tg = (window.event) ? event.srcElement : event.target,
				reltg = (typeof event.relatedTarget != "undefined") 
					? event.relatedTarget 
					: (typeof event.toElement != "undefined")
						? event.toElement
						: null;
		
		this.popup_shown = false;
		
		if (!thefind.infobox.is_inside('product_infocard', reltg))
			thefind.infobox.hide('product_infocard');
  } 

	this.pandora_logging_show = function(params) {
    this.params = params;
		var now = new Date();
		this.showPopupStartTime = now.getTime();
	}

	this.pandora_logging_hide = function() {
    if (this.params) {
			if (this.showPopupStartTime) {
				var now = new Date();
				var delta = now.getTime() - this.showPopupStartTime;
				var delay = this.params["popupTrackingDelay"] || 1000; // default to 1 sec if not set
				if (delta >= delay) {
					if (this.params["cmJs"]) {
						this.params["cmJs"]();
					}
					if (this.params["pandoraParams"]) {
						var pandoraParams = this.params["pandoraParams"] + "&popupDisplayTime=" + delta + "&mouseovertype=" + (typeof pandoraLog == "object" ? pandoraLog.mouseovertype : 'product');
						ajaxlib.Get(this.params["pandoraScript"] + pandoraParams);
					}
					if (typeof googleAnalytics=="object" && googleAnalytics.mouseovereventenable==1) {
						//googleAnalytics.trackEvent(['popup', 'mouseover', googleAnalytics.mouseovertype]);
					  googleAnalytics.mouseovereventenable = 0;
					}
				}
				// if delta > threshold for adding to myfinds recently view
				if (this.params["item"]) {
					delay = this.params["popupMyfindsDelay"] || 5000; // default to 5 sec if not set
					if (delta >= delay) {
						this.params["item"].addToMyfinds("recent", "myfindspanel");
					}
				}
				// reset
				this.params = null;
				this.showPopupStartTime = null;
			}
		}
	}
	
  this.addToMyfinds = function(type, target, myfindslist) {
    if (typeof search != "undefined" && search.mode != "slideshow") {
      var	img = $TF(this.obj).find("img.tf_search_item_productimage"),
					zindex = 200,
					id = "#tf_utils_panel_myfinds_";
			
			switch (type) {
				case 'saved': id += "saved_products"; break;
				case 'recent': id += "recent_products", zindex = 600; break;
				case 'savedstore': id += "saved_stores"; break;
				case 'savedbrand': id += "saved_brands"; break;
			}
			
      var	destsel = id + (type == "recent" ? " img" : ""),
					dest = $TF(destsel);
			
      if (img.length > 0 && dest.length > 0) {
        this.addToMyfindsAnimation(img[0],dest[0],zindex,id);
      }
    }
		
		if (type == 'saved' || type == 'slideshow') {
			if (typeof googleAnalytics=='object') googleAnalytics.trackEvent(['favs', 'save_product', this.item.category]);
			this.queueXHR('myfindsaction=addsaved&item_id=' + this.item.ddkey + '&target=' + target + "&query=" + this.query + "&category=" + this.item.category);
		} else if (type == 'recent') {
			this.queueXHR('myfindsaction=addrecent&item_id=' + this.item.ddkey + '&target=' + target + "&query=" + this.query + "&category=" + this.item.category);
		} else if (type == 'savedstore') {
			if (typeof googleAnalytics=='object') googleAnalytics.trackEvent(['favs', 'save_store', this.merchant.name]);
			this.queueXHR('myfindsaction=addsavedstore&item_id=' + this.item.ddkey + '&target=' + target + "&query=" + this.query + "&category=" + this.item.category + "&store=" + this.merchant.name + "&storeid=" + this.merchant.uniqsiteid);
		} else if (type == 'savedbrand') {
			if (typeof googleAnalytics=='object') googleAnalytics.trackEvent(['favs', 'save_brand', this.item.brand]);
			this.queueXHR('myfindsaction=addsavedbrand&item_id=' + this.item.ddkey + '&target=' + target + "&query=" + this.query + "&category=" + this.item.category + "&brand=" + this.item.brand);
		} else if (type == 'flag') {
			if (typeof googleAnalytics=='object') googleAnalytics.trackEvent(['favs', 'flag_product', this.item.ddkey]);
			this.queueXHR('myfindsaction=addflag&item_id=' + this.item.ddkey + '&target=' + target + "&query=" + this.query + "&category=" + this.item.category);
		}
  }
	
	this.queueXHR = function(parms) {
    var urlargs = null;
    ajaxlib.Queue({method:'POST', url:wwwroot + '/myfinds.fhtml?' + parms, args: urlargs}, false);
    if (ajaxlib.xmlhttpReady())
      ajaxlib.Go();
	}
	
	this.addToMyfindsAnimation = function(img,dest,zindex,id) {
		var type = thefind.browser.type, 
				start = thefind.func.dimensions(img),
				end = thefind.func.dimensions(dest),
				windowSize = thefind.func.dimensions(window),
				browserBody = (thefind.browser.type == 'safari')?document.body:document.documentElement;
		
		if (type != 'netscape' && type != 'safari')
			start.y += browserBody.scrollTop;
		
		if (zindex == 200)
			end.x += (dest.offsetWidth>>1) - 12;
		
		end.y += browserBody.scrollTop-1;
		end.x -= 1;
		end.w = 25;
		end.h = 25;
		
		if (type == 'msie') {
			end.y += 3;
			end.x += 3;
		}
		
		box = document.createElement('div');
		cloned = img.cloneNode(false);
		box.appendChild(cloned);
		
		$TF(box).css({
			position: 	(type == 'safari' ? 'fixed' : 'absolute'),
			background: '#e0e0e0',
			border: '1px solid #aaa',
			zIndex: 1,
			left: 	(start.x - 1) + 'px',
			top: 		(start.y - 1) + 'px', 
			width:	start.w + 'px',
			height:	start.h + 'px'
		});
		
		$TF(cloned).css({
			zIndex:	zindex,
			width:	'100%',
			height:	'100%'
		});
		
		document.body.appendChild(box);
		
		$TF(box).animate({
			width: end.w + 20,
			height: end.h + 20,
			top: (start.y + ((start.h >> 1) - 13)),
			left: (start.x + ((start.w >> 1) - 13)),
			opacity: .2
		}, 150,'easein').animate({
			top: end.y,
			left: end.x,
			width: end.w,
			height: end.h,
			opacity: 0
		}, 200, null, function() {
			$TF(box).css({
				display: 'none'
			});
			
			$TF(id).animate({ 
				backgroundColor: '#DDDDFF' 
			},200).animate({ 
				backgroundColor: '#FFFFFF' 
			},400).animate({ 
				backgroundColor: '#EAEAEA' 
			},800);
		});
	}
	
  this.show_relateditems = function() {
    var ret = "";
    var relateditems = (this.lists.relateditems?this.lists.relateditems:null);
    if (!thefind.utils.isNull(this.item.itemnum) && relateditems) {
      if (!thefind.utils.isNull(relateditems) && !thefind.utils.isNull(relateditems[this.item.itemnum])) {
        ret = '<div class="tf_search_item_relateditems"><strong>If you like this,</strong> the store also recommends...<ul>';
        for (var i = 0; i < relateditems[this.item.itemnum].length; i++) {
          ret += thefind.tplmgr.GetTemplate("search.item.infobox.relateditems", relateditems[this.item.itemnum][i]);
        }
        ret += '</ul></div>';
      }
    }
    return ret;
  }
  this.show_crosslinks = function() {
    var ret = "";
    var crosslinks = (this.relatedchildren && this.relatedchildren.psrelq?this.relatedchildren.psrelq:null);
    if (!thefind.utils.isNull(crosslinks)) {
      ret = '<div class="tf_search_item_bottom_section">';
      ret += '<div class="tf_search_item_crosslinks"><strong>Find More:</strong> <ul class="tf_search_item_crosslinks_list">';
      for (var i = 0; i < crosslinks.length; i++) {
        ret += '<li>';
        ret += thefind.tplmgr.GetTemplate("search.item.infobox.crosslinks", crosslinks[i]);
        ret += '</li>';
      }
      ret += '</ul></div>';
      ret += '</div>';
    }
    return ret;
  }
  this.show_localstore = function() {
    var ret = "";
    if ((typeof this.store != 'undefined') && (typeof this.store.zip != 'undefined')) {
      if(this.merchant.nearbynowid)
        this.merchant.nearbynowid_link = 1;
      else if(this.merchant.availurl)
        this.merchant.availurl_link = 1;
      ret = thefind.tplmgr.GetTemplate("search.item.infobox.localstore", this);
    } 
    return ret;
  }
	
  this.show_certifications = function() {
    var	ret = "",
				certs = arrayGet(this,'relatedchildren.tags') || false;
    
		if (certs) {
      var name = type = display = link = list = "";
      
			for (var i=0; i<certs.length; i++) {
        name = certs[i].name;
        type = certs[i].type;
        display = certs[i].display;
        link = certs[i].url;
        list += "<li>";
				if (link) list += '<a href="'+link+'" class="tf_utils_link_external">';
				list += '<img src="/images/misc/badges/' + type + '/' + name + '.gif" />';
				if (link) list += "</a>";
				list += "<span>" + display + "</span></li>";
      }
			this.certification_list = list
			ret = thefind.tplmgr.GetTemplate("search.item.infobox.certifications", this);
    }
		
		return ret;
  }
	
  this.show_rating = function() {
    var between = function(value,min,max) {
					if(value >= min && value <= max)
						return true;
				},
				ret = "";
    
		if(this.merchant.rating != 'null' && this.merchant.rating) {
      var	rating = this.merchant.rating,
					rating_icon = "";
      
			if(this.merchant.ratingsource == "bizrate") {
        this.rating_display_name = "BizRate";
        this.rating_out_of = "of 10";
				if(between(rating,0,2))
          level = 'poor';
				if(between(rating,3,5))
          level = 'satisfactory';
				if(between(rating,6,8))
          level = 'good';
				if(between(rating,8,10))
          level = 'outstanding';
				rating_icon = '<img src="/images/icons/ratings/bizrate_'+level+'.gif" />';
      } else if (this.merchant.ratingsource == "reseller") {
        this.rating_display_name = "Reseller";
        this.rating_out_of = "of 10";
        var	check = [],
						checks = Math.floor(rating) / 2;
        
				for(var a = 0; a <= 4; a++)
          check[a] = 'resellerratings_check_off.png';
				for(var b = 0; b <= checks; b++)
          check[b] = 'resellerratings_check.png';
				for(var c = 0; c <= check.length && c < 5; c++)
          rating_icon += '<img src="/images/icons/ratings/'+check[c]+'" />';
      } else {
				this.rating_display_name = this.merchant.ratingsource;
      }
			this.rating_icon = rating_icon;
      ret = thefind.tplmgr.GetTemplate("search.item.infobox.rating", this);
    }
		return ret;
  }
	
  this.show_offers = function() {
    var	ret = "",
				offers = arrayGet(this,'relatedchildren.offerslist') || false;
    
		if(offers && offers.length > 0) {
      var	moreinfo_link = '<a class="tf_search_item_offers_more_offers" href="http://coupons.thefind.com/coupons/store/'+offers[0].merchant_uniqcname+'/">More coupons for '+offers[0].merchant_sitename+'</a>',
					show_offers_number = 1;
			
      ret = '<div class="tf_search_item_offers"><ul>';
			for (var i = 0; i < show_offers_number; i++) {
        var	merchant_buyurl = offer_buyurl =	null;
						//show_nocode = null;  <-- this seems superfluous -lazarus
        
				if(offers[i].coupncode && !offers[i].buyurl) merchant_buyurl = 1;
				if(!merchant_buyurl && offers[i].buyurl) merchant_buyurl = 1;
				/*
				if(!offers[i].couponcode) show_nocode = 1;
				if(offers[i].thirdpartyurl && !offers[i].merchant_buyurl) show_nocode = null;
        */
        var vars = {
							"offer": offers[i],
							"item": this,
							"show_merchant_buyurl": merchant_buyurl,
							"show_offer_buyurl": offer_buyurl,
							"moreinfo_link": moreinfo_link
						}; //,buyurl = offers[i].buyurl; <-- and so does this -lazarus
        
				if(offers[i].merchant_uniqsiteid == this.merchant.uniqsiteid)
          ret += thefind.tplmgr.GetTemplate("search.item.infobox.offers", vars);
      }
      ret += '</ul></div>';
    }
    return ret;
  }
  this.show_offers_local = function(args) {
    var ret = "";
    var show = args.show || "";
    var local_store = "";
    var offers = "";
    // FIXME make configurable
    show = {"local":true,"offers":true};
    if(show.local)
      local_store = this.show_localstore();
    if(show.offers && this.relatedchildren)
      offers = this.show_offers();
    ret += offers;
    ret += local_store;
    return ret;
  }
  this.show_description = function(args) {
    var ret = "";
    var tmpobj = {item: this, description: this.item.description}
    if (!thefind.utils.isNull(this.item.pageType)) {
      if (this.item.pageType == 'shopbyissue') {
        tmpobj = {
                  description: this.item.description,
                  unavailablemsg: this.item.unavailablemsg
                 }
      } 
    }
    ret = thefind.tplmgr.GetTemplate("search.item.infobox.description", tmpobj); 
    return ret;
  }
  this.show_prettyprice = function() {
    var type = this.item.currency;
    var symbols=new Array();
        symbols['USD'] = '$';
        symbols['GBP'] = '&pound;';
        symbols['EUR'] = '&euro;';
        symbols['CAD'] = '$';
        symbols['AUD'] = '$';
        symbols['NZD'] = '$';
        symbols['SGD'] = '$';
        symbols['INR'] = '&#8360;';
    var symbol = (symbols[type]?symbols[type]:'$');
    var ret = symbol+'--';
    var issale = this.item.issale;
    if(issale)
      var class1 = 'tf_saleprice';
    else
      var class1 = '';
    if (this.item.minprice && this.item.maxprice) {
      var price = symbol + parseFloat(this.item.minprice).toFixed() + " - "+symbol + parseFloat(this.item.maxprice).toFixed();
    } else if (this.item.price) {
      var price = symbol + parseFloat(this.item.price).toFixed(2);
    }
    if(price)
      ret = '<span class="'+class1+'">' + price + '</span>';
    
    return ret;
  }
  this.show_itemtags = function() {
    var issale = this.item.issale;
		var label = (this.args.options) ? arrayGet(this.args.options.sale,"label") : 'sale';
    var ret = '';
    ret += '<ul class="tf_search_item_tags">';
    if(issale)
      ret += '<li>'+label+'<l/i>';
    ret += '</ul>';
    return ret;
  }
  this.show_comparebutton = function() {
    var ret = "";
    if(this.item.quantity)
      ret = " tf_search_offers";
    return ret;
  }
  this.show_productactions = function(args) {
    // ret needs to be updated with store filter saved store information
    if (typeof this.saved == 'undefined')
      this.saved = {};
			
    var storeid = this.merchant.uniqsiteid;
    if ($TF("#tf_search_filters_list_store_control").find('#tf_filter_store_' + storeid).hasClass("tf_state_selected")) {
      this.saved.store = true;
    } 
    var brandid = this.saved.brand_id;
    if ($TF("#tf_search_filters_right_list_brand_container").find('#tf_filter_brand_' + brandid).hasClass("tf_state_selected")) {
       this.saved.brand = true;
    }
    ret = thefind.tplmgr.GetTemplate("search.item.infobox.productactions", this);
    return ret;
  }
	
	this.toggle_about_store = function(content) {
		var siteid = this.merchant.siteid;
		
		thefind.infobox.nuke("about_store_"+siteid)
		this.init_about_store_popup(siteid,content);
		thefind.infobox.show("about_store_"+siteid);
	}
	
 this.init_about_store_popup = function(siteid, contenturl) {
    thefind.tplmgr.Create(
			'about.store.border.'+siteid, 
			'<div class="tf_upfront_badge_closebutton">' +
			'<a href="#" class="tf_utils_infobox_close" onclick="thefind.infobox.hide(\'about_store_'+siteid+'\'); return false">X</a></div>' +
			'<div id="tf_about_store_content">(%$content)</div>'
		);
		
		thefind.infobox.add(
			"about_store_"+siteid, 
			{
				ajax: true,
				absolute: true, 
				center: true, 
				reposition: true, 
				resizeclose: true, 
				lightbox: 'tf_infobox_lightbox',
				width: '30em',
				border: 'about.store.border.'+siteid, 
				scollTop: true,
				tail: false, 
				bgcolor: '#fff', 
				font: 'Arial, sans-serif'
			}, 
			{
				targetid: 'tf_about_store_content',
				hasoffers: this.item.hasoffers,
				siteid: this.merchant.uniqsiteid,
				ddkey: this.item.ddkey
			}, 
			contenturl
		);
  }
	
  this.parseHTML = function() {
    var boxElement = document.getElementById(this.html.id);
    if (boxElement) {
      var contentElements = thefind.utils.getElementsByClassName(boxElement, "div", "tf_search_item");
      if (contentElements[0]) {
        var item = contentElements[0];
				
        this.item.title = getChildContentByClassName(item, "tf_search_item_title");
        var description = getChildContentByClassName(item, "tf_search_item_description");
        if (description && !description.match(/^\s*$/)) {
          this.item.description = description;
        }
				
        this.item.merchant_buyurl = getChildContentByClassName(item, "tf_search_item_link", "href");
        this.item.merchant_onclick = getChildContentByClassName(item, "tf_search_item_link", "onclick");
        this.item.image = getChildContentByClassName(item, "tf_search_item_productimage", "src");
        this.item.issale = (getChildContentByClassName(item, "tf_search_item_tag_sale", "src") != null);
        this.item.isnew = (getChildContentByClassName(item, "tf_search_item_tag_new", "src") != null);
				
        this.complete = true;
      }
    }
  }
  
  this.openBuyWindow = function(event,target) {
    if (typeof googleAnalytics=='object') {
      try {
        googleAnalytics.trackClickout({
          'trans':[
            this.merchant.cname, // store
            0.10 // total price
          ],
          'item':[
            this.googleanalytics.itemID, // SKU/item code
            this.item.title.replace(/<.*?>/g, ""), // product name
            any(this.item.category, 'none'), // category
            0.10, // price
            1 // quantity
          ],
          'event':[
            'clickout', // category
            typeof this.item.itemtype!='undefined' ? this.item.itemtype : googleAnalytics.myfindspanel, // action
            any(this.googleanalytics.affiliate, this.merchant.name) // label
          ]
        });
      } catch(e) {
        console.log('Error while attempting to throw GA tag', e);
      }
    }

		if (typeof $TF != 'undefined' && !$TF(target).isChildOf('div#tf_myfinds_panel_box'))
			this.addToMyfinds("recent", "myfindspanel");
    
		var buyurl = this.merchant.buyurl;
    if (this.args.show.friendlyurl == 1 && this.merchant.buyurl_extras) {
      buyurl += "?" + this.merchant.buyurl_extras;
    }
    
		return openBuyWin(buyurl, event);
  }
  this.emailToFriend = function(hash) {
    this.queueXHR('myfindsaction=email&itemids=' + hash);
  }   

  this.deleteFromMyfinds = function(type, target) {
		var parms = 'myfindsaction=' + type + '&item_id=' + this.item.ddkey + '&target=' + target + "&query=" + this.query + "&category=" + this.item.category;
		
		switch (type) {
			case 'deletesaved': this.queueXHR(parms); break;
			case 'deletesavedstore': this.queueXHR(parms + "&store=" + this.merchant.name + "&storeid=" + this.merchant.uniqsiteid); break;
			case 'deletesavedbrand': this.queueXHR(parms + "&brand=" + this.item.brand); break;
		}
  }

  this.handleClick = function(event, eventid) {
		if (!event.data)
			return;

    var	target = $TF(event.target),
				currentTarget = $TF(event.target),
				starelement = (currentTarget.hasClass("tf_savestar") 
					? currentTarget	
					: currentTarget.find(eventid)),
				func = function(type, arr, bool) {
					if (bool) {
						starelement.removeClass("tf_state_selected");
						
						if (arr.length) 
							arr.removeClass("tf_state_selected");
						
						event.data.deleteFromMyfinds("deletesaved" + type, "myfindspanel");
					} else {
						starelement.toggleClass("tf_state_selected");
						
						if (arr.length) 
							arr.toggleClass("tf_state_selected");
						
						event.data.addToMyfinds("saved" + type, "myfindspanel");
					}
					
					event.data.saved[type] = !bool;
					event.preventDefault();
				};
		
		switch (eventid) {
			case ".tf_search_item_actions_saveinmyfinds_link":
				if (starelement.hasClass("tf_state_selected")) {
					starelement.removeClass("tf_state_selected");
					event.data.deleteFromMyfinds("deletesaved", "myfindspanel");
					event.data.saved.item = false;
					event.preventDefault();
				} else {
					starelement.toggleClass("tf_state_selected");
					event.data.addToMyfinds("saved", "myfindspanel");
					event.data.saved.item = true;
					event.preventDefault();
				}
				
				break;
			
			case ".tf_search_item_actions_savestoreinmyfinds_link":
				var	filter_storeid = 'tf_filter_store_'+event.target.id.replace(/^tf_store_/, ""),
						filter_store_star = $TF("#tf_search_filters_list_store_control").find('#'+filter_storeid);
				
				func('store', filter_store_star, starelement.hasClass("tf_state_selected"));
				
				break;
			
			case ".tf_search_item_actions_savebrandinmyfinds_link":
				var	filter_brandid = 'tf_filter_brand_'+event.target.id.replace(/^tf_brand_/, ""),
						filter_brand_star = $TF("#tf_search_filters_right_list_brand_container").find('#' + filter_brandid);
				
				func('brand', filter_brand_star, starelement.hasClass("tf_state_selected"));
				
				break;
			
			case ".tf_search_item_actions_flag_link":
				event.data.addToMyfinds('flag');
				event.preventDefault();
				$TF(eventid).addClass("tf_utils_state_selected").html('Flagged for review');
				
				break;
			
			case "a.tf_search_item_actions_emailtofriend_link":
				// FIXME - show lightbox with email to friend form
				event.data.emailToFriend(event.data.item.ddkey);
				event.preventDefault();
				
				break;
			
			case "a.tf_search_item_link":
				// openBuyWindow returns the opposite of what you expect due to legacy event handling
				if (event.data.html.buywin && !event.data.openBuyWindow(event,target[0])) {
					event.preventDefault();
				}
				
				break;
			
			case "a.tf_utils_link_offers":
			
			case "a.tf_utils_link_external":
        var link = event.target;
        if (typeof link.href == 'undefined') {
          link = $TF(link).parent(eventid)[0];
        }
				
        if (link && link.href) {
          var href = link.href;
          if (eventid == "a.tf_utils_link_offers") {
            // Ugly hack for PaypalUK.  First figure out which of the offers was clicked, and if it requires us to append our buyurl then do so
            for (var i = 0; i < event.data.relatedchildren.offerslist.length; i++) {
              if (event.data.relatedchildren.offerslist[i].offer_buyurl == link.href) {
                if (event.data.relatedchildren.offerslist[i].offer_appendbuyurl == 1) {
                  href += encodeURIComponent(document.location.protocol + "//" + document.location.host + event.data.merchant.buyurl);
                }
              }
            }
          }
					
  				openBuyWin(href, event);
	  			event.preventDefault();
        }
				break;
			case ".tf_search_item_clusterlink":
				if (typeof googleAnalytics != 'object') 
					break;
				//track clickout of the cluster page for best price
				if ($TF(eventid).find('a.clusterlink.track_clickout')) { 
					googleAnalytics.trackEvent(['link', 'find_best_price', event.data.item.groupid ]);
				}
                                break;			
			case ".tf_search_item_coupon_link": 
				if (typeof googleAnalytics != 'object') 
					break;
				googleAnalytics.trackEvent(['store_coupon', target.html().replace(/(((.*)See all\s)|(\scoupons(.*)))/g, ""), 2]);
				break;
			case ".coupon_item_xml": 
				if (typeof googleAnalytics != 'object') 
					break;
				
				if (target.hasClass('.store.track_clickout')) { 
					googleAnalytics.trackEvent(['clickout', event.data.item.itemtype,  target.html().replace(/(.*)Shop now at /, ""), 8]);
				}
				
				if (target.hasClass('.store.track_clickout_code')) { 
					googleAnalytics.trackEvent(['clickout', event.data.item.itemtype,  target.html().replace(/Click to copy coupon and open /, ""), 7]);
				}
				
				if (target.hasClass('.affiliate.track_clickout')) {
					googleAnalytics.trackEvent(['coupons_clickout', 'affiliate', target.html().replace(/More information at /, ""), 2]);
				}

				if (target.hasClass('.stbuttontext')) {
					googleAnalytics.trackEvent(['share', googleAnalytics.cobrand, "http://w.sharethis.com/button/sharethis.js#publisher=9c0d2c89-f385-4651-ad1f-c0ccd5410e2f&amp;type=website&amp;buttonText=Share"]);
				}
				
				break;
			case ".tf_product_info": 
				if (typeof googleAnalytics != 'object') 
					break;
				
				if (target.hasClass('.store_logo.track_clickout')) {
					googleAnalytics.trackEvent(['store_coupon', target.attr("alt"), 1]);
				}

				break;
		}
  }

  this.init();
});

var buyWinRef = null;
function openBuyWin(buyItUrl, event) {

  if (event && (event.shiftKey || event.ctrlKey)) { // If the user is using a click modifier, let the browser handle it
    return true;
  }
	
	
	// if mailto, dont open new (blank) window but instead use window.location
	if (buyItUrl) {
		var protocol = buyItUrl.split(':')[0];
		
		if (protocol == 'mailto')
			var buyWinRef = window;
	}

  if (buyWinRef == null || buyWinRef.closed) {
    buyWinRef = window.open(buyItUrl, 'tf_buyWin',
     'left=20,top=20,titlebar=1,status=1,' +
     'location=1,menubar=1,toolbar=1,scrollbars=1,resizable=1'
    );
  } else {
    buyWinRef.location = buyItUrl;
  }
  if (buyWinRef) {
    buyWinRef.focus();
    return false;
  }
  return true;
}

if(typeof thefind!='undefined')thefind.dependencies.registerMany({"utils":["init","tplmgr","initjquery","ajaxlib","infobox","panel"],"html":["utils"],"jquery":["contextmenu","suggest"],"search":["suggest","input","search","filters"],"product":["list"]});