                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
try { if(!window.JSK$EPB && navigator.appVersion.match(/[345]\.[.0-9 ]+Safari/)) {
	var d = document.createElement('div');
	d.style.height = 0;
	var tgt = 'jsk-ifrmsess-' + Math.random();
	d.innerHTML = '<iframe id="' + tgt + '" name="' + tgt + '" src="about:blank" width=0 height=0 style="border: none"></iframe>';
	var f = function() {
		document.body.appendChild(d);
		var ifrsess = d.firstChild;
		var getFrame = function(FrameName, Parent) {
			var tp = Parent ? getFrameDoc(Parent) : document;
			var fr = tp.getElementById(FrameName).contentWindow;
			return fr;
		}
		var getFrameDoc = function(FrameName, Parent) {
			var FEl = getFrame(FrameName, Parent);
			return FEl.contentDocument || FEl.document;
		}

		var iDOC = getFrameDoc(tgt);
		var frm = iDOC.createElement('form');
		frm.method = 'post';frm.action = window.location.protocol + '//js-kit.com/api/session/refresh.js';
		iDOC.body.appendChild(frm);
		ifrsess.onreadystatechange = ifrsess.onload = function() {
			if(ifrsess.readyState && ifrsess.readyState != 'loaded'
				&& ifrsess.readyState != 'complete') return;
			ifrsess.onload = ifrsess.onreadystatechange = null;
			
		};
		frm.submit();
	}
	if(document.body) f();
	else setTimeout(f, 0);
} else {}} catch(e) {};
/*
 * Copyright (c) 2007 JS-Kit <support@js-kit.com>. All rights reserved.
 * You may copy and modify this script as long as the above copyright notice,
 * this condition and the following disclaimer is left intact.
 * This software is provided by the author "AS IS" and no warranties are
 * implied, including fitness for a particular purpose. In no event shall
 * the author be liable for any damages arising in any way out of the use
 * of this software, even if advised of the possibility of such damage.
 * $Date: 2010-05-27 08:04:51 -0700 (Thu, 27 May 2010) $
 * $Id: top.js 24122 2010-05-27 15:04:51Z jskit $
 */

if(!window.$JTA) {
  var $JTA = [];
  var $JTLT = { 
    vote: 'vote',
    votes: 'votes',
    msgNoHotItems: 'There are currently no Hot items on this site.',
    msgNoTopItems: 'There are currently no Top Rated items on this site.',
    msgNoScoredItems: 'There are currently no Top Scored items on this site.',
    msgNoPoll: 'Polls are not installed on this site.',
    msgNoPicks: 'There are currently no Picks items on this site.',
    msgNoComments: 'There are currently no Comments on this site.',
    adminConsole: 'Admin Console',
    install: 'Install',
    installing: 'Installing...',
    guest: 'Guest',
    cancel: 'Cancel',
    save: 'Save',
    saving: 'Saving...',
    installationWelcome: '<b>Welcome!</b>  To complete installation, open the <a href="javascript:void(0);" class="js-topAdminConsoleLaunch">Admin&nbsp;Console</a>.',
    adminMsgNoViews: 'There are currently no active views in Navigator.  It will not be displayed to your users until you activate a view.',
    adminMsgNoRatings: 'There are currently no items in your Top Rated view.  Install our <a href="http://js-kit.com/ratings" title="JS-Kit Ratings" target="_blank">Ratings</a> service to start populating your list.  If you have already installed Ratings, listings will be displayed when enough votes have been collected.',
    adminMsgNoScore: 'There are currently no items in your Top Score view.  Install our <a href="http://js-kit.com/ratings/" title="JS-Kit Score" target="_blank">Score</a> service to start populating your list.  If you have already installed Score, listings will be displayed when enough votes have been collected.',
    adminMsgNoRatingsNoHot: 'There are currently no items in your Hot view.  Install our <a href="http://js-kit.com/ratings" title="JS-Kit Ratings" target="_blank">Ratings</a> service to start populating your list.  If you have already installed Ratings, listings will be displayed when enough data has been collected.',
    adminMsgTitleUneditable: 'You have TITLE set in-line in your HTML page.  If you wish to use the console, remove title="..." from your <div class="js-kit-top"> tag.',
    adminMsgCountUneditable: 'You have COUNT set in-line in your HTML page.  If you wish to use the console, remove count="..." from your <div class="js-kit-top"> tag.',
    hotInProgress: 'JS-Kit is measuring raters\' activity to present the most popular items here. Please allow some time for meaningful data to be collected.'
  };
  var $JTL = window.JSTC_Translate || function(t) { return $JTLT[t] || t; }
}



if(!window.JSKitLib) JSKitLib = {vars:{}};





JSKitLib.isPreIE7 = function() {
	if (document.body && document.body.filters && parseInt(navigator.appVersion.split("MSIE") [1]) < 7)
		return true;
}

JSKitLib.isPreIE8 = function() {
	if (document.body && document.body.filters && parseInt(navigator.appVersion.split("MSIE") [1]) < 8)
		return true;
}

JSKitLib.isIE = function() {
	if (document.body && document.body.filters && navigator.appVersion.match(/MSIE/))
		return true;
}

JSKitLib.getBrowser = function() {
	if (JSKitLib.vars.browser) return JSKitLib.vars.browser;
	if (document.body && document.body.filters && navigator.appVersion.match(/MSIE/)) {
			JSKitLib.vars.browser = "IE";
	} else if ((navigator.appCodeName.toLowerCase()=="mozilla") 
		&& (navigator.appName.toLowerCase()=="netscape") 
		&& (navigator.product.toLowerCase()=="gecko") 
	) {
		if (navigator.userAgent.toLowerCase().indexOf("safari")!=-1) {
			JSKitLib.vars.browser = "safari";
		} else if (navigator.userAgent.toLowerCase().indexOf("firefox")!=-1) {
			JSKitLib.vars.browser = "gecko";
		}
	} else if (navigator.product && navigator.product.toLowerCase()=="gecko") {
		JSKitLib.vars.browser = "gecko";
	} else if (navigator.appName.match(/Opera/)) { 
		JSKitLib.vars.browser = "opera"; 
	}
	return JSKitLib.vars.browser;
}

JSKitLib.isFF3 = function() {
	return (navigator.userAgent.indexOf("Firefox/3") != -1);
}

JSKitLib.isGChrome = function() {
	return (navigator.userAgent.toLowerCase().indexOf('chrome') != -1);
}

JSKitLib.isSafari = function() {
	if (navigator.appVersion.match(/Safari/)) {
		return true;
	}
}

JSKitLib.isOpera = function() {
	if (navigator.appName.match(/Opera/)) {
		return true;
	}
}





JSKitLib.setEventHandler = function(obj, eventNames, eventHandler) {
	JSKitLib.fmap(eventNames, function(eventName) {
		obj["on" + eventName] = function(){
			eventHandler();
			return false;
		}
	});
}

JSKitLib.resetEventHandler = function(obj, eventNames) {
	JSKitLib.fmap(eventNames, function(eventName) {
		obj["on" + eventName] = function(){};
	});
}

JSKitLib.addEventHandler = function(obj, eventNames, eventHandler, capture) {
	JSKitLib.fmap(eventNames, function(e) {
		if (obj.addEventListener) {
			obj.addEventListener(e, eventHandler, !!capture);
		} else if (obj.attachEvent) {
			if (capture) {
				if (capture === true) capture = obj;
				capture.setCapture();
				capture.attachEvent('onlosecapture', eventHandler);
			}
			obj.attachEvent('on' + e, eventHandler);
		}
	});
}

JSKitLib.removeEventHandler = function(obj, eventNames, eventHandler, capture) {
	JSKitLib.fmap(eventNames, function(e) {
		if (obj.removeEventListener) {
			obj.removeEventListener(e, eventHandler, !!capture);
		} else if (obj.detachEvent) {
			if (capture) {
				if (capture === true) capture = obj;
				capture.detachEvent('onlosecapture', eventHandler);
				capture.releaseCapture();
			}
			obj.detachEvent('on' + e, eventHandler);
		}
	});
}

JSKitLib.setMouseEvent = function(obj, eventName, eventHandler) {
	var normalize = function(pr_event){
		e = pr_event || window.event;
		if (!e.target)
			e.target = e.srcElement || document;
		if (e.target.nodeType == 3)
			e.target = e.target.parentNode;
		if (!e.relatedTarget && e.fromElement)
			e.relatedTarget = (e.fromElement == e.target) ? e.toElement : e.fromElement;
		return e;
	};
	obj["onmouse" + eventName] = function(pr_event) {
		var e = normalize(pr_event);
		if (e.relatedTarget == obj || JSKitLib.isChildNodeOf(obj, e.relatedTarget)) return false;
		eventHandler(e);
	};
}

JSKitLib.stopEventPropagation = function(e) {
	if (!e) e = window.event;
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
}

JSKitLib.preventDefaultEvent = function(e) {
  if (!e) e = window.event;
  e.returnValue = false;
  if (e.preventDefault) e.preventDefault();
}

JSKitLib.deferCall = function(func, onlyIE) {
	if (!JSKitLib.vars.windowOnLoadFired && (!onlyIE || (onlyIE && JSKitLib.isIE() && !window.$JSKitNoDeferCallIfIE))) {
		JSKitLib.addEventHandler(window, ['load'], func);
	} else {
		func();
	}
}

JSKitLib.addHandlers = function(obj, moveHandler, upHandler, capture) {
	JSKitLib.addEventHandler(obj, ['mousemove'], moveHandler, capture);
	JSKitLib.addEventHandler(obj, ['mouseup'], upHandler, capture);
}

JSKitLib.removeHandlers = function(obj, moveHandler, upHandler, capture) {
	JSKitLib.removeEventHandler(obj, ['mousemove'], moveHandler, capture);
	JSKitLib.removeEventHandler(obj, ['mouseup'], upHandler, capture);
}

JSKitLib.notDraggable = function(element) {
	element.onselectstart = function(ev) { JSKitLib.stopEventPropagation(ev); return true; }
	element.onmousedown = JSKitLib.stopEventPropagation;
	return element;
}

JSKitLib.getMousePosition = function(e) {
	if (!e) var e = window.event;
	if (e.clientX || e.clientY) {
		return {x:e.clientX, y:e.clientY};
	} else {
		return {x:e.pageX, y:e.pageY};
	}
}

JSKitLib.preventSelect = function(element, exceptions) {
	var browser = JSKitLib.getBrowser();
	var prevent = function() {
		if (browser == 'IE' || browser == 'safari') {
			element.onselectstart = function() { return false; }
		} else if (browser == 'gecko') {
			JSKitLib.addClass(element, 'js-nsgecko');
		}
	}
	if (typeof exceptions == 'object') {
		var include = exceptions.include || [];
		var exclude = exceptions.exclude || [];
		// Do not handle for certain browsers
		if (exclude.length) {
			for (var i=0; i < exclude.length; i++) {
				if (exclude[i] != browser) {
					prevent();
				}
			}
		}
		// Handle for certain browsers
		if (include.length) {
			for (var i=0; i < include.length; i++) {
				if (include[i] == browser) {
					prevent();
				}
			}
		}
	} else {
		prevent();
	}
}

JSKitLib.timedRetry = function(obj) {
	if(obj.pred()) {
		obj.onSuccess();
	} else {
		obj.currentRetries = (obj.currentRetries || 0) + 1;
		if(obj.currentRetries > obj.maxRetries) {
			if(obj.onFailure) obj.onFailure();
		} else {
			if(obj.onRetry) obj.onRetry();
			setTimeout(function(){
					JSKitLib.timedRetry(obj);
				}, obj.timeout);
		}
	}
}

JSKitLib.addDOMLoadedListener = function(callback) {
	window.JSK$DOMLoadedCallbacks = window.JSK$DOMLoadedCallbacks || [];
	window.JSK$DOMLoadedCallbacks.push(callback);
	if (window.JSK$DOMLoadedCallbacks.length > 1)
		return;
	var totalListener = function() {
		JSKitLib.fmap(window.JSK$DOMLoadedCallbacks, function(c) { c(); });
	}
	switch (JSKitLib.getBrowser()) {
		case 'gecko':
		case 'opera':
			document.addEventListener("DOMContentLoaded", totalListener, false);
			break;
		case 'IE':
			var temp = document.createElement('div');
			(function() {
				try {
					temp.doScroll('left');
				} catch (e) {
					setTimeout(arguments.callee, 100);
					return;
				}
				totalListener();
			})();
			break;
		case 'safari':
			(function() {
				if (document.readyState != 'complete') {
					setTimeout(arguments.callee, 100);
					return;
				}
				totalListener();
			})();
			break;
		default:
			JSKitLib.addEventHandler(window, ['load'], totalListener);
	}
}






JSKitLib.addCss = function(cssCode, name, content) {
	var doc = content || document;
	if(name) {
		name = "js-" + name + "-css";
		if (doc.getElementById(name)) return;
	}
	var se = doc.createElement("style");
	se.type = "text/css";
	if(name) se.id = name;
	if (se.styleSheet) se.styleSheet.cssText = cssCode;
	else se.appendChild(doc.createTextNode(cssCode));
	var hd = doc.getElementsByTagName("head");
	if(hd && hd[0]) hd[0].appendChild(se);
	else if (JSKitLib.isGChrome()) {
		doc.body.insertBefore(se, doc.body.firstChild);
	} else doc.write('<style>'+cssCode+'</style>');
}

JSKitLib.getElementsByClass = function(node, searchClass, tag) {
	var classElements = [];
	node = node || document;
	tag = tag || '*';
	var tagElements = node.getElementsByTagName(tag);
	var regex = new RegExp("(^|\\s)" + searchClass + "(\\s|$)");
	for (var i=0, j=0; i < tagElements.length; i++) {
		if (regex.test(tagElements[i].className)) {
			classElements[j] = tagElements[i];
			j++;
		}
	}
	return classElements;
};

JSKitLib.mapClass2Object = function(ctl, e) {
        if(e.className) {
                var arr = String(e.className).split(/[ ]+/);
                JSKitLib.map(function(el) { ctl[el] = e }, arr);
        }
        if(e.name) ctl[e.name] = e;
        try {
                var self = this;
                JSKitLib.map(function(child) {
                        JSKitLib.mapClass2Object(ctl, child);
                }, e.childNodes);
        } catch(e){}
        return ctl;
}

JSKitLib.hasClass = function(element, className) {
	return element.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'));
}

JSKitLib.addClass = function(element, className) {
	if (!JSKitLib.hasClass(element, className)) {
		element.className += ' ' + className;
	}
}

JSKitLib.removeClass = function(element, className) {
	if (JSKitLib.hasClass(element, className)) {
		var regex = new RegExp('(\\s|^)' + className + '(\\s|$)');
		element.className = element.className.replace(regex, ' ');
	}
}





JSKitLib.addPNG = function(node, imageURL) {
	if (JSKitLib.isIE()) {
		var cp = $JSKitGlobal.cachedPngs;
		JSKitLib.fmap(cp, function(img) {
			img.nodes = JSKitLib.filter(function(elm) { return elm != node; }, img.nodes);
		});
		if(cp[imageURL]) {
			if(cp[imageURL].loaded) {
				node.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + imageURL + "', sizingMethod='crop')"
			} else {
				cp[imageURL].nodes.push(node);
			}
		} else {
			cp[imageURL] = {nodes:[node]};
			var tPng = document.createElement("IMG");
			tPng.style.display = "none";
			tPng.onload = function() {
				cp[imageURL].loaded = true;
				var n = cp[imageURL].nodes;
				for(var i=0; i<n.length; i++) {
					n[i].runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + imageURL + "', sizingMethod='crop')";
				}
				cp[imageURL].nodes = [];
			};
			node.appendChild(tPng);
			tPng.src = imageURL;
		}
	} else {
		node.style.backgroundImage = 'url(' + imageURL + ')';
		node.style.backgroundRepeat = 'no-repeat';        
	}
	return node;
}

JSKitLib.preloadImg = function(imgURL) { 
	if (!JSKitLib.preloadImgList) JSKitLib.preloadImgList = {};
	if (!JSKitLib.preloadImgList[imgURL]) {
		(new Image()).src = imgURL; 
		JSKitLib.preloadImgList[imgURL] = true;
	}
};

JSKitLib.pngBar = function(color, div, fixed) {
	var str;
	var url = "'//js-kit.com/images/bars/bar-" + color + ".png'";
	if(document.body && document.body.filters) {
		str = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src="
			+ url + ", sizingMethod='"+(fixed?'crop':'scale')+"')";
		if(div) div.runtimeStyle.filter = str;
		return "filter: " + str + ";";
	} else {
		str = "url(" + url + ")";
		if(div) div.style.backgroundImage = str;
		return "background: " + str + ";";
	}
};

JSKitLib.createMiniStarObject = function(rating, scale, specs) {
	var fullStar = specs.full;
	var emptyStar = specs.empty;
	var starWidth = specs.width;
	var starHeight = specs.height;

	var setImage = function(star, imageURL) {
		if(star.imageURL == imageURL)
			return; // Already set and we know it

		star.imageURL = imageURL;
		JSKitLib.addPNG(star, imageURL);
	}

	var obj = document.createElement('div');
	var objWidth = 0;
	var objHeight = starHeight;

	/* Increment by Full Star Ratings */
	for (var i=2; i <= scale; i += 2) {
		var star = document.createElement('div');

		star.style.cssFloat   = 'left';
		star.style.styleFloat = 'left';
		star.style.width    = starWidth + 'px';
		star.style.height   = starHeight + 'px';
		star.style.fontSize = starHeight + 'px'; // ie6

		objWidth += starHeight;

		if (rating >= i) {
			setImage(star, fullStar);
		} else {
			setImage(star, emptyStar);
		}

		obj.appendChild(star);
	}

	JSKitLib.setStyle(obj, "height: " + objHeight + "px; width: " + objWidth + "px; float: left; margin-right: 5px;");

	return obj;
}





