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;
};
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('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('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 TFSearchInfo(parent, args) {

  $TF(document).ready(function() {
    var target = $TF("."+args.id);
    target.click(function (event) {
	if (target.hasClass("tf_state_selected")) {
	   target.removeClass("tf_state_selected");
           queueXHR('myfindsaction=deletesavedsearch' + '&target=myfindspanel' + "&query=" + search.request.query);
	   event.preventDefault();
	} else {
	   target.toggleClass("tf_state_selected");
           if (typeof googleAnalytics=='object') googleAnalytics.trackEvent(['favs', 'save_search', search.request.query]);
           queueXHR('myfindsaction=addsavedsearch' + '&target=myfindspanel' + "&query=" + search.request.query);
	   event.preventDefault();
        }
    });
    //thefind.tplmgr.Create("subcategories_popup","asdf");
		thefind.infobox.add(
			'onebox_subcategories', { 
				margin: 5,
				absolute: true,
				width: '21em', 
				border: 'page.tfinfobox',
				event: 'click',
				titlebar: true,
				label: "More Catagories",
        ajax: false
			}, 
			null, 
			"search.subcategories_popup", //"search/subcategories_popup",
      "tf_more_subcategories"
		);

  });

}


/*
 * 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);
	
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;
}
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"],"search":["search","suggest","input","filters","info"],"jquery":["contextmenu","suggest"],"product":["list"],"myfinds":["panel.js;"]});