JSKitLib.getOuterHTML = function(node) {
	var clone = node.cloneNode(true);
	var parent = document.createElement('div');
	parent.appendChild(clone);
	var ihtml = parent.innerHTML;

    // ff converts sp characters inside of href to hex ascii
	var ihtmlHref = ihtml.match(/href\s*=\s*"[^"]*(%7B|%7D)[^"]*"/g) || [];
	for (var i=0; i< ihtmlHref.length; i++) {
		var a = ihtmlHref[i];
		var b = a.replace(/%7B/g, '{');
		b = b.replace(/%7D/g, '}');
		ihtml = ihtml.replace(a, b);
	}
	return ihtml;
};

JSKitLib.html = function() {
        var div = document.createElement("div");
        for(var text = '', i = 0; i < arguments.length; i++)
                text += arguments[i];
        div.innerHTML = text;
        var ch = div.firstChild;
        div = null;
        return ch;
}

JSKitLib.text = function(text, element, clear) {
	var textNode = document.createTextNode(text);
	if (element) {
		if (clear) JSKitLib.removeChildren(element);
		element.appendChild(textNode);
	}
	return textNode;
}

JSKitLib.attachDescriptors2Elements = function(elements, layoutBlocksPrefix, descriptors, parentStructure) {
	JSKitLib.fmap(elements, function(element, id) {
		var pattern = id.match(layoutBlocksPrefix + "(.*)");
		var name = pattern ? pattern[1] : undefined;
		if (name && typeof(descriptors[name]) == "function") {
			var node = descriptors[name](element, parentStructure);
			if (node) element.appendChild(node);
		}
	});
}

JSKitLib.toDOM = function(template, layoutBlocksPrefix, descriptors) {
	var content = JSKitLib.html(template);
	var elements = JSKitLib.mapClass2Object({}, content);
	var structure = {
		"set" : function(name, element) { elements[layoutBlocksPrefix + name] = element; },
		"get" : function(name, ignorePrefix) { return elements[((ignorePrefix) ? "" : layoutBlocksPrefix) + name]; },
		"content" : content
	};
	JSKitLib.attachDescriptors2Elements(elements, layoutBlocksPrefix, descriptors, structure);
	return structure;
}

JSKitLib.htmlQuote = function (newValue, param) {
	newValue = newValue.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")
	param = param || {};
	if(!param.title)
		newValue = newValue.replace(/ /,"&nbsp;");
	if(param.attribute)
		newValue = newValue.replace(/"/g,"&quot;");
	return newValue;
}

JSKitLib.htmlUnquote = function (newValue) {
	return newValue.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&");
}

JSKitLib.addScript = function(src, content, callback) {
	var sId = "js-kit-script-"+src.replace(/[\/.]/g, '');
	content.jsk$scriptId = sId;
	if(document.getElementById(sId)) {
		if (callback) callback();
		return;
	}
	var s = document.createElement('script');
	s.id = sId;
	s.type ='text/javascript';
	s.charset = 'utf-8';
	s.src = src;
	content.appendChild(s);
	if (callback) {
		s.onload = s.onreadystatechange = function() {
			if (s.readyState && s.readyState != 'loaded' && s.readyState != 'complete') return;
			s.onreadystatechange = s.onload = null;
			callback();
		}
	}
	return s;
}

JSKitLib.stripTags = function(text) {
	var r = /<\/?(a|em|strong|i|b|u|sup|sub|object|param|embed|span|pre|p)(.|\n)*?>/gi;
	text = text.replace(/<object(.|\n)+?<\/object>/gi,"[video]");
	text = text.replace(r,"");
	return (text.length > 150) ? text.slice(0,150) + "..." : text;
}

JSKitLib.createHiddenIframe = function(id, target, cb, clearOnload, src) {
	clearOnload = (typeof clearOnload == 'undefined' ? true : !!clearOnload);
	src = src || 'about:blank';
	target = target || document.body;
	var d = document.createElement('div');
	d.style.height = 0;
	d.innerHTML = '<iframe id="' + id + '" name="' + id + '" src="' + src + '" width="0" height="0" frameborder="0"  style="border: none"></iframe>';
	target.appendChild(d);
	var ifr = d.firstChild;
	if (cb) {
		ifr.onreadystatechange = function(e) {
			if (ifr.readyState && ifr.readyState != 'loaded' && ifr.readyState != 'complete') return;
			if (clearOnload) {
				ifr.onreadystatechange = ifr.onload = null;
			}
			cb();
		};
		if (!JSKitLib.isOpera()) {
			ifr.onload = ifr.onreadystatechange;
		}
	}
	return ifr;
}

JSKitLib.overlapSelectsIE = function(target) {
	var container = document.createElement('div');
	container.innerHTML = '<iframe style="position: absolute; z-index: -1; filter: mask(); border: 0; margin: 0; padding: 0; top: 0; left: 0; width: 9999px; height: 9999px; overflow: hidden;"></iframe>';
	target.appendChild(container.firstChild);
}

JSKitLib.openPopup = function(url, extConfig){
	var target = '_blank';
	var config = { 
		'width' : '960',
		'height' : '800',
		'status' : 'no',
		'menubar' : 'no',
		'toolbar' : 'no',
		'resizable' : 'no',
		'location'  : 'yes',
		'scrollbars' : 'yes',
		'directories': 'no'};

	JSKitLib.fmap(extConfig || [], function(value, key){
		if (key == 'target') target = value; else config[key] = value; 
	});

	var calcScreenDimensions = function(){
		if (JSKitLib.isOpera()) {
			var doc = (document.compatMode == "BackCompat") ? document.body : document.documentElement;
			return {'width': doc.clientWidth,
				'height': doc.clientHeight};
		}
		return {'width': screen.width,
			'height': screen.height};
	};

	var calcCorrections = function() {
		if (JSKitLib.isOpera()) return {'height': 35, 'width': 10, 'top' : 0}; 
		if (JSKitLib.isSafari() && !JSKitLib.isGChrome()) return {'height': 150, 'width': 0, 'top' : 100};
		return {'height': 0, 'width': 0, 'top' : 0};
	};

	var screenDimensions = calcScreenDimensions();
	var corrections = calcCorrections();

	if (config.height > screenDimensions.height - corrections.height) config.height = screenDimensions.height - corrections.height;
	if (config.width > screenDimensions.width - corrections.width) config.width = screenDimensions.width - corrections.width;

	if (!(config.left && config.top) && config.width && config.height) {
		config.left = Math.round((screenDimensions.width - config.width)/2);
		config.top = Math.round((screenDimensions.height - corrections.top - config.height)/2);
	}

	var params = JSKitLib.fmap(config, function(value, key) {return key + "=" + value;}).join(", ");
	return window.open(url, target, params);
}





// rounds number to x decimal places
JSKitLib.round = function(number, x) {
	x = (!x ? 2 : x);
	return Math.round(number*Math.pow(10,x))/Math.pow(10,x);
}

JSKitLib.zeroPad = function(number, x) {
	number = JSKitLib.round(number, x);
	var text = new String(number);
	var matches = text.match(/(\d*)(\.(\d*))?/) || [];
	var decimal = matches[3] || '';
	if (!decimal) {
		text += '.';
	}
	var count = x - decimal.length;
	for (var i=0; i<count; i++) {
		text += '0';
	}
	return text;
}





function JSDL(elmParent, arrDragElms) {
       var self = this;
       self.isIE = JSKitLib.isIE();
       var drgElms = arrDragElms || [elmParent];
       for(var i=0; i<drgElms.length; i++) {
               self.addDraggableChild(drgElms[i]);
       }
       self.elmParent = elmParent;
       self.setParent = 1;
}

JSDL.prototype.reSetDragParent = function () {
       if(!this.setParent) return;
       if(this.elmParent.parentNode!=document.body
       || JSKitLib.getStyleProperty(this.elmParent, 'position') != 'absolute') {
               var elmPos;
               if(this.elmParent.parentNode) {
                       elmPos = this.getElmAbsPos(this.elmParent, false);
                       this.elmParent.parentNode.removeChild(this.elmParent);
               }
               document.body.appendChild(this.elmParent);
               this.elmParent.style.position = 'absolute';
               if(elmPos) {
                       this.elmParent.style.left = elmPos.x + "px";
                       this.elmParent.style.top = elmPos.y + "px";
               }
       }
       this.setParent = 0;
}

JSDL.prototype.getCurScroll = function() {
       var scroll_left=0,scroll_top=0;
       if(self.pageXOffset){
               scroll_left=self.pageXOffset;
       } else {
               if(document.documentElement&&document.documentElement.scrollLeft){
                       scroll_left=document.documentElement.scrollLeft;
               } else {
                       if(document.body){
                               scroll_left=document.body.scrollLeft;
                       }
               }
       }
       if(self.pageYOffset){
               scroll_top=self.pageYOffset;
       } else {
               if(document.documentElement&&document.documentElement.scrollTop){
                       scroll_top=document.documentElement.scrollTop;
               } else {
                       if(document.body){
                               scroll_top=document.body.scrollTop;
                       }
               }
       }
       return {"scroll_left":scroll_left,"scroll_top":scroll_top};
}

JSDL.prototype.getElmAbsPos = function (element, usescroll){
       var x=0;
       var y=0;
       var e=element;
       var scroll_left=0,scroll_top=0,cur_scroll;
       if(usescroll){
               cur_scroll=this.getCurScroll();
               scroll_left=cur_scroll.scroll_left;
               scroll_top=cur_scroll.scroll_top;
       }
       if(!this.isIE){
               while(e){
                       x+=e.offsetLeft;
                       y+=e.offsetTop;
                       e=e.offsetParent;
               }
               e=element;
               while(e && e!=document.body && e!=document.documentElement){
		       x -= e.scrollLeft || 0;
		       y -= e.scrollTop || 0;
                       e=e.parentNode;
               }
               if(usescroll){
                       x-=scroll_left;
                       y-=scroll_top;
               }
               return {x:x,y:y};
       }
       e=element;
       while(e){
               var left_border=0;
               var top_border=0;
               if(e!=element){
                       var left_border = parseInt(e.style.borderLeftWidth) || 0;
                       var top_border = parseInt(e.style.borderTopWidth) || 0;
               }
               if(document.compatMode == "BackCompat"){
                       x+=e.offsetLeft-left_border;
                       y+=e.offsetTop-top_border;
               } else {
                       x+=e.offsetLeft+left_border;
                       y+=e.offsetTop+top_border;
               }
               try {
                       e=e.offsetParent;
               } catch(err) { e=null; };
       }
       if(usescroll){
               x-=scroll_left;
               y-=scroll_top;
       }
       return {x:x,y:y};
}

JSDL.prototype.addDraggableChild = function(dragElm) {
       var self = this;
       dragElm.style.cursor = "move";
       dragElm.onmousedown = function(e){self.onStartDragHandler(e);}
}

JSDL.prototype.onStartDragHandler = function (e) {
       var self = this;
       self.reSetDragParent();
       e=e || window.event;
       var elmPos = self.getElmAbsPos(this.elmParent, false);
       var mousePos = JSKitLib.getMousePosition(e);
       self.startx = mousePos.x - elmPos.x;
       self.starty = mousePos.y - elmPos.y;
       var maxLeft = document.body.clientWidth - self.elmParent.offsetWidth -
               (parseInt(self.elmParent.style.marginLeft) || 0) -
               (parseInt(self.elmParent.style.marginRight) || 0);

       var onMoveDragHandler = function(event) {
               event = event || window.event;
               var mousePos = JSKitLib.getMousePosition(event);
               var left = mousePos.x - self.startx;
	       self.elmParent.style.left = (left >= maxLeft ? maxLeft : (left < 0 ? 0 : left)) + "px";
               self.elmParent.style.top = (mousePos.y - self.starty < 0) ? 0 : (mousePos.y - self.starty) + "px";
       }

       var onStopDragHandler = function(event) {
               event = event || window.event;
               JSKitLib.removeHandlers(document, onMoveDragHandler, onStopDragHandler, self.elmParent);
               JSKitLib.stopEventPropagation(event);
               if(self.elmParent.jsk$on_stop_drag) self.elmParent.jsk$on_stop_drag(e);
       }

       JSKitLib.addHandlers(document, onMoveDragHandler, onStopDragHandler, self.elmParent);
       JSKitLib.stopEventPropagation(e);
       JSKitLib.preventDefaultEvent(e);
       if(self.elmParent.jsk$on_start_drag) self.elmParent.jsk$on_start_drag(e);
}





JSKitLib.removeChildren = function(element) {
	while(element && element.hasChildNodes())
		element.removeChild(element.firstChild);
}

JSKitLib.visible = function(element) {
	return element.style.display != 'none';
}

JSKitLib.show = function(element, style) {
	element.style.display = style || '';
}

JSKitLib.hide = function(element) {
	element.style.display = 'none';
}

JSKitLib.toggle = function(element, style) {
	(element.style.display == 'none') ? JSKitLib.show(element, style) :  JSKitLib.hide(element);
}

JSKitLib.getStyle = function(element) {
	if (typeof element.style.cssText != "undefined") {
		return element.style.cssText;
	} else {
		return element.getAttribute("style");
	}
}

JSKitLib.setStyle = function(element, style) {
	if (typeof element.style.cssText != "undefined") {
		element.style.cssText = style;
	} else {
		element.setAttribute("style", style);
	}
}

JSKitLib.addStyle = function(element, style) {
	var oldStyle = JSKitLib.getStyle(element);
	JSKitLib.setStyle(element, oldStyle + '; ' + style); // IE needs ;
}

JSKitLib.getStyleProperty = function(el, prop) {
	if (typeof el == 'string') {
		el = document.getElementById(el);
	}
	if (el.currentStyle) {
		return el.currentStyle[prop];
	} else if (window.getComputedStyle) {
		return document.defaultView.getComputedStyle(el, null).getPropertyValue(prop);
	} else {
		return el.style[prop];
	}
}

JSKitLib.findPos = function(obj) {
	var origObj = obj;
	var curleft = curtop = curright = curbottom = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft;
		curtop = obj.offsetTop;
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		}
	}
	curright = curleft + origObj.offsetWidth;
	curbottom = curtop + origObj.offsetHeight;
	return [curleft,curtop,curright,curbottom];
}

JSKitLib.calcCenterPos = function(elmWidth, elmHeight) {
	var doc = (document.compatMode == "BackCompat") ? document.body : document.documentElement;
	var scroll = JSDL.prototype.getCurScroll();
	return [
		scroll.scroll_left + Math.max(0, Math.round((doc.clientWidth - elmWidth)/2)),
		scroll.scroll_top + Math.max(0, Math.round((doc.clientHeight - elmHeight)/2))
	];
}

JSKitLib.getDocSize = function (){
	var doc_width,doc_height;
	if(typeof window.innerWidth=="number"){
		if(document.documentElement && document.defaultView && typeof document.defaultView.scrollMaxY=="number"){
			doc_height=document.documentElement.offsetHeight-document.defaultView.scrollMaxY;
			doc_width=document.documentElement.offsetWidth;
		} else {
			doc_height=window.innerHeight;
			doc_width=window.innerWidth;
		}
	} else {
		if(document.documentElement && typeof document.documentElement.clientWidth=="number" && document.documentElement.clientWidth){
			doc_height=document.documentElement.clientHeight;
			doc_width=document.documentElement.clientWidth;
		} else {
			if(document.compatMode == "BackCompat"){
				doc_height=document.body.offsetHeight;
				doc_width=document.body.offsetWidth;
			} else {                                
				doc_height=document.body.clientHeight;
				doc_width=document.body.clientWidth;
			}
		}
	}
	return [doc_height,doc_width];
}

JSKitLib.getJSKitBodyElement = function() {
	var be = document.getElementById('js-kit-body-element');
	if (!be) {
		be = document.createElement('div');
		be.id = "js-kit-body-element";
		document.body.appendChild(be);
	}
	return be;
}

JSKitLib.isChildNodeOf = function(parent, child) {
	if (parent === child) 
		return false
	while (child && child !== parent) {
		try {child = child.parentNode;}
		catch(e){child = parent;}
	}
	return child === parent;
}

JSKitLib.replaceChildren = function(where, replacement) {
	JSKitLib.removeChildren(where);
	JSKitLib.addChild(where, replacement);
}

JSKitLib.addChild = function(to, what) {
	if (typeof(to) != 'object')
		return;
	if(arguments.length == 3 && arguments[2])
		to.insertBefore(what, to.firstChild);
	else
		to.appendChild(what);
}

JSKitLib.hasParentNode = function(el) {
	return el && el.parentNode && el.parentNode.nodeType != 11;
}

JSKitLib.setOpacity = function(div, val) {
	if(document.body.filters) {
		if(val == 1) div.style.filter = '';
		else div.style.filter = 'alpha(opacity: ' + Math.round(val * 100) + ')';
	} else {
		div.style.opacity = val;
	}
}





JSKitLib.setThumbImage = function(args) {

	if (typeof args != 'object')
		return;

	var element     = args.element;
	var ud          = args.ud;
	var actionable  = args.actionable;
	var imageURL    = args.imageURL;
	var ignoreEmpty = args.ignoreEmpty;
	var numVotes    = args.numVotes; 
	var thumbWidth  = args.thumbWidth;
	var thumbHeight = args.thumbHeight;

	if(element.imageURL != imageURL){
		element.imageURL = imageURL
		JSKitLib.addPNG(element, imageURL);
	}

	var offsetTop=0;
	var offsetLeft=0;
	if(ud == 'down') offsetLeft=-thumbWidth;
	if((!actionable)||(!numVotes && !ignoreEmpty)) offsetTop=-thumbHeight;
	if(JSKitLib.isIE() && !JSKitLib.isPreIE7()){
		element.parentNode.parentNode.style.left=offsetLeft+'px';
		element.parentNode.parentNode.style.top=offsetTop+'px';
	} else {
		element.parentNode.style.left=offsetLeft+'px';
		element.parentNode.style.top=offsetTop+'px';
	}
}

// Returns an single div with a specified thumb image
JSKitLib.createThumbImage = function(args) {

	if (typeof args != 'object')
		return;

	var ud = args.ud;
	var actionable = args.actionable;
	var imageURL = args.imageURL;
	var ignoreEmpty = args.ignoreEmpty;
	var numVotes = args.numVotes;
	var thumbWidth = args.thumbWidth;
	var thumbHeight = args.thumbHeight;

	var div1 = document.createElement('div');
	var div2 = document.createElement('div');
	var div3 = document.createElement('div');

	div3.style.position = 'relative';
	div3.style.width = thumbWidth + 'px';
	div3.style.height = thumbHeight + 'px';
	div3.style.overflow = 'hidden';

	div2.style.position = 'absolute';
	div2.style.width = thumbWidth + 'px';
	div2.style.height = thumbHeight + 'px';

	// div1 is full size of all thumb images, and uses offset and 
	// overflow of its parents to show specific thumb image
	div1.style.width = (thumbWidth * 2) + 'px';
	div1.style.height = (thumbHeight * 2) + 'px';

	if(JSKitLib.isIE() && !JSKitLib.isPreIE7()){
		var divtmp = document.createElement('div');
		divtmp.style.width = (thumbWidth * 2) + 'px';
		divtmp.style.height = (thumbHeight * 2) + 'px';
		div3.appendChild(div2);
		div2.appendChild(divtmp);
		divtmp.appendChild(div1);
	} else {
		div2.appendChild(div1);
	}

	div3.appendChild(div2);

	JSKitLib.setThumbImage( { element: div1, ud: ud, actionable: actionable, imageURL: imageURL, ignoreEmpty: ignoreEmpty, numVotes: numVotes, thumbWidth: thumbWidth, thumbHeight: thumbHeight } );

	return div3;

}





JSKitLib.map = function(f, arr) {
	if(arr) for(var i = 0; i < arr.length; i++) f(arr[i], i, arr);
	return arr;
}

JSKitLib.filter = function(f, arr) {
	var newArr = [];
	if(arr)
		for(var i = 0; i < arr.length; i++)
			if(f(arr[i], i, arr))
				newArr.push(arr[i]);
	return newArr;
}

JSKitLib.lookup = function(f, arr){
	return JSKitLib.filter(f, arr).shift();
}

JSKitLib.fmap = function(o,f) {
	var r, a = [], l = o.length;
	if(l > 0 || l === 0)
		for(var i = 0; i < l; i++) {
			r = f.call(this,o[i],i,arguments);
			if(r !== undefined) a.push(r);
		}
	else
		for(var i in o)
			if(o.hasOwnProperty(i)) {
				r = f.call(this,o[i],i,arguments);
				if(r !== undefined) a.push(r);
			}
	return a;
}

JSKitLib.foldl = function(acc,o,f) {
	var r, l = o.length;
	if(l > 0 || l === 0)
		for(var i = 0; i < l; i++) {
			r = f.call(this,o[i],acc,i);
			if(r != undefined) acc = r;
		}
	else
		for(var i in o)
			if(o.hasOwnProperty(i)) {
				r = f.call(this,o[i],acc,i);
				if(r != undefined) acc = r;
			}
	return acc;
}

JSKitLib.intersperse = function(f) {
	return JSKitLib.foldl([], this, function(e, acc, i) {
		if(acc.length) acc.push(f);
		acc.push(e);
	});
}

JSKitLib.merge = function() {
	return Array.prototype.concat.apply([], arguments);
}

JSKitLib.cloneObject = function(obj) {
	return JSKitLib.foldl({}, obj, function(value, acc, key) { acc[key] = value; });
}





if (typeof JSKitLib.vars.windowOnLoadFired == 'undefined') {
        JSKitLib.vars.windowOnLoadFired = false;
        JSKitLib.addEventHandler(window, ['load'], function(){ JSKitLib.vars.windowOnLoadFired = true; });
}





JSKitLib.getRef = function(self) {
	var wl = window.location;
	return wl.protocol + "//" + self.config.domain + wl.pathname;
}

JSKitLib.readConfig = function(wtype, target, cf) {
	cf = cf || {};
	var gtags = JSKitLib.parseConfigTags(document, wtype, 'span');
	var ltags = JSKitLib.parseConfigTags(target, '', 'span');
	var gc = window.JSKitConfig || {};
	for(var i = 3; i < arguments.length; i++) {
		var arg = arguments[i];
		if(typeof(arg) == 'string') arg = [arg];
		var name = arg[0];
		var value = cf[name] || target.getAttribute(name) || ltags[name]
			|| gc[wtype + '-' + name] || gtags[name];
		var wl = window.location;
		switch (name) {
			case 'path': value = JSKitLib._normPath(target, value); break;
			case 'permalink':
				value = value || wl.href.replace(wl.hash,'');
				if (!value.match(/^https?:\/\//))
					value = "http://" + wl.host + value.replace(/^([^\/]+)/, "/$1");
				break;
			case 'title': value = value || document.title; break;
			case 'domain': value = value || wl.host; break;
		}
		if(arg.length > 1) {
			if(typeof(arg[1]) == 'number') {
				if(value) {
					var n = parseInt(value);
					if(isNaN(n) || n < 0) {
						if(value == "no") value = 0;
						else value = arg[1];
					} else value = n;
				} else value = arg[1];
			} else if(typeof(arg[1]) == 'object') {
				for(var j=arg[1].length; j; j--)
					if(arg[1][j-1] == value) break;
				if(!j) value = arg[1][j];
			} else {
				if(!value) value = arg[1];
			}
		}
		cf[name] = value;
	}
	return cf;
}

JSKitLib.parseConfigTags = function(target, wtype, tag) {
	var cache = document._widgets_config;
	if (wtype && cache && cache[wtype])
		return cache[wtype];
	var regp = wtype ? wtype+'?-' : '';
	var nodes = target.getElementsByTagName(tag);
	var config = {};
	for (var i = 0; i < nodes.length; i++) {
		var reg = RegExp("^js-kit-config-"+regp+"(.*)$");
		var m = reg.exec(nodes[i].className);
		if (m && m.length) {
			config[m[1].toLowerCase()] = nodes[i].innerHTML;
			nodes[i].style.display = 'none';
		}
	}
	if (wtype) {
		document._widgets_config = document._widgets_config || {};
		document._widgets_config[wtype] = config;
	}
	return config;
}

JSKitLib._normPath = function(target, path) {
	var wl = window.location;
	var uniq = String(target.getAttribute("uniq") || target.getAttribute("unique") || '');
	/* trim uniq */
	var uniq = uniq.replace(/^\s\s*/, ''), ws = /\s/, i = uniq.length;
	while (ws.test(uniq.charAt(--i)));
	uniq = uniq.slice(0, i + 1);
	/* end of trim */
	var plus = true;
	if (uniq) {
		plus = uniq.match(/^\+\/*(.*)/);
		if (plus) path = plus[1];
		else path = uniq;
	}
	if(path) {
		path = String(path);
		var ar = path.match(/^https?:\/\/[^\/]+(.*)/);
		if(ar) path = ar[1];
		else path = path.replace(/^([^\/]+)/, (plus ? wl.pathname : "") + "/$1");
		path = path.replace(/^\/+/, "/");
	} else { path=wl.pathname; }
	return path;
}

JSKitLib.initWidgets = function(widget_type, request, constructor) {
	var sendRequest = function(domain, multiParams, target) {
		if (!multiParams.length)
			return;
		var wl = window.location;
		request = request || {"extra_params": {}};
		var req = {
			uri: request.base_uri,
			ref: wl.protocol + "//" + domain + wl.pathname,
			epb: window.JSKitEPB ? JSKitEPB.getAsHash() : {},
			request: request.extra_params,
			variableRequest: multiParams,
			transport: 'GET',
			target: target,
			trailer: request.trailer
		};
		new JSRVC(req);
	}

	var els = document.body.getElementsByTagName("div");
	if(!els || !els.length)
		return;

	var multiI = {};
	var multiQ = {};
	var obj;
	var reg = new RegExp('js-kit-' + widget_type + '?');
	for (var i = 0; i < els.length; i++) {
		var m = reg.exec(els[i].className);
		if (!m || !m.length || els[i].jsk$initialized)
			continue;

		obj = constructor(els[i]);
		els[i].jsk$initialized = true;
		if (obj.config.disabled && obj.config.disabled != "no") continue;
		var d = obj.config.domain;

		if (!multiQ[d]) {
			multiQ[d] = [];
			multiI[d] = 0;
		}
		multiQ[d].push(obj.singleRequestParams);
		multiI[d]++;
	}
	JSKitLib.fmap(multiQ, function(v, k){ if (v) sendRequest(k, v, obj.target); });
}





function JSIPE(obj) {
	var self = this;
	self.obj = obj;
	var form = this.makeForm(obj.title);
	var inp = form.input;
	self.form = form;

	form.cleaner.onmousedown = function(e){
		inp.value = "";
		form.cleaner.style.visibility = "hidden";
		inp.focus();
		JSKitLib.preventDefaultEvent(e || window.event);
	}
	
	var keyHandler = function(e) {
		e = e || window.event;
		setTimeout(function(){
			form.cleaner.style.visibility = (inp.value.length != 0) ? "visible" : "hidden";
			if(obj.type == "Tab" || obj.type == "Image") form.cleaner.style.display = "none";
		}, 0);
		switch(e.keyCode || e.which) {
			case 27:
				JSKitLib.preventDefaultEvent(e);
				if(obj.mode == "full") self.finishEditing(obj.field, obj.field.lastValue);
				if(obj.jsk$on_cancel_exit) obj.jsk$on_cancel_exit();
			break;
			case 10: case 13:
				JSKitLib.preventDefaultEvent(e);
				if (inp.value && obj.mode == "full")
					self.finishEditing(obj.field, inp.value);
				if(obj.jsk$on_submit_exit) obj.jsk$on_submit_exit(inp.value);
			break;
			case 9:
				JSKitLib.preventDefaultEvent(e);
				if (obj.siblings) obj.siblings[(obj.field.pos+1)%obj.siblings.length].tabKeyHandler();
			break;
		}
	}
	self.addKeyHndl(keyHandler);		
	if (obj.inpSize) inp.style.width = obj.inpSize;
	form.cleaner.style.visibility = "hidden";
	if(obj.mode == "form") return form;

	if(!window.jsipe$glob) window.jsipe$glob = {};
	var glob = window.jsipe$glob;
	obj.field.style.cursor = "pointer";
	if(obj.siblings) obj.field.pos = obj.siblings.length;

	this.finishEditing = function(field, newValue) {
		if(!field.input) return;
		glob.isEditing = false;
		field.input.onblur = JSKitLib.isOpera() ? undefined : "";
		field.input.onkeypress = JSKitLib.isOpera() ? undefined : "";
		field.input = null;
		field.wasEdited(newValue);
		field.style.textDecoration = field.oldDecoration;
	}

	var onclickHandler = function() {
		if(obj.field.input) return false;
		if(obj.jsipe$start && !obj.jsipe$start()) return false;
		if(glob.stopEditing) glob.stopEditing();
		if(obj.containerElement.tId) {
			clearTimeout(obj.containerElement.tId);
			obj.containerElement.tId = 0} 
		obj.field.oldDecoration = obj.field.style.textDecoration;
		obj.field.isHtmlLink = obj.field.firstChild.tagName == 'A';
		obj.field.lastValue = obj.itemObject[obj.Property];
		obj.field.ondblclick = JSKitLib.isOpera() ? undefined : "";
		inp.type = 'text';
		inp.value = obj.itemObject[obj.Property];
		self.addKeyHndl(keyHandler);		

		inp.onblur = function(e) {
			if(self.form.input.value) {
				self.finishEditing(self.obj.field, self.form.input.value);
				if (obj.field.lastValue == self.form.input.value) {
					if(obj.jsk$on_cancel_exit) obj.jsk$on_cancel_exit(self.form.input.value)}
				else{
					if(obj.jsk$on_submit_exit) obj.jsk$on_submit_exit(self.form.input.value)}
			};
			//Do not close field until non-empty
		}

		obj.field.input = inp;
		glob.stopEditing = function() {
			glob.stopEditing = null;
			if((obj.field.input)&&obj.field.input.value) self.finishEditing(obj.field, obj.field.input.value);
		}
		JSKitLib.removeChildren(obj.field);
		obj.field.appendChild(form.main);
		obj.field.style.textDecoration = "none";
		form.cleaner.style.visibility = (inp.value.length != 0) ? "visible" : "hidden";
		if(obj.type == "Tab"  || obj.type == "Image") form.cleaner.style.display = "none";
		inp.onselectstart = function(e) {
			JSKitLib.stopEventPropagation(e || window.event);
			return true;
		};
		obj.containerElement.onselectstart = function(e) { return true };
		inp.focus();
		inp.select();
		glob.isEditing = true;
		return false;
	}

	var ondblclickHandler = function() {
		if(0 && obj.field.isHtmlLink)
			window.location.href = this.firstChild.value;
	}

	switch(obj.type) {
	case "Tab":
		obj.field.ondblclick = onclickHandler;
		break;
	case "Others":
                obj.field.onclick = onclickHandler;
                obj.field.tabKeyHandler = onclickHandler;
                obj.field.ondblclick = ondblclickHandler;
		break;
	case "Search": case "Image":
		obj.field.onclick = onclickHandler;
		break;
	}
}

JSIPE.prototype.addKeyHndl = function(keyHandler){
	var inp = this.form.input;
        switch(this.obj.type) {
        case "Tab":
                if (JSKitLib.isIE()) inp.onkeydown = keyHandler;
                else if(JSKitLib.isSafari()) inp.onkeyup = keyHandler;
                else inp.onkeypress = keyHandler;
                break;
        case "Others": case "Image":
		if(JSKitLib.isOpera()) inp.onkeypress = keyHandler;
		else inp.onkeydown = keyHandler;
                break;
        case "Search":
		if (JSKitLib.isIE() || JSKitLib.isSafari())
			inp.onkeydown = keyHandler;
		else inp.onkeypress = keyHandler;
                break;
        }
}

JSIPE.prototype.makeForm = function(title){
	var text = this.dtContent.replace(/TITLE/, title || "");
	var div = JSKitLib.html(text);
	var ctls = JSKitLib.mapClass2Object({}, div);
	if(!title) ctls['js-JSIPETitle'].style.display = "none";
	return {'main': div,'input': ctls['js-JSIPEInput'], 'cleaner':ctls['js-JSIPECleaner']};
}

JSIPE.prototype.dtContent
='<table border=0 style="padding: 0px; display: inline" cellspacing="0px" cellpadding="0px">'
+'      <tr>'
+'              <td class="js-JSIPETitle" style="padding:0px 4px 0px 0px; cursor: text;"><b>TITLE</b></td>'
+'              <td style="padding: 0px;">'
+'                      <input class="js-JSIPEInput" style="vertical-align:middle; padding: 0px;"></input></td>'
+'              <td style="padding: 0px;">'
+'                      <img class="js-JSIPECleaner" style="margin-left: 4px; vertical-align:bottom; cursor: pointer;" src="//js-kit.com/images/clear-search-button.gif" width="16" height="16"></img></td>'
+'      </tr>'
+'</table>';





// JS Visual Sorter
function JSVS(){
	var self = this;
	this.get = function(id) { return document.getElementById(id); }
	this.cr = function(tag) { return document.createElement(tag); }
}

JSVS.prototype.makeSortable = function(node) {
	var self = this;
	self.Container = node;
	if(node.childNodes.length > 1) {
		for (var i=0; i<node.childNodes.length; i++) {
			self.itemSortable(node.childNodes[i], true);
		}
	}
}

JSVS.prototype.itemSortable = function(singleItem, isSortable) {
	var self = this;
 	var clickHandle = function(e) {
		e = e || window.event;
		if (this != (e.srcElement || e.target)) return true;
		self.dragStart(singleItem, e);
		JSKitLib.stopEventPropagation(e);}
	JSKitLib.map(function(handle) {
		handle.style.cursor = isSortable ? "move" : "";
		handle.onmousedown = isSortable ? clickHandle : "";
		}, singleItem.vs_handles ? singleItem.vs_handles() : [singleItem]);
}

JSVS.prototype.dragStart = function(item, event) {
	var self = this;
	if(window.jsipe$glob.stopEditing) window.jsipe$glob.stopEditing();
	if (self.newObj || self.Container.childNodes.length == 1) return;
	self.movedItem = item;
	event = event || window.event;
	self.cloneY = (event.clientY || event.pageY) - item.offsetTop;
	var clone = item.cloneNode(true);
	clone.style.background = "#E8E5E4";
	self.newObj = self.cr("div");
	self.newObj.appendChild(clone);
	if(!JSKitLib.isIE()) self.newObj.style.margin = '-1px';
	self.newObj.style.border = "1px solid #808080";
	self.setOpacity(item, 0);
	JSKitLib.preventSelect(self.newObj);
	self.newObj.style.position = "absolute";
	self.newObj.style.top = item.offsetTop + 'px';
	self.newObj.style.width = item.offsetWidth + 'px';
	self.newObj.style.height = item.offsetHeight + 'px';
	self.newObj.style.left = item.offsetLeft + 'px';
	self.setOpacity(self.newObj,0.8);
	self.Container.appendChild(self.newObj);
	if(JSKitLib.isIE()){
		self.containerHeight=self.Container.firstChild.offsetTop;
		for (var i=0; i<self.Container.childNodes.length-1; i++)
			self.containerHeight+=self.Container.childNodes[i].offsetHeight;
		self.containerHeight-=self.newObj.offsetHeight;
	} else {
		self.containerHeight = self.Container.offsetHeight + self.Container.firstChild.offsetTop - self.newObj.offsetHeight + 2;
	}
	JSKitLib.addHandlers(document,moveHandler,upHandler);
	
	function moveHandler(ev) {
		ev = ev || window.event;
		var topFirstElem = self.Container.firstChild.offsetTop;
		var yOffset = (ev.clientY || ev.pageY) - self.cloneY;
		if (yOffset > topFirstElem) { 
			if (yOffset > self.containerHeight)
				self.newObj.style.top = self.containerHeight + 'px';
			else
				self.newObj.style.top = yOffset + 'px';
		} else {
			self.newObj.style.top = topFirstElem + 'px';
		}

		self.showDummy(true);

	JSKitLib.stopEventPropagation(ev);
	}

	function upHandler(ev) {
		JSKitLib.removeHandlers(document,moveHandler,upHandler);
		self.setOpacity(self.movedItem, 1);
		var clone = self.newObj;
		self.showDummy();
		clone.style.display = 'none';
		delete self.newObj;
		// avoid flicker in ff
		setTimeout(function() {
		    clone.parentNode.removeChild(clone);
		    var index = 0;
		    JSKitLib.map(function(child, i) {
			if (child.id == self.movedItem.id) index = i+1;
		    }, self.Container.childNodes);
		    self.movedItem.vs_moved(index);
		}, 10);

	JSKitLib.stopEventPropagation(ev);
	}
}

JSVS.prototype.showDummy = function(initial) {
	if(this.newObj) {
		if(initial) {
			var self = this;
			if(!this.sDummyIntvl)
				this.sDummyIntvl = setInterval(function() {
					self.showDummy() }, 100);
			return;
		}
	} else {
		clearInterval(this.sDummyIntvl);
		delete this.sDummyIntvl;
		return;
	}
		var cloneTop = this.newObj.offsetTop;
		var cloneBottom = this.newObj.offsetTop+this.newObj.offsetHeight;
		var prevSibl = this.movedItem.previousSibling;
		var nextSibl = (this.movedItem.nextSibling == this.newObj) ? null : this.movedItem.nextSibling;
		var prevMid = prevSibl ? (prevSibl.offsetHeight/2 + prevSibl.offsetTop) : 0;
		var nextMid = nextSibl ? (nextSibl.offsetHeight/2 + nextSibl.offsetTop) : 0;

		if(prevSibl && cloneTop < prevMid-1)
			this.Container.insertBefore(this.movedItem, prevSibl)
		else if(nextSibl && cloneBottom > nextMid+1)
			this.Container.insertBefore(this.movedItem,nextSibl.nextSibling);
		else return;
}

JSVS.prototype.setOpacity = function(div, val) {
	div.style.opacity = val;
	if(val == 1) div.style.filter = '';
	else div.style.filter = 'alpha(opacity: ' + Math.round(val * 100) + ')';
}





if(!window.JSKW$Events){
        var JSKW$Events = new JSEC();
}

/////////////////////////////////////
// JS Event Class
/////////////////////////////////////
function JSEC() {
	this.contextHandles = [];
}

JSEC.prototype.registerEventCallback = function (contextHandle, eventHandle, eventName) {
	if(!contextHandle) {
		contextHandle = new JSECC(eventHandle, eventName);
		this.contextHandles.push(contextHandle);
		contextHandle.cHdlId = this.contextHandles.length - 1;
	} else {
		contextHandle.registerEventCallback(eventHandle, eventName);
	}
	return contextHandle;
}

JSEC.prototype.deRegisterEventCallback = function (contextHandle, eventHandle, eventName) {
	contextHandle.deRegisterEventCallback(eventHandle, eventName);
}

JSEC.prototype.syncBroadcast = function (eventName) {
	var args = arguments;
	JSKitLib.fmap(this.contextHandles, function(c){
		if(c) c.broadCast.apply(c, args);
	});
}

JSEC.prototype.asyncBroadcast = function (eventName) {
	var self = this;
	var args = arguments;
	setTimeout(function(){
		self.syncBroadcast.apply(self, args);
	}, 0);
}

JSEC.prototype.invalidateContext = function (contextHandle) {
	if(contextHandle) {
		contextHandle.invalidateContext();
		delete this.contextHandles[contextHandle.cHdlId];
	}
}

/////////////////////////////////////
// JS Event Context Class
/////////////////////////////////////
function JSECC(eventHandle, eventName) {
	this.registeredCallbacks = [];
	if(eventName || eventHandle) this.registerEventCallback(eventHandle, eventName);
}

JSECC.prototype.registerEventCallback = function (eventHandle, eventName) {
	var ev = eventName || '';
	if(!this.registeredCallbacks[ev]) this.registeredCallbacks[ev] = [];
	this.registeredCallbacks[ev].push(eventHandle);
}

JSECC.prototype.deRegisterEventCallback = function (eventHandle, eventName) {
	var ev = eventName || '';
	var self = this;
	if(!eventHandle) {
		delete this.registeredCallbacks[ev];
		return;
	}
	var k=0;
	while(k<this.registeredCallbacks[ev].length) {
		if(this.registeredCallbacks[ev][k] == eventHandle) {
			self.registeredCallbacks[ev].splice(k, 1);
		} else k++;
	}
	if(!this.registeredCallbacks[ev].length) delete this.registeredCallbacks[ev];
}

JSECC.prototype.invalidateContext = function () {
	this.registeredCallbacks = [];
	try {
		if(this.jsk$invalidate) this.jsk$invalidate();
	} catch(e) { ; };
}

JSECC.prototype.broadCast = function (eventName) {
	var self = this;
	var ar = [''];
	var args = arguments;
	if(eventName!='') ar.push(eventName);
	JSKitLib.fmap(ar, function(ev){
		if(self.registeredCallbacks[ev]) JSKitLib.fmap(self.registeredCallbacks[ev], function(evHdl){
			evHdl.apply(self, args);
		});
	});
}





var JSKitGlobal = function() {

	this._appAvailable = {};
	this._appObjects = {};  // Specific objects of an application type 
	this._appObjectActions = {}; // app.object.actions
	
	this.cachedPngs = {};

	this._isAppAvailable = function(app) {
		return (this._appAvailable[app]) ? true : false;
	}

	this.isRatingsAppAvailable = function() {
		return this._isAppAvailable('ratings');
	}

	this.isCommentsAppAvailable = function() {
		return this._isAppAvailable('comments');
	}

	this._setAppAvailable = function(app) {
		this._appAvailable[app] = true;
		/* index this app */
		this.indexAppObjects(app);
		/* execute any queued actions */
		this.executeAppObjectActions(app);
	}

	this.setRatingsAppAvailable = function() {
		this._setAppAvailable('ratings');
	}

	this.setCommentsAppAvailable = function() {
		this._setAppAvailable('comments');
	}

	this.indexAppObjects = function(app) {
		if (app == 'ratings') {
			var appArray = $JRA;
		} else if (app == 'comments') {
			var appArray = $JCA;
		} else {
			alert('Attempt to index invalid app type');
			return;
		}
		for (var i=0; i < appArray.length; i++) {
			// Check that it's not standalone
			if (appArray[i].isStandalone()) {
				continue;
			}
			var uniq = appArray[i].uniq;
			if ( ! this._appObjects[uniq] ) {
				this._appObjects[uniq] = {};
			}
			if ( ! this._appObjects[uniq][app]) {
				this._appObjects[uniq][app] = [];
			}
			this._appObjects[uniq][app].push(appArray[i]);
		}
	}

	this.executeAppObjectActions = function(app) {
		if (this._appObjectActions[app]) {
			for (var i=0; i < this._appObjectActions[app].length; i++) {
				var uniq = this._appObjectActions[app][i].uniq;
				if (this._getAppObject(app, uniq)) {
					this._appObjectActions[app][i].action();
				}
			}
		}
	}

	this._getAppObject = function(app, uniq) {
		if (this._appObjects[uniq] && this._appObjects[uniq][app]) {
			return this._appObjects[uniq][app][0];  // Return only the first
		}
		return null;
	}

	this.getCommentsAppObject = function(uniq) {
		return this._getAppObject('comments', uniq);
	}

	/* Returns a Ratings Object */
	this.getRatingsAppObject = function(uniq) {
		return this._getAppObject('ratings', uniq);
	}

	this.copyRatingsAppObject = function(uniq, node) {
		if ( ! this.isRatingsAppAvailable()) {
			return;
		}
		var oldObj = this.getRatingsAppObject(uniq);
		var newObj = oldObj.clone(node, { 'view':'user', 'commentprompt':'no', 'menu':'no'  } );
		return newObj;
	}

	this._tryAppObjectAction = function(app, uniq, action) {
		if (this._isAppAvailable(app)) {
			if (this._getAppObject(app, uniq)) {
				action();
			}
		} else {
			if ( ! this._appObjectActions[app]) {
				this._appObjectActions[app] = [];
			}
			this._appObjectActions[app].push( { 'uniq' : uniq, 'action' : action } );
		}
	}

	this.tryRatingsAppObjectAction = function(uniq, action) {
		this._tryAppObjectAction('ratings', uniq, action);
	}

	this.tryCommentsAppObjectAction = function(uniq, action) {
		this._tryAppObjectAction('comments', uniq, action);
	}
}

/* Singleton-like handler */
JSKitGlobal.getInstance = function() {
	if (!window.JSKitGlobalInstance) {
		JSKitGlobalInstance = new JSKitGlobal();
	}
	return JSKitGlobalInstance;
}





/* JSKitGlobal  object */
$JSKitGlobal = JSKitGlobal.getInstance();



/* Constants */

JSTC.DOMAIN = (window.location.protocol.substr(0, 4) != 'http' ? 'http:' : '')
              + '//js-kit.com';
JSTC.IMG_DIR = JSTC.DOMAIN + '/images/top';
JSTC.SKIN_DIR = JSTC.IMG_DIR + '/skins';
JSTC.VIEW_TYPES =  { TR:"Top Rated", TS:"Top Scored", HT:"Hot", EP:"Editor's Picks", PL:"Poll", CR:"Comments Roll" };

/* Class Functions */

// Initialize instances of JSTC objects
JSTC.init = function() {
	var els = JSKitLib.getElementsByClass(document, 'js-kit-top', 'div');
	if (els && els.length) {
		for (var i=0; i < els.length; i++) {
			if(!els[i].jk$initialized) {
        	        	els[i].jk$initialized = true;
                        	new JSTC(els[i]);
        		}
		}
	} else {
		// Missing <div class="js-kit-top"></div> Tag
	}
}

/* CSS Base Style */

document.write('<style type="text/css">'

// User Generic
+ ".js-topFont { font-family: Arial, Helvetica, sans-serif; font-size: 10pt; }"
+ ".js-epAdminButton { font-family: Arial, Helvetica, sans-serif; font-size: 10pt; }"
+ ".js-topTitleFont { font-weight: bold; }"
+ ".js-topTabFont { font-weight: bold; }"
+ ".js-topDetailFont { font-family: Arial, Helvetica, sans-serif; font-size: 8pt; }"
+ ".js-topRowColor1 {}"
+ ".js-topRowColor2 {}"

// General 

+ "div.js-Top { margin: 0; padding: 0; }" 

+ "div.js-TopBg { width: 100%; }" // width needed for ie redraw 
+ "div.js-topView { border-left: 1px solid #e0e0e0;"
		+ "border-right: 1px solid #e0e0e0;"
		+ "margin: 0; padding: 0;"
		+ "zoom: 1; }"
+ "div.js-topBody { margin: 0; }" 
+ "div.js-topTop { margin: 0; }"
+ "div.js-topHot { margin: 0; }"
+ ".js-nsgecko { -moz-user-select: none; }"

// Tab Navigation
+ "div.js-topNav { margin: 0; }"
+ "div.js-topNavTabWrap { float: left;  }"
+ "div.js-topNavTab { text-align: center; cursor: pointer;"
			+ "margin-top: 1px;"
			+ "padding: 0.4em 3px;"
			+ "border-left: 1px solid #e0e0e0; "
			+ "border-bottom: 1px solid #e0e0e0; }"
+ "div.js-topNavTabActive { border-bottom: none; cursor: default;}"
+ "div.js-topNavTabLeft { border-left: none; }"
+ "div.js-topNavTabRight { border-right: none; }"

// Header 
+ "div.js-topHeader { border:1px solid #e0e0e0; margin: 0; padding: 0.2em 0; zoom: 1; }"
+ "div.js-topTitle { margin: 0; padding-top: 2px; text-align:center;}"

// Top Rated
+ "div.js-topItems { position: relative; margin: 0; text-align: left; }"
+ "div.js-topItem { padding: 0.3em 0.6em; zoom: 1; margin: 0px; }"
+ "a.js-topItemLink { zoom: 1; cursor: pointer; }"
+ "span.js-topItemRating { margin: 0; white-space: nowrap }"

// Top Score
+ "div.js-topScoreItems { position: relative; margin: 0; text-align: left; }"
+ "div.js-topScoreItem { padding: 0.3em 0.6em; zoom: 1; margin: 0; }"
+ "a.js-topScoreItemLink { zoom: 1; cursor: pointer; }"
+ "span.js-topScoreItemRating { margin: 0; white-space: nowrap }"

// Hot
+ "div.js-topHotItems { position: relative; margin: 0; text-align: left; }"
+ "div.js-topHotItem { padding: 0.3em 0.6em; zoom: 1; }"
+ "a.js-topHotItemLink { zoom: 1; }"

// Footer
+ "div.js-topFooter { border: 1px solid #e0e0e0; height: 16px; margin: 0; overflow: hidden; padding: 0; position: relative; zoom: 1; }"
+ "div.js-topPoweredBy { height: 16px; position:absolute; right: 0; top: 0; width: 60px; cursor: pointer; }"
+ "div.js-topGrab { height: 16px; left: 0; position: absolute; top: 0; width: 100px; cursor: pointer; display: none;}"
+ "input.js-topCode { width: 95%; }"
+ "div.js-topGrabWindow { border: 1px solid #e0e0e0; margin: 1px 0 0 0; padding: 0; }"
+ "div.js-topHelp { margin: 0; padding: 0.6em 0.6em; }"
+ "div.js-topInvitation { margin: 0; padding: 0.6em 0.6em; }"

+"div.js-epAdminEP {"
+"margin: 0;"
+"zoom: 1;"
+"width: 100%;"
+"}"

+"div.js-epAdminEPItem {"
+"padding: 0.3em 0.6em 0.3em 0.6em;"
+"position: relative;"
+"}"

+"div.js-epAdminEPItemEdit {"
+"cursor: pointer;"
+"}"

+"div.js-epAdminEPItemEditWindow {"
+"padding-right: .3em;"
+"padding-top: .3em;"
+"}"

+".js-epAdminEPItemHidden {"
+"background-color: #e0e0e0;"
+"}"

+"div.js-epAdminEPTitle {"
+"width: 100%;"
+"}"

+"div.js-epAdminEPLink {"
+"width: 100%;"
+"}"

+"div.js-epAdminEPItemDel  { cursor: pointer; }"
+"div.js-epAdminEPItemAdd { cursor: pointer; color: white; }"

+"span.js-epAdminEPItemAddLink { color: inherit; text-decoration: underline}"
+".js-epActiveElem { background-color: #fdffd7;	color: #000000; cursor: pointer }"
+"div.js-epAdminEPFooter {"
+"padding: 3px 0.6em;"
+"}"

// Admin 
+ "div.js-topAdminBar { border: 1px solid #e0e0e0; border-top: none; padding: 2px; text-align:center; cursor: pointer; }"
+ "div.js-topAdminConsole { border:1px solid #afafaf; position:absolute;width: 329px; background-color:#ffc; filter: alpha(opacity=90); opacity: 0.9; color: #000; text-align: left; z-index: 1000; }"
+ "div.js-topAdminConsoleHeader { text-align:center; padding: 5px 0; margin-bottom: 5px; background-color: #dda; cursor: move; }"
+ "div.js-topAdminConsoleBody { padding: 10px; }"
+ "div.js-topAdminConsoleViews { padding-bottom: 5px; }"
+ "div.js-topAdminConsoleView { padding: 2px 0; }"
+ "div.js-topAdminConsoleFooter { padding: 7px; }"
+ "input.js-topAdminConsoleTitle { width: 160px; }"
+ "input.js-topAdminConsoleCount { width: 20px; }"
+ "input.js-topAdminConsoleViewTitle { width: 100%; background-color: #ffffff; }"
+ "div.js-topBodyMsg { padding: 0.7em 0.5em; }"
+ "div.js-topBodyAdminMsg { padding: 0.7em 0.5em; }"
+ "div.js-topBodyAdminMsgHeader { padding-bottom: 0.3em; }"
+ "div.js-topBodyAdminMsgBody {  }"

// Comments Roll
+ ".js-topCommentsRoll { padding: 0px; }"
+ ".js-topComments { position: relative; text-align: left; }"
+ ".js-topSingleComment { zoom: 1; font-size: 8pt; font-family: Verdana, Helvetica; text-align: left;}"
+ ".js-topSingleCommentBg { padding: 0.3em; }"
+ ".js-topSingleCommentINFO { color: #808080; float: right; padding: 3px; margin-left: 2em; text-align: right;}"
+ ".js-topSingleCommentAvatar { margin-right: 1px; margin-left: 0.5em; float: right; }"
+ ".js-topSingleCommentDate { font-size: 7pt; }"
+ ".js-topSingleCommentOrigin { zoom: 1; padding: 0px 0px 0.3em 0.3em; font-size: 7pt; color: #808080; }"
+ ".js-topCommentPermalink { cursor: pointer; }"

+ "</style>");

// Problem with ie and %width of input tags
if (JSKitLib.isIE()) {
  document.write('<style type="text/css">'
  + "input.js-topCode { width: auto; }"
  + "</style>");
}

/* Object and Methods */

JSTC.prototype.writeSkinCSS = function() {

	var titleFont = '';
	var tabFont = '';
	var navTab = '';
	var detailFont = '';
	var msgBody = '';
	var adminBar = '';

	var skin = this.config.get('skin');

	if (skin != 'none') {
		var skinDir = JSTC.SKIN_DIR + '/' + skin;
		var header = 'background: url(' + skinDir + '/navi-header-bg.gif) -20px top repeat; border: none;';
		var footer = 'background: url(' + skinDir + '/navi-footer-bg.gif) right top no-repeat; border: none;';
		var grabWindow = 'background: #e6e9ec url(' + skinDir + '/navi-code-bg.gif) 0 -15px repeat-x;';
		var grab = 'background: url(' + skinDir + '/navi-footer-buttons.gif) 5px -16px no-repeat;';
		var poweredBy = 'background: url(' + skinDir + '/navi-footer-buttons.gif) -20px -32px no-repeat;';
		var view = 'background: #ffffff url(' + JSTC.IMG_DIR + '/navi-tab-front-bg.gif) top repeat-x;';
		var rowColor2 = "background: #f8f8f8;";
		var navTab = "background: url(" + JSTC.IMG_DIR + "/navi-tab-back-bg.gif) 0 -1px repeat-x;";
		var adminNote = 'color: #009933';
		switch (skin) {
			case 'default':
				grabWindow += ' border: 1px solid #bbd1dd; background-color: #e6e9ec; color: #435362';
				adminBar += ' border: 1px solid #bbd1dd; border-top: none; background-color: #e6e9ec; color: #435362';
				titleFont = ' color: #435362';
				tabFont = ' color: #003366';
				detailFont = ' color: #435362';
				msgBody = ' color: #435362';
				break;
			case 'ice':
				grabWindow += ' border: 1px solid #bbd1dd; background-color: #f2f9ff; color: #3d6883';
				adminBar += ' border: 1px solid #bbd1dd; border-top: none; background-color: #f2f9ff; color: #3d6883';
				titleFont = ' color: #3d6883';
				tabFont = ' color: #003366';
				detailFont = ' color: #3d6883';
				msgBody = ' color: #3d6883';
				break;
			case 'silver':
				grabWindow += ' border: 1px solid #cfcbc9; background-color: #fcfbfb; color: #5d5954';
				adminBar += ' border: 1px solid #cfcbc9; border-top: none; background-color: #fcfbfb; color: #5d5954';
				titleFont = ' color: #5d5954';
				tabFont = ' color: #003366';
				detailFont = ' color: #5d5954';
				msgBody = ' color: #5d5954';
				break;
			case 'suede':
				grabWindow += ' border: 1px solid #d5bab4; background-color: #f0e8e1; color: #9a6329';
				adminBar += ' border: 1px solid #d5bab4; border-top: none; background-color: #f0e8e1; color: #9a6329';
				titleFont = ' color: #603a13';
				tabFont = ' color: #9a6329';
				detailFont = ' color: #603a13';
				msgBody = ' color: #603a13';
				break;
			default:
				break;
		}
	} else {
		var skinDir = JSTC.SKIN_DIR + '/none';
		var grab = 'background: url(' + skinDir + '/navi-footer-buttons.gif) 5px -16px no-repeat;';
		var poweredBy = 'background: url(' + skinDir + '/navi-footer-buttons.gif) -20px -32px no-repeat;';
	}

	document.write('<style type="text/css">'
		+ "div.js-topHeader {" + header + "}"
		+ ".js-topTitleFont {" + titleFont + "}"
		+ "div.js-topView {" + view + "}"
		+ ".js-topTabFont {" + tabFont + "}"
		+ "div.js-topNavTab {" + navTab + "}"
		+ ".js-topDetailFont {" + detailFont + "}"
		+ "div.js-topFooter {" + footer + "}"
		+ "div.js-topGrab {" + grab + " ;display: none;}"
		+ "div.js-topGrabWindow {" + grabWindow + "}"
		+ "div.js-topPoweredBy {" + poweredBy + "}"
		+ ".js-topRowColor2 {" + rowColor2 + "}"
		+ "div.js-topBodyMsgBody {" + msgBody + "}"
		+ "div.js-topBodyAdminMsgBody {" + msgBody + "}"
		+ "div.js-topNavTabActive { background: none; }"
		+ "a.js-topItemLink {" + tabFont + "}"
		+ "a.js-topScoreItemLink {" + tabFont + "}"
		+ "a.js-topHotItemLink {" + tabFont + "}"
		+ "a.js-epAdminEPItemAdd {" + tabFont + "}"
		+ "div.js-epItemEField-link {" + tabFont + "}"
		+ "div.js-epItem-TL {" + tabFont + "}"
		+ "div.js-topBodyAdminMsgHeader {" + adminNote + "}"
		+ "div.js-topAdminBar {" + adminBar + "}"
		+ "</style>"
	);

}

JSTC.init(); // Initialize our badges 

/* Class JSTC */
function JSTC(target) {

	this.jtaIndex = $JTA.length;
	$JTA.push(this);
	this.cr = function(tag) { return document.createElement(tag); }
	var wl = window.location;

	this.target = target;


	// Tab/Body data
	this.views = [];

	this.part = {}; // TR, HH, HD, HW parent object

	this.starWidth = 9;
	this.starHeight = 9;

	this.thumbnailWidth = 50;
	this.thumbnailHeight = 50;

	var self = this;

	/* Config */
	this.config = {};
	this.config.inline = {};
	this.config.server = {}; // config from server, or recently saved
	this.config.get = function(key) { return self.config.inline[key] || self.config.server[key] }; 
	this.config.getInline = function(key) { return self.config.inline[key] }; 
	this.config.getServer = function(key) { return self.config.server[key] }; 

	var iConfig = {};
	iConfig.skin = target.getAttribute("skin") || 'default';
	iConfig.target = target.getAttribute("target") || '';
	iConfig.image1url = target.getAttribute("image1url") || '';
	iConfig.image2url = target.getAttribute("image2url") || '';
	iConfig.imagesize = target.getAttribute("imagesize") || '';
	iConfig.category = target.getAttribute("category") || '';
	iConfig.title = target.getAttribute("title") || '';
	target.setAttribute("align", "left");
	this.title = iConfig.title;
	if (target.getAttribute("count")) 
		iConfig.count = target.getAttribute("count");
	if((iConfig.image1url || iConfig.image2url) && iConfig.imagesize) {
		var dim = iConfig.imagesize.match(/(\d+)([^\d]+(\d+))?/);
		if(dim) {
			this.starWidth = dim[1];
			this.starHeight = dim[3] || this.starWidth;
		}
	}

	this.config.inline = iConfig;

	this.domain = target.getAttribute("site") || wl.host + wl.pathname;
	this.domain = this.domain.replace(/^[a-z]+:\/\//, '');
	this.domain = wl.protocol + "//" + this.domain;

	// Set Skin CSS
	this.writeSkinCSS();

	this.server = function(smod, ext, data) {
		var wl = window.location;
		var sc = self.cr("script");
		sc.setAttribute("charset", "utf-8");

		var domain = self.domain || wl.protocol + "//" + wl.host + wl.pathname;
		var categ =  self.config.get('category') ? "&category=" + self.config.get('category') : "";
		sc.src = JSTC.DOMAIN + (/^\//.test(smod)?'':'/') + smod + ext
			+ "?ref="
			+ encodeURIComponent(domain + "/")
			+ "&" + data
			+ categ;
		self.target.appendChild(sc);
		return false;
	}
	this.serverPut = function(ext, data) { return self.server("editor-picks", "", data + "&action=" + ext); }

	var maxAdSize = function(prepend) {
	  // Needed to measure the expected width of a non-styled div
	  //self.target.innerHTML = '<div id="bh_testme" style="width:100%;"></div>';
	  var styleVar = function(name) {
		var cs = self.target.currentStyle
		|| document.defaultView.getComputedStyle(self.target, null);
		var v = cs[name] || self.target.style[name] || 0;
		var a = String(v).match(/^([0-9]+)px/);
		return a ? a[1] : 0;
	  }
	  var ww = styleVar('width');    
	  var w = self.target.offsetWidth;
	  var h = 0;
	  //self.target.innerHTML = '';
	  return prepend + w + "x" + h;
	}

	if (JSKitLib.isSafari() || JSKitLib.isOpera()) {
		self.server("bestof", "-data.js","jx="+self.jtaIndex+"&count="+self.config.get('count')); 
		JSKitLib.addEventHandler(window, ['load'], function() {
			self.server("ad", "-data.js","jx="+self.jtaIndex + maxAdSize("&wxh="));
		});
	} else {
		self.server("bestof", "-data.js","jx="+self.jtaIndex+"&count="+self.config.get('count') + maxAdSize("&wxh=")); 
	}


}

JSTC.prototype.getMainTemplate = function() {

  var html  
   = '<div style = "word-wrap:break-word">'
//   + '<table cellspacing="0" cellpadding="0" border="0" width="100%"><tbody><tr><td>'

    + '<div class="js-Top">' 
     + '<div class="js-TopBg">' 
      + '<div class="js-topHeader">' 
       + '<div class="js-topTitle js-topTitleFont">{Title}</div>'
      + '</div>'

      // View is instance of a Tab/Body 
      + '<div class="js-topView">'
       + '<div class="js-topNav js-topTabFont"></div>'  // Tab Navigation
       + '<div class="js-topBody"></div>' // Body 
      + '</div>'
  
      // Top Footer
      + '<div class="js-topFooter">'
       + '<div class="js-topGrab"></div>'
       + '<div class="js-topPoweredBy"></div>'
       + '<div style="clear:both;"></div>'
      + '</div>'
  
      // Grab this
      + '<div style="clear:both; display:none;" class="js-topGrabWindow">'
       + '<div class="js-topHelp js-topFont">To embed this widget into your site, just copy this HTML:</div>'
       + '<div style="text-align: center;"><input class="js-topCode" onclick="select();" readonly style="font-size: 10px;"></input></div>'
       + '<div class="js-topInvitation js-topDetailFont">Visit <a href="http://js-kit.com/navigator/?wow" target="_blank" title="JS-Kit" style="js-topDetailFont; text-decoration: underline;">JS-Kit</a> for more information.</div>'
      + '</div>' 

      + '<div class="js-topAdminBar js-topDetailFont" style="display:none; text-align: center;">'
       + '<span class="js-topAdminConsoleLaunch" style="cursor: pointer;">' + $JTL('adminConsole') + '</span>'
      + '</div>'
  
     + '</div>'  // js-TopBg
    + '</div>'  // js-Top

//   + '</td></tr></tbody></table>'
   + '</div>'
  ;

	return html;
} 

JSTC.prototype.dtBodyAdminMsg
 = '<div class="js-topBodyAdminMsg">'
  + '<div class="js-topBodyAdminMsgHeader">'
   + '<span style="font-size:12pt; font-weight: bold;">Note to admin:</span>'
  + '</div>'
  + '<div class="js-topBodyAdminMsgBody js-topFont"></div>'
 + '</div>'
;

JSTC.prototype.dtBodyMsg
 = '<div class="js-topBodyMsg">'
  + '<div class="js-topBodyMsgBody js-topFont"></div>'
 + '</div>'
;
 
JSTC.prototype.dtBodyNew
 = '<div class="js-topBodyNew js-topFont" style="padding: 1.2em .8em; text-align: left;">'
  + $JTL('installationWelcome')
 + '</div>'
;

JSTC.prototype.dtBodyTop 
 = '<div class="js-topTop">'
  + '<div class="js-topClip">'
  + '<div class="js-topItems">'
   + '<div class="js-topItem">'
    + '<a class="js-topItemLink js-topFont" href="{url}">{title}</a>'
    + '<div class="js-topItemInfo">'
     + '<table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="middle">'
      + '<div class="js-topItemStars"></div>'
     + '</td><td>'
      + '<span class="js-topItemRating js-topDetailFont">{rating}&nbsp;({votes})</span>'
     + '</td></tr></tbody></table>'
     + '<div style="clear:both"></div>'
    + '</div>'
   + '</div>'
  + '</div>'
 + '</div>'
;

JSTC.prototype.dtBodyTopScore 
 = '<div class="js-topTopScore">'
  + '<div class="js-topClip">'
  + '<div class="js-topScoreItems">'
   + '<div class="js-topScoreItem">'
    + '<a class="js-topScoreItemLink js-topFont" href="{url}">{title}</a>'
    + '<div class="js-topScoreItemInfo">'
     + '<table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="middle">'
      + '<div class="js-topScoreItemStars" style="position: relative; padding-right:5px;"></div>'
     + '</td><td>'
      + '<span class="js-topItemScoreRating js-topDetailFont"><b>{rating}</b>&nbsp;({votes})</span>'
     + '</td></tr></tbody></table>'
     + '<div style="clear:both"></div>'
    + '</div>'
   + '</div>'
  + '</div>'
 + '</div>'
;

JSTC.prototype.dtBodyHot
 = '<div class="js-topHot">'
 + '<div class="js-topClip">'
  + '<div class="js-topHotItems">'
    + '<div class="js-topHotItem">'
     + '<a class="js-topHotItemLink js-topFont" href="{url}">{title}</a>'
     + '<table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="middle">'
      + '<span class="js-topHotItemInfo js-topDetailFont"> ({votes})</span>'
     + '</td></tr></tbody></table>'
     + '<div style="clear:both"></div>'
    + '</div>'
   + '</div>'
  + '</div>'
  + '</div>'
;

JSTC.prototype.dtAdminConsole 
 = '<div class="js-topAdminConsole">'
  + '<div class="js-topAdminConsoleHeader"><b>JS-Kit Navigator Admin Console</b></div>'
  + '<div class="js-topAdminConsoleBody">'

   + '<table cellpadding="2" cellspacing="0" border="0"><tbody><tr>'
   + '<td>Title: </td>'
   + '<td><input class="js-topAdminConsoleTitle" style = "background-color: #efefef;">'
   + '&nbsp;<span class="js-topAdminConsoleNoEditTitle" style="display:none; ">[<a href="javascript:void(0);">non-editable</a>]</span></td>'
   + '</tr><tr>'
   + '<td>Count: </td>'
   + '<td><input class="js-topAdminConsoleCount" style = "background-color: #efefef;">'
   + '&nbsp;<span class="js-topAdminConsoleNoEditCount" style="display:none;">[<a href="javascript:void(0);">non-editable</a>]</span></td>'
   + '</tr></tbody></table>'

   + '<div class="js-topAdminConsoleViewsHeader" style="padding: 8px 0 3px 0; margin-bottom: 2px; border-bottom: 1px solid #666; font-family: Arial; font-weight: bold; font-size:10pt;">'
    + '<table cellpadding="0" cellspacing="0" border="0"><tbody>'
    + '<tr><td width="30">&nbsp;</td><td width="100">Tab Type</span></td><td width="100">Tab Title</td></tr>'
    + '</tbody></table>'
   + '</div>'

   + '<div class="js-topAdminConsoleViews">'

    + '<div class="js-topAdminConsoleView">'
     + '<table cellpadding="0" cellspacing="0" border="0"><tbody>'
      + '<tr><td width="30">'
       + '<input type="checkbox" class="js-topAdminConsoleViewActive">'
      + '</td><td width="100" class="js-topAdminConsoleViewType">'
       + '<input type="hidden" class="js-topAdminConsoleViewTypeValue">'
      + '</td><td width="100">'
       + '<input class="js-topAdminConsoleViewTitle">'
      + '</td></tr>'
     + '</tbody></table>'
    + '</div>'


   + '</div>'

  + '</div>' 
  + '<div class="js-topAdminConsoleFooter">'
  +  '<button class="js-topAdminConsoleCancel" style="margin: 0 .2em;">' + $JTL('cancel') + '</button>'
  +  '<button class="js-topAdminConsoleSave" style="margin: 0 .2em;">' + $JTL('save') + '</button>'
  +  '<button class="js-topAdminConsoleSaving" style="margin: 0 .2em; display:none;" disabled="on">' + $JTL('saving') + '</button>'
  +  '<div style="padding: 7px 5px 0 5px; font-family: Arial; font-size: 9pt;"><a href="http://js-kit.com/support/">Contact our Support Team</a> with questions, comments and feedback.</div>'
  + '</div>'
 + '</div>'
;

JSTC.prototype.dtComments
= '<div class="js-topCommentsRoll">'
  + '<div class="js-topClip">'
   + '<div class="js-topComments">'
    + '<div class="js-topSingleComment">'
     + '<div class="js-topSingleCommentBg">'
      + '<div class="js-topSingleCommentAvatar"></div>'
      + '<div class="js-topSingleCommentINFO">'
       + '<div class="js-topSingleCommentName" style="clear:both">{Name}</div>'
       + '<div class="js-topSingleCommentDate">{Date}</div>'
      + '</div>'
      + '<div class="js-topSingleCommentText">{Text}</div>'
     + '</div>'
     + '<div class="js-topSingleCommentOrigin"><a class="js-topCommentPermalink">{ShowLink}</a></div>'
     + '<div style="clear: both;"/>'
    + '</div>'
   + '</div>'
  + '</div>'
+ '</div>'
;


JSTC.prototype.addChild = function(to, what) {
	if(arguments.length == 3 && arguments[2])
		to.insertBefore(what, to.firstChild);
	else
		to.appendChild(what);
}

JSTC.prototype.gtmpl = function(t) {
	var lowercase = function(a, m) { return String(m).toLowerCase(); }
	t = t.replace(/^[^<]*(<.*>)[^>]*$/m, "$1");
	t = t.replace(/(<[\/]?[A-Z]+)/g, lowercase);
	t = t.replace(/%7B/g, "{");
	t = t.replace(/%7D/g, "}");
	t = t.replace(/{Label:([^}]*)}/g,function(a,m){return $JTL(m);});
	return t;
}

JSTC.prototype.tmpl = function(t, obj) {
	var self = this;
	t = self.gtmpl(t);
	var purify = function(text, m) {
		var text = String(text).replace(/^[ \s]+|[ \s]+$/, '');
		if(m != "Link") text = text.replace(/([^&<>\s]{12})([^&<>\s]{12})/g, '$1<wbr></wbr>$2');
		text = text.replace(/[ \t\r\n]+/g, ' ');
		return text;
	}
	t = t.replace(/{([A-Za-z0-9]+)}/g,function(a,m){return obj.hasOwnProperty(m)?purify(obj[m],m):'{'+m+'}';});
	return t;
}

// TODO: We want this to be customizable
JSTC.prototype.getMiniStars = function(rating, scale) {

	rating = Math.round(rating);

	var fullStar = this.config.get('image1url') || JSTC.DOMAIN + '/images/stars/gold-tiny.png';
	var emptyStar = this.config.get('image2url') || JSTC.DOMAIN + '/images/stars/gray-tiny.png';

	var stars = JSKitLib.createMiniStarObject(rating, scale, { full: fullStar, empty: emptyStar, width: this.starWidth, height: this.starHeight });

	return stars;
}

// TODO: We want this to be customizable
JSTC.prototype.getMiniThumb = function(score) {

	var thumbImage = JSTC.DOMAIN + '/images/stars/small-thumb.png';

	var upDown = score >=0 ? 'up' : 'down';
	var miniThumb = JSKitLib.createThumbImage({ ud: upDown, actionable: true, imageURL: thumbImage, ignoreEmpty: true, thumbWidth: 10, thumbHeight: 12 });

	return miniThumb; 
}


// Code propogation
JSTC.prototype.toggleGrab = function() {
  var grabWin = this.ctls['js-topGrabWindow'];
  var topGrab = this.ctls['js-topGrab'];
  JSKitLib.toggle(grabWin);
  (grabWin.style.display == 'none') ? topGrab.style.backgroundPosition='0pt -16px' :  topGrab.style.backgroundPosition='0pt -0px';
}

JSTC.prototype.getPropCode = function() {
	var site = ' site="' + this.domain + '"';
	var title = ' title="' + this.title + '"';
	var count = ' count="' + this.config.get('count') + '"';
	var category = this.config.get('category') ? ' category="' + this.config.get('category') + '"' : '';
	var skin = (this.config.get('skin') && this.config.get('skin') != 'default') ? ' skin="' + this.config.get('skin') + '"' : '';
	var style = ' style="width: ' + (this.target.style.width ? this.target.style.width : '300px') + '"';
	var code = '<div class="js-kit-top"' + site + title + count + category + skin + style + '></div><script src="' + JSTC.DOMAIN + '/top.js"></script>';
	return code;
}

/*
 * Extract all info from our config and place in our object
 */
JSTC.prototype.processConfig = function(config) {
	// Note: defaults should fall in here??
	var sConfig = this.config.server;
	var self = this;
	var parse = function(value, def) {
		if (config[value]) {
			sConfig[value] = config[value];
		} else {
			sConfig[value] = def;
		}
	}
	parse('title', 'Navigator');
	parse('count', 10);
	var views = [
		{ type:"TR", title:"Top" },
		{ type:"TS", title:"Score" },
		{ type:"HT", title:"Hot" },
		{ type:"EP", title:"Picks" },
		{ type:"PL", title:"Poll" },
		{ type:"CR", title:"Comments" }
	];
	if (config.views){
		self.views = config.views;
		// Add any new views since the config was saved
		var tHash ={};
		JSKitLib.map(function(item){tHash[item.type] = item}, config.views);
		JSKitLib.map(function(item){if(!tHash[item.type]) self.views.push(item)}, views);
	} else {
		this.views = views;
		// Parse out what type of data we already have
		var dataTypes = this.getServerDataTypes();
		for (var i=0; i < this.views.length; i++) {
			switch (this.views[i].type) {
				case "TR": 
					// If Neither TR or TS exists, we will default to showing TR
					this.views[i].active = (dataTypes.TR || ! dataTypes.TS)  ? true : false; 
					break;
				case "TS": 
					this.views[i].active = dataTypes.TS ? true : false; 
					break;
				case "HT": 
				case "EP": 
				case "CR": 
				case "PL": 
					this.views[i].active = true; 
					break;
			}
		}
	}
}

// Returns a hash of server provided data types
JSTC.prototype.getServerDataTypes = function() {

	var data = this.serverData[0].data;
	var dataTypes = {};
	for (var i=0; i < data.length; i++) {
		dataTypes[data[i].type] = true;
	}

	return dataTypes;
}

JSTC.prototype.toggleViews = function(id) {
	// Iterate through hide/unactivate as necessary
	var views = this.getActiveViews();
	if (!views.length) return;

	for (var i=0; i < views.length; i++) {
		JSKitLib.removeClass(views[i].tab, "js-topNavTabActive");
		JSKitLib.hide(views[i].content);
	}
	// Now display the proper view
	JSKitLib.addClass(views[id].tab, "js-topNavTabActive");
	JSKitLib.show(views[id].content);
	this.defaultView = views[id].content;
	if(views[id].type == "TR" || 
	   views[id].type == "HT" || 
	   views[id].type == "TS" ||
	   views[id].type == "CR") this.addClip(views[id].content);
	JSKW$Events.syncBroadcast("JSKitNavigator_toggleViews", this.currentView, views[id]);
	this.currentView = views[id];
}

JSTC.prototype.table = function(tr) {
  var self = this;
  var a = function(n, w) {var o=self.cr(n);o.appendChild(w);return o;}
  var t = a('table', a('tbody', tr));
  var z = function(a) {t.setAttribute(a, '0')}
  z('cellSpacing');
  z('cellPadding');
  z('border');
  return t;
}

JSTC.prototype.getViews = function() {
	return this.views;
}

JSTC.prototype.getActiveViews = function() {
	var views = this.views;
	var aViews = [];
	for (var i=0; i < views.length; i++) {
		if (typeof views[i] == 'object' && views[i].active) {
			aViews.push(views[i]);
		}
	}
	return aViews;
}

JSTC.prototype.isViewActive = function(type) {
	var views = this.getActiveViews();    
	for (var i=0; i < views.length; i++) {
		if (typeof views[i] == 'object' && (views[i].type == type) && views[i].active) {
			return true;
		}
	}
	return false;
}

JSTC.prototype.createTabs = function() {
	var self = this;
	var views = this.getActiveViews();

	var numTabs = views.length;

	// TODO: Show no tab if only one

	// Calculate the width of each tab
	var width = Math.floor(100/numTabs);
	var adjWidth = (numTabs * width != 100) ? (100 - ((numTabs - 1) * width)) : width;


	var tr = this.cr('tr');
	self.titleTabArr = [];

	for (var i=0; i < views.length; i++) {
		var td = this.cr('td');
		td.setAttribute('width', width + '%');

		var tabWrap = this.cr('div');
		tabWrap.className = "js-topNavTabWrap";
		tabWrap.style.width = '100%';

		var tabMain = this.cr('div');
		tabMain.className = "js-topNavTab";
		JSKitLib.preventSelect(tabMain); // preventSelect for tabs titles

		// Left, Right
		if (i==0) { 
			td.setAttribute('width', adjWidth + '%');
			JSKitLib.addClass(tabMain, "js-topNavTabLeft");
			JSKitLib.addClass(tabMain, "js-topNavTabActive"); 
		} else {
			if (i == (views.length - 1)) {
				JSKitLib.addClass(tabMain, "js-topNavTabRight");
			}
		}

		var divTitle = document.createElement("div");
		divTitle.className = "js-topNavTabTitle";
		divTitle.innerHTML = JSKitLib.htmlQuote(views[i].title,{title:true});
		self.titleTabArr.push(divTitle);
		divTitle.view=views[i];

		(function(i) {
			tabMain.onclick = function() { 
				self.toggleViews(i); 
			};
		})(i);
    
		tabMain.appendChild(divTitle);
		tabWrap.appendChild(tabMain);

		if (this.isAdmin){
			divTitle.wasEdited = function(newValue) { 
				var acf = self.adminConfigForm;
				if(!acf){
					self.buildAdminConsole();
					self.hideAdminConsole();
					acf = self.adminConfigForm;
				}
        			var ctls = JSKitLib.mapClass2Object({}, acf);
				var views = ctls['js-topAdminConsoleViews'];
				for (var i=0; i < views.childNodes.length; i++) {
					var vctls =JSKitLib.mapClass2Object({}, views.childNodes[i]);
					if (vctls['js-topAdminConsoleViewActive'].value == this.view.type) 
						vctls['js-topAdminConsoleViewTitle'].value = newValue;
				}
				if (self.config.server.views)
					for (var  i=0; i<self.config.server.views.length; i++)
						if (self.config.server.views[i].type == this.view.type)
							self.config.server.views[i].title = newValue;
				self.tabAlign();
				if (!self.adminConsole || !JSKitLib.visible(self.adminConsole)) self.saveConfig();
				var config = self.processAdminConfig();
				self.refreshData(config);
				
			}
			var obj={
				 'type':                        'Tab',
				 'inpSize':                     '50px',
				 'containerElement':            tabMain,
				 'field':                       divTitle,
				 'itemObject':                  views[i],
				 'Property':                    'title',
				 'mode':                        'full'
			};
			new JSIPE(obj);
		}
		views[i].tab = tabMain; // Obj ref to tab node

		td.appendChild(tabWrap);
		tr.appendChild(td);
	}

	var table = this.table(tr);
	table.setAttribute('width', '100%');
    
	return table;

}

JSTC.prototype.epDeleted = function(itemId) {
	this.serverPut("del", "uid=" + itemId);
}
JSTC.prototype.epEdited = function(item) {
	var data = [];
	var tmpl = [['id', 'uid'], ['link', 'permalink'], ['title', 'title'], ['description', 'descr']];
	for(var i = tmpl.length - 1; i >= 0; i--) {
		var nam = tmpl[i][0];
		var prm = tmpl[i][1];
		data.push(prm + '=' + encodeURIComponent(item[nam]));
	}
	this.serverPut("put", data.join('&'));
}
JSTC.prototype.epMoved = function(items) {
	this.serverPut("order", "ids="+items.join(','));
}

JSTC.prototype.createThumbnail = function(image, link) {
       var thumbnail = this.cr('div');
       thumbnail.style.cssFloat   = 'left';
       thumbnail.style.styleFloat = 'left';
       thumbnail.style.width    = this.thumbnailWidth + 'px';
	var getThumbHeight = function(imageName) {
		var vl = imageName.match(/-(\d+)x(\d+)\..{3}$/);
		if(vl) {
			return parseInt(vl[2] || '');
		} else {
			return 0;
		}
	}
	var thumbheight = getThumbHeight(image) || this.thumbnailHeight;
       thumbnail.style.height   = thumbheight + 'px';
       thumbnail.style.fontSize = thumbheight + 'px'; // ie6
       JSKitLib.addPNG(thumbnail, image);
       thumbnail.style.marginRight = 0.2 + 'em';
       thumbnail.style.marginTop = '2px';
       thumbnail.style.cursor= 'pointer';
       thumbnail.onclick = function(){ window.location.href = link }
       return thumbnail;
}

JSTC.prototype.createBodyDefault = function() {
	if (this.isAdmin) {
		if (this.isNewSite) {
			var body = JSKitLib.html(this.dtBodyNew);
			var ctls = JSKitLib.mapClass2Object({}, body);
			var adminConsoleLaunch = ctls['js-topAdminConsoleLaunch'];
			var self = this;
			adminConsoleLaunch.onclick = function() { 
				self.showAdminConsole();
			}
		} else {
			var body = this.createBodyAdminMsg($JTL('adminMsgNoViews'));
		}
	}
	return body;
}

JSTC.prototype.createBodyAdminMsg = function(msg) {
	var el = this.crBodyElements(this.dtBodyAdminMsg, 'js-topBodyAdminMsgBody', msg);
	return el.body;
}

JSTC.prototype.createBodyMsg = function(msg) {
	var el = this.crBodyElements(this.dtBodyMsg, 'js-topBodyMsgBody', msg);
	return el.body;
}

JSTC.prototype.createBody = function(navData) {
	var self = this;
	var views = this.getActiveViews();
	var contentDiv = this.cr('div');
	contentDiv.className = "js-topcdiv";

	for (var i=0; i < views.length; i++) {
		var tn = views[i].type;
		var fname = tn + 'PanelConstr';
		if(!this[fname]) continue;
		navData.part[tn] = navData.part[tn] || {};
		var panel = this[fname](navData.part[tn], views[i]);
		if (typeof panel == 'object') {
			views[i].content = panel;
			contentDiv.appendChild(panel);
		}
	}

	// Handling for new views
	if (!views.length) {
		var content = this.createBodyDefault();
		contentDiv.appendChild(content);
	}

	return contentDiv;
}

JSTC.prototype.crBodyElements = function(tmpl, elem, msg) {
        var body = JSKitLib.html(tmpl);
        var ctls = JSKitLib.mapClass2Object({}, body);
        var items = ctls[elem];
        var template = items.innerHTML;
        items.innerHTML = msg || '';
	return {'template' : template, 'items' : items, 'body' : body}
}

JSTC.prototype.CRPanelConstr = function(panelCfg) {
	var self = this;
	var el = self.crBodyElements(this.dtComments, 'js-topComments');	

	var crItem = function(obj, i) {
		if (!obj.Name) obj.Name = $JTL("guest");
		var item = JSKitLib.html(self.tmpl(el.template, obj));
		var ictls = JSKitLib.mapClass2Object({}, item);
		ictls['js-topCommentPermalink'].href = obj.permalink;
		if (i % 2 != 0) JSKitLib.addClass(item, "js-topRowColor2");
		return item;
	}
        if (panelCfg.items.length) {
                JSKitLib.map(function(item, i, items) {
                        self.addChild(el.items, crItem(items[i], i));
                }, panelCfg.items);
        } else el.items.appendChild(this.createBodyMsg($JTL('msgNoComments')));

	JSKitLib.preventSelect(el.body);
	self.iPhoneScroll(el.body);
	return el.body;
}

JSTC.prototype.PLPanelConstr = function(panelCfg, view) {
	if(this.oldPollPanel)
		return this.oldPollPanel;
	var content = this.cr("div");
	this.oldPollPanel = content;
	content.jsk$isEmbedded = true;
	content.jsk$notShowBjs = true;
	content.jsk$supressAdminConsole = true;
	content.jsk$msg = this.createBodyMsg($JTL('msgNoPoll'));
	var config = JSKitLib.readConfig('polls', this.target, {}, 'path');
	if (config.path) content.setAttribute("path", config.path);
	if (!window.JSPC$Callbacks) JSPC$Callbacks = [];
	var toggleViewsCallback = function(eventName, oldView, activeView) {
		if (oldView && oldView.type == "PL") JSKW$Events.syncBroadcast("JSKitPolls_closeAdminConsole", content);
		if (activeView.type == "PL") JSKitLib.deferCall(function() { JSKW$Events.syncBroadcast("JSKitPolls_openAdminConsole", content); });
	};
	this.eventsCtx = JSKW$Events.registerEventCallback(this.eventsCtx, toggleViewsCallback, "JSKitNavigator_toggleViews");
	JSPC$Callbacks.push(function() { try { new JSPoll(content); } catch(e) {} });
	return content;
}

JSTC.prototype.EPPanelConstr = function(panelCfg) {
	var jsepw = new JSEPW();
	jsepw.setCallbacks(this, {
		deleted: this.epDeleted,
		moved: this.epMoved,
		edited: this.epEdited
	});
	var subWidget = this.cr("div");
	subWidget.className = "js-epAdminEP";
	jsepw.setTemplates(function() { return 	{
		title: "Click to change title",
		link: "http://js-kit.com/",
		description: "Click to change description"}},
		jsepw.dtAdminEPItem);
	subWidget.msgNoPicks = this.createBodyMsg($JTL('msgNoPicks'));
	return jsepw.installPlugin(subWidget,
			panelCfg.items, this.isAdmin);
}

JSTC.prototype.TRPanelConstr = function(panelCfg) {
	var self = this;
	var el = self.crBodyElements(this.dtBodyTop, 'js-topItems');

	var topItem = function(items, idx) {
		var item = items[idx];
		var image = item.thumbnail;
		var idiv = JSKitLib.html(self.tmpl(el.template, item));
		if (idx % 2 != 0) JSKitLib.addClass(idiv, "js-topRowColor2");
		var ictls = JSKitLib.mapClass2Object({}, idiv);
		var link = ictls['js-topItemLink'];
		var domain = self.target.getAttribute("site") || window.location.protocol + "//" + window.location.host;
		link.href = (item.url.match(/^[a-z]+:\/\//)) ? item.url : domain + item.url;
		if (idiv.firstChild && image)
	               idiv.insertBefore(self.createThumbnail(image, link.href),idiv.firstChild);
		if (self.config.get('target')) 
			link.target = self.config.get('target');
		var stars = ictls['js-topItemStars'];
		stars.appendChild(item.stars);
		JSKitLib.preventSelect(idiv);
		return idiv;
	}
	if (panelCfg.items.length) {    
		JSKitLib.map(function(item, i, items) {
			self.addChild(el.items, topItem(items, i));
		}, panelCfg.items);
	} else {
		if (this.isAdmin) {el.items.appendChild(this.createBodyAdminMsg($JTL('adminMsgNoRatings')));}
		else {el.items.appendChild(this.createBodyMsg($JTL('msgNoTopItems')));}
	}

	JSKitLib.preventSelect(el.body);
	self.iPhoneScroll(el.body);
	return el.body;
}

JSTC.prototype.TSPanelConstr = function(panelCfg) {
	var self = this;
	var el = self.crBodyElements(this.dtBodyTopScore, 'js-topScoreItems');

	var topItem = function(items, idx) {
		var item = items[idx];
		var image = item.thumbnail;
		var idiv = JSKitLib.html(self.tmpl(el.template, item));
		if (idx % 2 != 0) JSKitLib.addClass(idiv, "js-topRowColor2");
		var ictls = JSKitLib.mapClass2Object({}, idiv);
		var link = ictls['js-topScoreItemLink'];
		var domain = self.target.getAttribute("site") || window.location.protocol + "//" + window.location.host;
		link.href = (item.url.match(/^[a-z]+:\/\//)) ? item.url : domain + item.url;
		if (idiv.firstChild && image)
			idiv.insertBefore(self.createThumbnail(image, link.href),idiv.firstChild);
		if (self.config.get('target')) 
			link.target = self.config.get('target'); 
		var stars = ictls['js-topScoreItemStars'];
		stars.appendChild(item.stars);
		JSKitLib.preventSelect(idiv);
		return idiv;
	}
	if (panelCfg.items.length) {    
		JSKitLib.map(function(item, i, items) {
			self.addChild(el.items, topItem(items, i));
		}, panelCfg.items);
	} else {
		if (this.isAdmin) {el.items.appendChild(this.createBodyAdminMsg($JTL('adminMsgNoScore')));}
		else {el.items.appendChild(this.createBodyMsg($JTL('msgNoScoredItems')));}
	}

	JSKitLib.preventSelect(el.body);
	self.iPhoneScroll(el.body);
	return el.body;
}

JSTC.prototype.HTPanelConstr = function(panelCfg) {
	var self = this;
	var el = self.crBodyElements(this.dtBodyHot, 'js-topHotItems');

	var hotItem = function(items, idx) {
		var item = items[idx];
		var image = item.thumbnail;
		var idiv = JSKitLib.html(self.tmpl(el.template, item));
		if (idx % 2 != 0) JSKitLib.addClass(idiv, "js-topRowColor2");
		var ictls = JSKitLib.mapClass2Object({}, idiv);
		var link = ictls['js-topHotItemLink'];
		var domain = self.target.getAttribute("site") || window.location.protocol + "//" + window.location.host;
                link.href = (item.url.match(/^[a-z]+:\/\//)) ? item.url : domain + item.url;
                if (idiv.firstChild && image)
                       idiv.insertBefore(self.createThumbnail(image, link.href),idiv.firstChild);
		if (self.config.get('target'))
			link.target = self.config.get('target');
		JSKitLib.preventSelect(idiv);
		return idiv;
	}

	if (panelCfg.items.length) {    
		JSKitLib.map(function(item, i, items) {
			self.addChild(el.items, hotItem(items, i));
		}, panelCfg.items);
	} else {
		var dataTypes = this.getServerDataTypes();
		if (dataTypes.TR){
			el.items.appendChild(this.createBodyMsg($JTL('hotInProgress')));
		} else {
			if (this.isAdmin) {el.items.appendChild(this.createBodyAdminMsg($JTL('adminMsgNoRatingsNoHot')));}
			else {el.items.appendChild(this.createBodyMsg($JTL('msgNoHotItems')));}
		}
	}
	
	self.iPhoneScroll(el.body);
	JSKitLib.preventSelect(el.body);
	return el.body;
}

JSTC.prototype.displayTop = function(navData, opts) {
	var self = this;

	navData.Title = this.config.get('title');
	navData.code = this.getPropCode();

	var template = this.getMainTemplate();        

	var pdiv = JSKitLib.html(this.tmpl(template, navData));
	var ctls = JSKitLib.mapClass2Object({}, pdiv);
	this.ctls = ctls;

	JSKitLib.preventSelect(ctls['js-topHeader']);
	JSKitLib.preventSelect(ctls['js-topHelp'], {exclude:['IE']});
	JSKitLib.preventSelect(ctls['js-topInvitation'], {exclude:['IE']});

	/* Navigation Tabs */
	var topNav = ctls['js-topNav'];
	topNav.appendChild(this.createTabs());

	/* Main Content */
	var topBody = ctls['js-topBody'];
	topBody.appendChild(this.createBody(navData));

	/* Activate the Main View */
	// TODO: handle for single view
	this.toggleViews(0);

	/* Grab it */
	/* Grab it panel was temporary hidden[M:1518] 
	var gt = ctls['js-topGrab'];
	gt.onclick = function() { self.toggleGrab(); }; */

	var gc = ctls['js-topCode'];
	gc.value = this.getPropCode();

	ctls['js-topPoweredBy'].onclick = function() {
		document.location.href='http://js-kit.com/navigator/?wow';
	};
	if (opts.whitelabel) {
		JSKitLib.hide(ctls['js-topPoweredBy']);
		JSKitLib.hide(ctls['js-topGrab']);
	}

	/* Footer */
	if(opts.subs) ctls['js-topPoweredBy'].style.display = 'none';

	/* Admin */
	if (this.isAdmin) {
		var adminBar = this.ctls['js-topAdminBar'];
		JSKitLib.show(adminBar);
		var adminConsoleLaunch = this.ctls['js-topAdminConsoleLaunch'];
		adminConsoleLaunch.onclick = function() { 
			self.showAdminConsole();
		}
		if (!self.target.getAttribute('title')){
			var header = ctls['js-topTitle'];
			header.wasEdited = function(newValue) {
				this.innerHTML = JSKitLib.htmlQuote(newValue);
				self.config.server.title = newValue;
				navData['Title'] = newValue;
				self.saveConfig(self.config.server);
			}
                        var obj={
                                 'containerElement':            ctls['js-topHeader'],
                                 'field':                       header,
                                 'itemObject':                  navData,
                                 'type':                        'Others',
                                 'Property':                    'Title',
                                 'mode':                        'full'
                                };
                        new JSIPE(obj);
		}
	}

	this.target.innerHTML = '';
	this.addChild(this.target, pdiv);
        if(this.oldPollPanel) JSKitLib.addScript(JSTC.DOMAIN + "/polls.js", this.oldPollPanel);
	
        var ctls = JSKitLib.mapClass2Object({}, this.target);
        this.addClip(ctls['js-topTop']);
        this.addClip(ctls['js-topHot']);
        this.addClip(ctls['js-topTopScore']);
        this.addClip(ctls['js-topCommentsRoll']);
	
	this.tabAlign();
}

JSTC.prototype.tabAlign = function(){
	var self = this;
	if (self.titleTabArr[0] && self.titleTabArr[0].offsetHeight) var max = self.titleTabArr[0].offsetHeight;
	for (var i=0; i<self.titleTabArr.length; i++ )
		if(self.titleTabArr[i].offsetHeight>max)
			max = self.titleTabArr[i].offsetHeight;
	for (var i=0; i<self.titleTabArr.length; i++ ){
		self.titleTabArr[i].parentNode.style.height = max+'px';
		self.titleTabArr[i].style.paddingTop = 
			Math.round((max-self.titleTabArr[i].offsetHeight+parseInt(self.titleTabArr[i].style.paddingTop || 0))/2) + 'px';
	}
}

/*
 * Administration 
 */

JSTC.prototype.createAdminConsole = function() {
	var self = this;
	var tmpl = JSKitLib.html(this.dtAdminConsole);
	var ctls = JSKitLib.mapClass2Object({}, tmpl);

	var pos = JSKitLib.findPos(this.target);
	var ac = ctls['js-topAdminConsole'];

	ac.opts = {"width" : 340, "margin" : 10};
	ac.opts.pos = (pos[0] < ac.opts.width + ac.opts.margin) ? 
		(document.body.clientWidth < pos[0] + self.target.offsetWidth + ac.opts.width + ac.opts.margin) ?
			{"x" : pos[0], "y" : pos[3] + ac.opts.margin} :
			{"x" : pos[0] + self.target.offsetWidth + ac.opts.margin, "y" : pos[1]} :
		{"x" : pos[0] - ac.opts.width - ac.opts.margin, "y" : pos[1]};
	JSKitLib.addStyle(ac, "left:" + ac.opts.pos.x + "px; top:" + ac.opts.pos.y + "px; width: " + ac.opts.width + "px;");

	var ach = ctls['js-topAdminConsoleHeader'];
	new JSDL(ac, [ach]);
	ac.jsk$on_start_drag = function(e) {self.postCheckBoxesForIE6();}

	var acv = ctls['js-topAdminConsoleViews'];
	var vTemplate = acv.innerHTML;
	acv.innerHTML = '';

	this.adminConfigForm = ac;

	var titleNode = ctls['js-topAdminConsoleTitle'];
	titleNode.value = this.config.get('title');
	titleNode.onchange = function() {
		self.previewConfig();
	}

	if (this.config.getInline('title')) {
		titleNode.disabled = true;
		var tNoEdit = ctls['js-topAdminConsoleNoEditTitle'];
		JSKitLib.show(tNoEdit);
		tNoEdit.onclick = function() { alert($JTL('adminMsgTitleUneditable')); }
		titleNode.parentNode.appendChild(tNoEdit);
	}

	var countNode = ctls['js-topAdminConsoleCount'];
	countNode.value = this.config.get('count');
	countNode.onchange = function() {
		self.previewConfig();
	}

	if (this.config.getInline('count')) {
		countNode.disabled = true;
		var cNoEdit = ctls['js-topAdminConsoleNoEditCount'];
		JSKitLib.show(cNoEdit);
		cNoEdit.onclick = function() { alert($JTL('adminMsgCountUneditable')); }
		countNode.parentNode.appendChild(cNoEdit);
	}

	var self = this;

	var acViews = function(views, idx) {
		var vdiv = JSKitLib.html(vTemplate);
		var vctls = JSKitLib.mapClass2Object({}, vdiv);

		var viewActiveNode = vctls['js-topAdminConsoleViewActive'];
		if (!JSKitLib.isIE()) viewActiveNode.style.backgroundColor = "#ffffff";
		viewActiveNode.value = views[idx].type;
		if (views[idx].active) {
			viewActiveNode.checked = true;
		}

		// Using onclick instead of onchange to support IE
		viewActiveNode.onclick = function() { 
			if (
				(self.isViewActive(this.value) && !this.checked) 
				|| ( (!self.isViewActive(this.value)) && this.checked) 
			) {
				self.previewConfig();
			}
		}

		// View Type
		var viewType = vctls['js-topAdminConsoleViewType'];
		JSKitLib.preventSelect(viewType);
		
		var vt = document.createTextNode(JSTC.VIEW_TYPES[views[idx].type]);
		viewType.appendChild(vt);

		var viewTypeValue = vctls['js-topAdminConsoleViewTypeValue'];
		viewTypeValue.value = views[idx].type;

		// View Title
		var viewTitleNode = vctls['js-topAdminConsoleViewTitle'];
		viewTitleNode.value = views[idx].title;
		viewTitleNode.onchange = function() {
			self.previewConfig();
		}

		vdiv.vs_moved = function(){
			self.postCheckBoxesForIE6();
			self.previewConfig();
		}
		vdiv.vs_handles = function() { return [viewType]; }

		return vdiv;
	}

	JSKitLib.map(function(view, i, views) {
		acv.appendChild(acViews(views, i));
	}, this.getViews());
	
	if (!self.isNewSite){
		self.jsvs = new JSVS();	
		self.jsvs.makeSortable(acv);
	}

	var acCancel = ctls['js-topAdminConsoleCancel'];

	if (this.isNewSite) {
		JSKitLib.hide(acCancel);
	}

	acCancel.onclick = function() { 
		self.refreshData(); 
		self.hideAdminConsole();
	}

	var acSave = ctls['js-topAdminConsoleSave'];
	var acSaving = ctls['js-topAdminConsoleSaving'];

	if (this.isNewSite) {
		acSave.innerHTML = $JTL('install');
		acSaving.innerHTML = $JTL('installing');
	}

	var numCurViews = self.getActiveViews().length;
	acSave.onclick = function() { 
		acCancel.disabled = true;
		JSKitLib.toggle(acSave); 
		JSKitLib.toggle(acSaving); 
		self.saveConfig(); 
		self.hideAdminConsole();
	}

	this.onSaveConfigAck = function() {        
		self.hideAdminConsole();
		acCancel.disabled = false;
		JSKitLib.toggle(acSave); 
		JSKitLib.toggle(acSaving); 
	}

	JSKitLib.preventSelect(ctls['js-topAdminConsoleHeader'], {include:['IE']});
	JSKitLib.preventSelect(ctls['js-topAdminConsoleViewsHeader'], {include:['IE']});

	JSKitLib.hide(ac);
	return ac;
}

// Reads the new admin configuration and builds an object
JSTC.prototype.processAdminConfig = function() {

	// Create a config object out of the admin's input
	var config = {};
	config.views = [];

	var acf = this.adminConfigForm;
	var ctls = JSKitLib.mapClass2Object({}, acf);
	config.title = ctls['js-topAdminConsoleTitle'].value;
	config.count = ctls['js-topAdminConsoleCount'].value;

	var views = ctls['js-topAdminConsoleViews'];

	for (var i=0; i < views.childNodes.length; i++) {
		var vctls = JSKitLib.mapClass2Object({}, views.childNodes[i]);
		var view = {};
		view.type = vctls['js-topAdminConsoleViewTypeValue'].value;
		view.title = vctls['js-topAdminConsoleViewTitle'].value;
		view.active = vctls['js-topAdminConsoleViewActive'].checked;
		config.views.push(view);
	}

	//this.adminConfig = config;
	return config;
}

JSTC.prototype.previewConfig = function() {
	var config = this.processAdminConfig();
	this.refreshData(config);
}

JSTC.prototype.saveConfig = function(conf) {

	var config = conf || this.processAdminConfig();

	this.config.pending = config; // will be set to this.config.server when ack'd

	// Params
	var navView = [];
	var navViewTitle = [];
	var navViewActive = [];

	for (var i=0; i < config.views.length; i++) {
		navView[i] = config.views[i].type;
		navViewTitle[i] = config.views[i].title;
		navViewActive[i] = config.views[i].active;
	}

	var query = 'ref=' + encodeURIComponent(this.domain);
	query += '&navTitle=' + encodeURIComponent(config.title);
	query += '&navCount=' + config.count;
	for (var i=0; i < navView.length; i++) {
		query += '&navView[' + i + ']=' + navView[i] + '&navViewTitle[' + i + ']=' +  encodeURIComponent(navViewTitle[i]) + '&navViewActive[' + i + ']=' + navViewActive[i];
	}

	query += '&jx=' + this.jtaIndex;

	var sc = document.createElement('script');
	sc.src = JSTC.DOMAIN + '/navcfg.put?' + query;
	sc.setAttribute("charset", "utf-8");

	this.target.appendChild(sc);
}

JSTC.prototype.saveConfigAck = function(data) {
	if (typeof data == 'object') {
		if (data.success) {
			this.config.server = this.config.pending;
			this.onSaveConfigAck();
			this.isNewSite = false;
		}
	} 
}


JSTC.prototype.prepAdminConsole = function() {

	var self = this;

	var prep = function() {
		self.buildAdminConsole();
	}    

	// document.body.append functionality can only happen after window.onload in IE
	JSKitLib.deferCall(prep, true);

}

JSTC.prototype.buildAdminConsole = function() {
	var ac = this.createAdminConsole();
	this.adminConsole = ac;
	document.body.appendChild(ac);

	this.postCheckBoxesForIE6();
}

JSTC.prototype.postCheckBoxesForIE6 = function () {
	// For IE6, boxes may only be checked while attached to the document
	if (JSKitLib.isPreIE7()) {
		var els = JSKitLib.getElementsByClass(this.adminConsole, 'js-topAdminConsoleViewActive', 'input');
		if (els && els.length) {
			for (var i=0; i < els.length; i++) {
				if (this.isViewActive(els[i].value)) {
					els[i].checked = true;
				}
			}
		}
	}
}


JSTC.prototype.hideAdminConsole = function() {

	if (
		this.adminConsole 
		&& JSKitLib.visible(this.adminConsole) 
	) {
		document.body.removeChild(this.adminConsole);
		this.adminConsole = null;
	}
}

JSTC.prototype.showAdminConsole = function() {
	if (!this.adminConsole || !JSKitLib.visible(this.adminConsole)) {
		this.buildAdminConsole();        
		JSKitLib.show(this.adminConsole);
	}
}

JSTC.prototype.getRelativeTime = function(seconds) {
	if (seconds < 60) {
		return (seconds == 1) ? '1 second' : seconds + ' seconds'; 
	} else if (seconds < 3600) {
		var minutes = Math.round(seconds/60);
		return (minutes == 1) ? '1 minute' : minutes + ' minutes';
	} else if (seconds < 86400) {
		var hours = Math.round(seconds/3600);
		return (hours == 1) ? '1 hour' : hours + ' hours';
	} else {
		var days = Math.round(seconds/86400);
		return (days == 1) ? '1 day' : days + ' days';
	}
}

JSTC.prototype.getTextForTotalVotes = function(votes) {
  var text;
  switch(parseInt(votes)) {
    case  1: text = votes + ' ' + $JTL('vote');  break;
    default: text = votes + ' ' + $JTL('votes'); break;
  }
  return $JTL(text);
}

JSTC.prototype.getTextForTotalScoreVotes = function(votes) {
  return $JTL('by') + ' ' + this.getTextForTotalVotes(votes);
}

JSTC.prototype.prepHotItems = function(items) {

	if (!items.length) return;

	// Prepare vote counts
	for (var i=0; i < items.length; i++) {
		items[i].votes = this.getTextForTotalVotes(items[i].val2); 
	}    

	return items;
}

JSTC.prototype.prepTopItems = function(items) {

	if(!items.length) return;

	// Prepare our stars 
	for (var i=0; i < items.length; i++) {
		items[i].stars = this.getMiniStars(items[i].val1, 10);
		items[i].rating = JSKitLib.zeroPad(JSKitLib.round(items[i].val1 / 2, 2), 2);
		items[i].votes = this.getTextForTotalVotes(items[i].val2); 
		items[i].counter = i + 1;
	}    

	return items;
}

JSTC.prototype.htmlBreak = function (newValue) {
       var wbstr = JSKitLib.getBrowser()=='gecko' ? '<wbr>' : '&shy;';
       newValue = newValue.replace(/([^&<>]{3})([^<>]{3})/g, "$1"+wbstr+"$2");
       return newValue;
}

JSTC.prototype.prepTopScoreItems = function(items) {

	if(!items.length) return;

	// Prepare our stars 
	for (var i=0; i < items.length; i++) {
		items[i].rating = JSKitLib.round(items[i].val1>0 ? '+'+items[i].val1 : items[i].val1);
		items[i].stars = this.getMiniThumb(items[i].rating);
		items[i].votes = this.getTextForTotalScoreVotes(items[i].val2); 
	}    

	return items;
}

/*
 * Navigator Data Processing 
 */
JSTC.prototype.processDataCR = function(navData) {
	var wl = window.location;
	var localDate = function(t){
		if(!t) return "";
		var d = new Date(t * 1000);
		return d.toLocaleDateString();
	}
	var parseText = function(text){
		var r = /<\/?(a|em|strong|i|b|u|sup|sub|object|param|embed|span|pre|p)(.|\n)*?>/gi;
		text = text.replace(/<object(.|\n)+?<\/object>/gi,"[video]");
		text = text.replace(r,"");
		return (text.length > 150) ? text.slice(0,150) + "..." : text;
	}
	var parseLink = function(link){
		var r=/^(([a-z]{1,6}):\/\/)?(([a-z0-9-]{1,63}\.)+[a-z]{2,10})?(\/~[a-z0-9_ \.-]+)?(.*)/i;
		var arr = r.exec(link);
		return arr[6] || "/";
	}
	navData.part.CR.items = JSKitLib.map(function(o){
		o.Date = localDate(o.TS);
		o.permalink = o.permalink || 
			      wl.protocol+'//'+wl.host+(o.path||'');
		o.ShowLink = JSKitLib.htmlQuote(parseLink(o.permalink)); 
		o.Text = parseText(o.Text); 
	}, navData.recentComments);
}

JSTC.prototype.processDataEP = function(navData) {

	var EP = JSKitLib.map(function(o) {
			o.description = o.opt || "";
			o.link = o.url || "/";
			o.id = o.uid;
		}, JSKitLib.filter(function(o) {
		return (o.type === "EP"); }, navData.data));

	navData.part.EP.items = EP;
}

JSTC.prototype.processDataTop = function(navData) {

	var TR = JSKitLib.filter(
		function(o) { return (o.type === "TR" && o.title.length); },
			navData.data);

	navData.part.TR.items = this.prepTopItems(TR) || [];
}

JSTC.prototype.processDataTopScore = function(navData) {

	var TS = JSKitLib.filter(
		function(o) { return (o.type === "TS" && o.title.length); },
			navData.data);

	navData.part.TS.items = this.prepTopScoreItems(TS) || [];
}

JSTC.prototype.processDataHot = function(navData) {

	// Hot by Hour
	var HH = JSKitLib.filter(
		function(o) { return (o.type === "HH" && o.title.length); },
			navData.data);

	// Hot by Day
	var HD = JSKitLib.filter(
		function(o) { return (o.type === "HD" && o.title.length); },
			navData.data);

	// Hot by Week
	var HW = JSKitLib.filter(
		function(o) { return (o.type === "HW" && o.title.length); },
			navData.data);

	// For Hot, use HD, and if less than 2 results use HW
	navData.part.HT.items = this.prepHotItems(HD) || [];
	if (navData.part.HT.items.length < 2) {
		navData.part.HT.items = this.prepHotItems(HW) || [];
	}

}

// Basically a call to newData w/ more configurability
JSTC.prototype.refreshData = function(config) {
	var data = this.serverData[0];
	var opts = this.serverData[1];

	if (!config) config = this.config.server;

	while(this.target.firstChild) this.target.removeChild(this.target.firstChild);

	var navData = this.prepareData(data, config);

	// Now parse template and attach node
	this.displayTop(navData, opts);
}

// JS Editor's Picks Window
function JSEPW() {
	var self = this;
	this.get = function(id) { return document.getElementById(id); }
	this.cr = function(tag) { return document.createElement(tag); }
	this.itemIds = [];
	this.callbacks = {};
	this.hostWidget = this;
	this.setCallbacks = function(hostWidget, cbs) {
				self.hostWidget = hostWidget;
				self.callbacks = cbs; }
	this.callBack = function(cbName, arg) {
		var args = [arg];
		self.callbacks[cbName].apply(self.hostWidget, args);
		return false;
	}
}

JSEPW.prototype.htmlBreak = function (newValue) {
       var wbstr = JSKitLib.getBrowser()=='gecko' ? '<wbr>' : '&shy;';
       newValue = newValue.replace(/([^&<>]{6})([^<>]{6})/g, "$1"+wbstr+"$2");
       return newValue;
}

JSEPW.prototype.installPlugin = function(rhtml, data, admin) {
	var self = this;
	var items = this.cr('div');
	items.className = "js-epAdminEPItems";
	var footer = this.cr('div');
	footer.className = "js-epAdminEPFooter";
	JSKitLib.preventSelect(footer); 
	footer.innerHTML = '<a class="js-epAdminEPItemAdd js-topFont">[<span class="js-epAdminEPItemAddLink" style="cursor: pointer">new link</span>]</a>'
	if (!data.length && !admin) items.appendChild(rhtml.msgNoPicks);
	for (var i=0; i < data.length; i++)
	{
		var div = JSKitLib.html(this.tmpl(this.tmplItem, data[i]));
		div.className = "js-epAdminEPItem";
		if (i % 2 != 0) JSKitLib.addClass(div, "js-topRowColor2");
		if(admin) {
			div.id = data[i].id;
			data[i].order = i;
			self.init_vs_moved(div, data, data[i]);
		}
		if (JSKitLib.getBrowser() == "IE") div.style.styleFloat ='left';
		this.itemHandler(div, admin, data, data[i]);
		JSKitLib.preventSelect(div);
		items.appendChild(div);
	}
	self.jsvs = new JSVS();
	if (admin) self.jsvs.makeSortable(items);
	this.topElemHandler(items, footer, admin, data);
	rhtml.appendChild(items);
	rhtml.appendChild(footer);
	return rhtml;
}

JSEPW.prototype.dtAdminEPItem
='<div class="js-epAdminEPItem">'
+	'<div style="float: right;" height="100%">'
+		'<div class="js-epAdminEPItemDel" style="position:absolute; right: 1px; top: 0; cursor: pointer">'
+			'<img src="'+JSTC.IMG_DIR+'/nav_collapse.gif"></img>'
+		'</div>'
+	'</div>'
+       '<div class="js-epItem-TL js-topFont" style="float: left; cursor: pointer"><a style="color: inherit" href="{Link}">{title}</a></div>'
+	'<div style="clear:both"></div>'
+	'<div class="js-epItemEField-title js-topFont" style="float: left; display: none">{title}</div>'
+	'<div style="clear:both"></div>'
+	'<div class="js-epItemEField-link js-topFont" style="float: left; display: none"><a style="color: inherit" href="{Link}">{link}</a></div>'
+       '<div style="clear:both"></div>'
+	'<div class="js-epItemEField-description js-topDetailFont" style="float: left">{description}</div>'
+	'<div style="clear:both"></div>'
+'</div>';

JSEPW.prototype.init_vs_moved = function(div, data, dataItem) {
	var self = this;
	div.vs_moved = function(index) {
		var oldOrder = dataItem.order;
		data.splice(oldOrder, 1);
		data.splice(index-1, 0, dataItem);
		var ids = [];
		for (var i=0; i<data.length;i++) {
			data[i].order = i;
			ids.push(data[i].id);
		}
		JSKitLib.map(function(child, i) {
			if (i % 2 != 0)
				JSKitLib.addClass(child, "js-topRowColor2");
			else
				JSKitLib.removeClass(child, "js-topRowColor2");
		}, this.parentNode.childNodes);
		return self.callBack('moved', ids);
	}
}

JSEPW.prototype.itemHandler = function(div, admin, data, itemObject) {
	var self = this;
	var ctls = JSKitLib.mapClass2Object({}, div);
	var del = ctls["js-epAdminEPItemDel"];
	del.style.display = 'none';
        var title = ctls["js-epItemEField-title"];
        var link = ctls["js-epItemEField-link"];
        var titleLink = ctls["js-epItem-TL"];
        if (!admin) return;
	titleLink.onclick = function(e) {
		e = e || window.event;
		title.style.display = '';		
		link.style.display = '';		
		this.style.display = 'none';
		JSKitLib.preventDefaultEvent(e);
		title.onclick();
	}

	div.onmouseover = function() { del.style.display = ''; }
	div.onmouseout = function() { del.style.display = 'none'; }
	del.onclick = function() {
		div.parentNode.removeChild(div);
		data.splice(itemObject.order, 1);
		for (var i=0; i<data.length;i++) {
			data[i].order = i; 
			if (i % 2 != 0) JSKitLib.addClass(document.getElementById(data[i].id), "js-topRowColor2");
			else JSKitLib.removeClass(document.getElementById(data[i].id), "js-topRowColor2");
		}

		if(data.length == 1)
			self.jsvs.itemSortable(document.getElementById(data[0].id), false);
		return self.callBack('deleted', div.id);
	}
	
	var siblings = [];	
	var makeEditable = function(element, Property) {
		element.onmouseover = function () {
			if(!element.input) 
				JSKitLib.addClass(element, "js-epActiveElem");}
		element.onmouseout = function () {JSKitLib.removeClass(element, "js-epActiveElem");}
                var obj={
                         'type':                        'Others',
                         'containerElement':            div,
                         'field':                       element,
                         'itemObject':                  itemObject,
                         'Property':                    Property,
                         'siblings':                    siblings,
                         'mode':                        'full'
                        };
		obj.jsipe$start = function(){
			JSKitLib.removeClass(div, "js-nsgecko");
			element.onmouseout();
			return true;
		}	
		var prevSelect = function(){
			JSKitLib.preventSelect(div);
		} 
		obj.jsk$on_cancel_exit = prevSelect;
		obj.jsk$on_submit_exit = prevSelect;
		
                var jsipe = new JSIPE(obj);
                siblings.push(jsipe.obj.field);
		element.wasEdited = function(newValue) { 
			while(this.hasChildNodes())
             		        this.removeChild(this.firstChild);
			if (this.isHtmlLink) {
				var a = newValue.match(/^\s*([a-z]{3,7}:\/\/.*)$/);
				if(!a && newValue.indexOf("/"))
					newValue = 'http://' + newValue;
				else if(a) newValue = a[1];
				var tagA = document.createElement("a");
				tagA.style.cssText = "color: inherit";
				tagA.setAttribute('href', JSKitLib.htmlQuote(newValue, {attribute: true}));
                		tagA.appendChild(document.createTextNode(newValue));
				this.appendChild(tagA);	
			} else {
                		this.appendChild(document.createTextNode(newValue));
			}
			itemObject[Property] = newValue;
			div.tId = setTimeout(function(){
				title.style.display = 'none';
				link.style.display = 'none';
				titleLink.style.display = '';
				titleLink.innerHTML = 
				'<a style="color: inherit" href="'
                        	+ itemObject['link'] + '">' + itemObject['title'] +'</a>';
                	}, 5000);
			self.callBack('edited', itemObject); 
		}
	} 
	for(var c in ctls) { 
		var a = c.match(/^js-epItemEField-(.*)/); 
		if(!a) continue;
		makeEditable(ctls[c], a[1]); 
	}
}

JSEPW.prototype.setTemplates = function(itemTemplate, tI){
	this.takenData = itemTemplate || function() { return {title: "Click here to enter new title", link: "Click here to enter new URL", description: "Click here to enter new description"}}
	this.tmplItem = tI || this.dtAdminEPItem;
}

JSEPW.prototype.topElemHandler = function(items, footer, admin, data){
	var self = this;
	if (!admin) {footer.style.display = 'none'; return}
	footer.firstChild.onclick = function(){
		var dataItem = self.takenData(); 
		var newItem = self.cr('div');
		newItem = JSKitLib.html(self.tmpl(self.tmplItem, dataItem));
		newItem.className = "js-epAdminEPItem";
		JSKitLib.preventSelect(newItem);
		if (JSKitLib.getBrowser() == "IE") newItem.style.styleFloat ='left';
		var d = new Date();
		newItem.id = d.getTime() + Math.random();
		dataItem.id = newItem.id;
		dataItem.order = data.length;
		if (dataItem.order % 2 != 0) JSKitLib.addClass(newItem, "js-topRowColor2");
		data.push(dataItem);
		self.itemHandler(newItem, admin, data, dataItem);
		self.init_vs_moved(newItem, data, dataItem);
		self.jsvs.itemSortable(newItem, true);

		if (data.length == 1) newItem.style.cursor = "default";
		if (data.length == 2) self.jsvs.itemSortable(items.firstChild, true);

		items.appendChild(newItem);
	}
}

JSEPW.prototype.tmpl = function(t, obj) {
	var self = this;
	t = self.gtmpl(t);
	var purify = function(text, m) {
		var text = String(text).replace(/^[ \s]+|[ \s]+$/, '');
		text = text.replace(/&/g,"&amp;");
		text = text.replace(/</g,"&lt;").replace(/>/g,"&gt;");
		text = text.replace(/"/g,"&#34;");
		if(m != 'Link') {
			var wbstr = JSKitLib.getBrowser()=='gecko' ? '<wbr>' : '&shy;';
			text = text.replace(/([^&<>]{6})([^&<>]{6})/g, "$1"+wbstr+"$2");
		}
		text = text.replace(/[ \t\r\n]+/g, ' ');
		return text;
	}
	t = t.replace(/{([A-Za-z0-9]+)}/g,function(a,m){var lm = m.toLowerCase(); return obj.hasOwnProperty(lm)?purify(obj[lm], m):'{'+m+'}';});
	return t;
}

JSEPW.prototype.gtmpl = function(t) {
	var lowercase = function(a, m) { return String(m).toLowerCase(); }
	t = t.replace(/^[^<]*(<.*>)[^>]*$/m, "$1");
	t = t.replace(/(<[\/]?[A-Z]+)/g, lowercase);
	t = t.replace(/{Label:([^}]*)}/g,function(a,m){return $JTL(m);});
	return t;
}

JSTC.prototype.assignTop = function(items,upperRange,top){
	if (top < upperRange) items.style.top = upperRange + "px";
	else if (top > 0 ) items.style.top = 0 + "px";
        	else items.style.top = top + "px";
}

JSTC.prototype.addClip = function(subWid){
	if(!subWid || !subWid.offsetTop) return;
	// Prevent scrollbars from showing when un-clipped content is large
	JSKitLib.addStyle(subWid, "position: relative; overflow: hidden");
	var buf = subWid.firstChild;
	var items = buf.firstChild;
	var count = parseInt(this.config.get('count')) || 10;
	if(items.childNodes[count]){
		items.style.cursor = (count <= items.childNodes.length) ? "move" : "default";
		var h = items.childNodes[count].offsetTop - items.firstChild.offsetTop;
		if (!h) return;
		subWid.style.height = h + "px";
		buf.style.cssText = "position: absolute; clip: rect(0px auto "+ h +"px auto); width:"+ subWid.offsetWidth +"px";}
}

JSTC.prototype.iPhoneScroll = function(subWid){
	var self = this;
	var upperRange,iter,offset;
	var buf = subWid.firstChild;
	var items = buf.firstChild;

	items.onmousedown = function(event){	
                if(self.decay){ 
			clearInterval(self.decay);
	                delete self.decay;
		}
		offset = 0;
		event = event || window.event;
        	self.offsetY = (event.clientY || event.pageY)-items.offsetTop;
		var topDown = items.offsetTop;
		upperRange = subWid.offsetHeight-items.offsetHeight
		JSKitLib.addHandlers(document,moveHandler,upHandler,false);

		function LinSmooth(dy,S){ return dy*0.8 + S*0.2 }
        	function moveHandler(ev) {
                	ev = ev || window.event;
			var top = (ev.clientY || ev.pageY) - self.offsetY;
			var prevTop = items.offsetTop;
			self.assignTop(items,upperRange,top);
			var dy = items.offsetTop-prevTop;
			offset = LinSmooth(dy,offset);
			JSKitLib.stopEventPropagation(ev);
        	}

        	function upHandler(ev) {
			JSKitLib.removeHandlers(document,moveHandler,upHandler,false);
			iter = 0;
			var topUp = items.offsetTop;

			if(!(topDown-topUp)) return;
			var sign = (offset<0) ? -1 : 1;
			
			var drift = function(speed){
                                speed = speed || 1;
                                var offset = Math.round(speed*7);
				var h = (offset > 0) ? 0 : subWid.offsetHeight;
                                for(var i = 0; i < items.childNodes.length;i++){
                                        var shift = items.childNodes[i].offsetTop+items.offsetTop + offset - h;
                                        if(shift >= 0){
                                                i=(sign<0) ? i : ((!i) ? 0 : i-1);
                                                var height = items.childNodes[i].offsetHeight;
                                                break;}
					if(shift<0 && i==items.childNodes.length-1) shift = items.lastChild.offsetHeight;
                                }
                                return offset + ((sign<0) ? shift*=sign : height - shift);
                        }	

			var slowDown = function(offset){
				var step = 0, iter = 0, arr = [], sum = 0, devider;
				if(offset<30) divider = Math.ceil(offset/2);	
				else if(offset<150) divider = Math.ceil(offset/6);
				else divider = Math.ceil(offset/17);
				while ((Math.round(offset/divider) > step) && (sum < offset)){
					step = Math.round(Math.exp(0.2*iter));
					arr.push(step);
					sum+=step;
					iter++;
				}
				var count = Math.floor((offset-sum)/step);
				for (var i=0;i<count;i++) arr.push(step), sum+=step;
				arr.push(offset-sum);
				arr.sort(function(x,y){if (x<y) return 1; else return (x==y) ? 0 : -1});
				return arr;
			}
			var arr = slowDown(Math.abs(drift(offset)));
		var iter = 0;
		self.decay = setInterval(function(){
                        self.assignTop(items,upperRange, items.offsetTop + sign*arr[iter]);
        		iter++;
			if(iter >= arr.length){ 
                		clearInterval(self.decay);
	               		delete self.decay;}
	    	},50);
			JSKitLib.stopEventPropagation(ev);
        	}
	}
}

JSTC.prototype.prepareData = function(data, config){
        var navData = {};
        navData.data = data.data;
        navData.recentComments = data.recentComments;

        // Process Config
        this.processConfig(config);

        navData.part = {
                CR: {},
                EP: {},
                TR: {},
                TS: {},
                HH: {},
                HD: {},
                HW: {},
                HT: {}  // Composite of HH, HD, HW
        };

        this.processDataTop(navData);
        this.processDataTopScore(navData);
        this.processDataHot(navData);
        this.processDataEP(navData);
        this.processDataCR(navData);
	return navData;
}

// This must be the last function.
JSTC.prototype.newData = function(data, opts) {
	var self = this;
	opts = opts || {};
	this.serverData = [ data, opts ]; // Saving what was returned by server.  
	this.config.server = data.config || {};
	this.serverTime = opts.serverTime;
	this.isAdmin = opts.admin || false;
	this.isNewSite = opts.newSite || false;
	var navData = this.prepareData(data, this.config.server);

	// Now parse template and attach node
	JSKitLib.deferCall(function(){ self.displayTop(navData, opts); }, true);
}

