                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
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-2009 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.
 * $Id: polls.js 24122 2010-05-27 15:04:51Z jskit $
 * $Date: 2010-05-27 08:04:51 -0700 (Thu, 27 May 2010) $
 */

if (!window.pollsWidgetsList) {
  pollsWidgetsList = [];
  $J$PLT = {
	saveChanges : 'Save',
	cancel : 'Cancel',
	viewResults : 'View results',
	addSection : 'Add another question',
	addAnswer : 'Add another answer',
	multipleAnswers : 'Multiple choices',
	help : 'Help',
	submit : 'Submit',
	reVote : 'Edit my vote',
	loading : 'Data is loading. Please wait ...',
	removeItem : 'remove',
	removeSection : 'Remove question',
	backToVoteForm : 'Back to voting',
	backToDesignMode : 'Back to question configuration',
	removeSectionConfirm : 'Do you want to delete this question?',
	noOptionSelectedStart : 'Please answer to',
	noOptionSelectedEnd : 'as well.',
	thanksForVote : 'You already voted',
	tooLong : 'Option label is too long (300 bytes max)',
	configurePoll : 'Configure poll',
	userItemsListHeader : 'User defined answers list',
	closeConfigurationPanel : 'Close configuration panel',
	savePollConfirm : 'Save changes and launch the poll?\nPlease note, all votes will be reset.',
	pollsAdminConsoleTitle : 'JS-Kit Poll Admin Console',
	resultColor : 'Results bar color ',
	cancelPollChangesConfirm : 'Do you want to cancel all changes and close configuration panel?',
	defaultUserItemText : 'Other',
	unableToDeleteLastSection : 'At least one question must be present in a poll, could not delete the last question.',
	allowRevoting : 'Allow to edit vote',
	freeFormAnswers : 'Free form answer',
	closeResultsForm : 'Configure poll',
	openResultsForm : 'Open results form',
	openUserItemsList : 'Show answers',
	closeUserItemsList : 'Hide answers',
	specifyYourChoice : 'Please specify your choice: ',
	allSectionsVoted : "Thank you for your vote!",
	pollClosed : "Poll is closed",
	itemTitleIPE : "Answer title (click to edit)",
	sectionTitleIPE : "Question title (click to edit)",
	sectionDescIPE : "Question description (click to edit). Leave empty for no description",
	pollTitleIPE : "Poll title (click to edit)",
	pollDescIPE : "Poll description (click to edit). Leave empty for no description",
	freeFormItemNotice : '(it\'s a free form item, users will be able to specify their own choice and input it into the text field)'
  };
  $J$PL = window.JSPC_Translate || function(t) { return $J$PLT[t] || t; }
}



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





JSKitLib.cr = function(arg) {
	if(!arg) return document.createElement("div");
	arg.t = arg.t || "div";
	var div = document.createElement(arg.t);
	if(arg.className) div.className = arg.className;
	if(arg.style) JSKitLib.addStyle(div, arg.style);
	return div;
}

JSKitLib.deleteProperty = function(obj, prop) {
	if (typeof obj[prop] == 'function') {
		obj[prop] = null;
	} else {
		try {
			delete obj[prop];
		} catch (e) {
			obj[prop] = null;
		}
	}
}

JSKitLib.trim = function(str) {
	if (typeof(str) != "string") return "";
	var str = str.replace(/^\s\s*/, ''), ws = /\s/, i = str.length;
	while (ws.test(str.charAt(--i)));
	return str.slice(0, i + 1);
}

JSKitLib.truncate = function(text, maxLength, postfix, cutWords) {
        if (text.length <= maxLength) return text;
        var match = text.match(new RegExp("^.{1," + maxLength + "}\\b"));
        return ((match && !cutWords ? match[0] : false) || text.substr(0, maxLength)) + (postfix || "");
}

JSKitLib.extractDomain = function(url) {
	var match = url.match(/(https?:\/\/)?(www.)?([^\/]*)/);
	return match ? match[3] : url;
}

JSKitLib.encodeJSONLiteral = function(string) {
	var replacements = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
	return string.replace(/[\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff\\]/g, 
		function (a) { return (replacements.hasOwnProperty(a)) ? replacements[a] : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); });
}

JSKitLib.Object2JSON = function(obj) {
	var out;
	switch (typeof(obj)) {
		case "number"  : out = isFinite(obj) ? obj : 'null'; break; 
		case "string"  : out = '"' + JSKitLib.encodeJSONLiteral(obj) + '"'; break;	
		case "boolean" : out = '"' + obj.toString() + '"'; break;
		default :
			if (obj instanceof Array) {
				var container = JSKitLib.fmap(obj, function(element) { return JSKitLib.Object2JSON(element); });
				out = '[' + container.join(",") + ']';
			} else if(obj instanceof Object) {
				var source = obj.exportProperties || obj;
				var container = JSKitLib.fmap(source, function(value, property) {
					if (source instanceof Array) { property = value; value = obj[property]; } 
					return '"' + property + '":' + JSKitLib.Object2JSON(value);
				});
	      			out = '{' + container.join(",") + '}';
			} else {
				out = 'null';
			}
	}
	return out;
}

JSKitLib.appendExternalParams = function(service, requestType, currentParams) {
	if (!window.JSKitExternalParams) return currentParams;
	JSKitLib.fmap(window.JSKitExternalParams, function(data) {
		var serviceRegExp = new RegExp(data.service || "*");
		var requestTypeRegExp = new RegExp(data.requestType || "*");
		if (serviceRegExp.test(service) && requestTypeRegExp.test(requestType)) {
			JSKitLib.fmap(data.params, function(value, key) { currentParams[key] = value; });
		}
	});
	return currentParams;
}





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 JSKbdHandler(element, events) {

	this.kbdCallback = function(e) {
		var event = e || window.event;
		var key = event.charCode || event.keyCode;
		if (key == 9 || key == 13 || key == 27) JSKitLib.preventDefaultEvent(event);
		if(JSKitLib.isSafari()) JSKitLib.stopEventPropagation(event);
		for(var i = 0; i < events.length; i++) {
			for(var j = 0; j < events[i].keys.length; j++) {
				if(typeof(events[i].keys[j]) == "string") events[i].keys[j] = String.charCodeAt(events[i].keys[j]);
				var shiftCondition = (events[i].shift != undefined) ? events[i].shift == event.shiftKey : true; 
				if (events[i].keys[j] == key && shiftCondition) {
					if(!events[i].args)
						(events[i].action)();
					else
						events[i].action.apply(events[i], events[i].args);
				}
			}
		}
	}

	if(element.addEventListener) {
		if(JSKitLib.isSafari()) element.addEventListener("keydown", this.kbdCallback, false);
		else if(JSKitLib.isOpera()) element.addEventListener("keydown", this.kbdCallback, false);
		else element.addEventListener("keypress", this.kbdCallback, false);
	} else {
		element.onkeydown = this.kbdCallback;
	}
}





function JSIPE2(obj) {
/* 
	JSIPE2 API

	obj:		object contains property
	title: 		hint
	defaultText:	default text in created div
	property:	property where save the result
	maxLength:	max string length
	width: 		input width
	jsk$validate	callback, validates the value before applying
	jsk$wasEdited	callback, called at the end of editing 
	readonly:	readonly mode
	
	example: 
	var jsipe = new JSIPE2({obj: elem,
				property: 'descr',
				title: 'Description',
				defaultText: 'Add caption',
				width: '90px',
				maxLength: 12,
				jsk$wasEdited: function(){...},
				readonly: true
	});

*/

	for(var i in obj)
		this[i] = obj[i];
	var div = JSKitLib.cr();
	div.title = this.readonly ? "" : (this.title || $JCL("clickToEdit"));
	var defaultText = this.readonly ? "" : (this.defaultText || $JCL("clickToEditEmpty"));
	var maxTextLength = this.maxLength || 256;
	var isFocused = false;

	var self = this;

	var textDivDisplayCSS = typeof(self.textModeDisplayCSS) != "undefined" ? self.textModeDisplayCSS : "inline";
	var textDiv = JSKitLib.cr({style:{display:textDivDisplayCSS}});
	var textValue = (JSKitLib.trim(self.obj[self.property]).length > 0) ? self.obj[self.property] : defaultText;
	var text = JSKitLib.text(textValue);
	textDiv.appendChild(text);
	div.appendChild(textDiv);

	var editDiv = JSKitLib.cr();
	editDiv.style.display = "none";
	div.appendChild(editDiv);
	var edit = JSKitLib.cr({t:"input", type:"edit", className:"jsipe-input",
		style: "width: " + (self.width || "150px"), readonly: this.readonly});
	edit.value = this.obj[this.property] || "";
	editDiv.appendChild(edit);

	if (!this.hideApplyBtn) {
		var applyDiv = JSKitLib.cr();
		JSKitLib.addClass(applyDiv, "jsipe-applyButton");
		applyDiv.title = "Apply";
		JSKitLib.addPNG(applyDiv, "//js-kit.com/images/tick.png");
		editDiv.appendChild(applyDiv);
	}

	this.div = div;

	if (this.readonly) return;

	textDiv.onmouseover = function() { JSKitLib.addClass(textDiv, "jsipe-onmouseover"); }
	textDiv.onmouseout  = function() { JSKitLib.removeClass(textDiv, "jsipe-onmouseover"); }

	this.displayMode = function() {
		JSKitLib.show(textDiv, textDivDisplayCSS);
		JSKitLib.hide(editDiv);
		textDiv.removeChild(text);
		text = JSKitLib.text(self.obj[self.property] || defaultText);
		textDiv.appendChild(text);
	}

	this.editMode = function(e) {
		if(!self.editModeEventEnabled) JSKitLib.stopEventPropagation(e);
		JSKitLib.hide(textDiv);
		JSKitLib.show(editDiv, "inline");
		edit.focus();
		edit.select();
	}

	var applyChanges = function() {
		if(typeof self.jsk$validate == "function" && !self.jsk$validate(edit.value)) return;
		if(edit.value == self.obj[self.property]) { self.displayMode(); return;}
		if(edit.value.length > maxTextLength) {
			alert("The text you entered cannot exceed "+ maxTextLength +" symbols");
			resetChanges();
			return;
		}
		self.obj[self.property] = edit.value = JSKitLib.trim(edit.value);
		if(isFocused) edit.blur();
		self.displayMode();
		if(self.jsk$wasEdited) self.jsk$wasEdited();
	}

	this.resetChanges = function() {
		edit.value = self.obj[self.property];
		if(isFocused) edit.blur();
		self.displayMode();
	}

	var jumpNextSibling = function() {
		if(isFocused) edit.blur();
		if(self.nextSib)
			self.nextSib.editMode();
	}

	var jumpPrevSibling = function() {
		if(isFocused) edit.blur();
		if(self.prevSib)
			self.prevSib.editMode();
	}

	if(this.dblclick)
		textDiv.ondblclick = this.editMode;
	else
		textDiv.onclick = this.editMode;
	edit.onblur = function() { applyChanges(); isFocused = false; };
	edit.onfocus = function() { isFocused = true; };
	edit.onclick = function(e) { JSKitLib.stopEventPropagation(e); }
	if (!this.hideApplyBtn) applyDiv.onmousedown = applyChanges;

	new JSKbdHandler(edit, [
					{action:applyChanges, keys:[10,13]}
					,{action:this.resetChanges, keys:[27]}
					,{action:jumpNextSibling, keys:[9], shift:false}
					,{action:jumpPrevSibling, keys:[9], shift:true}
					]);
}

JSIPE2.prototype.addNextSibling = function(next) {
	if (next) {
		this.nextSib = next;
		next.prevSib = this;
	}
}





if(!window.JSKitEPB){
	var JSKitEPB = new JSKitEPBLib();
}

function JSKitEPBLib() {
	this.JSK$EPB = window.JSK$EPB ? window.JSK$EPB : {};
}

JSKitEPBLib.prototype.isExists = function() {
	return (this.JSK$EPB.mac && this.JSK$EPB.profile) ? 1: 0;
}

JSKitEPBLib.prototype.getValue = function(ValueName) {
	return !this.isExists() || this.JSK$EPB.profile[ValueName] == undefined ? undefined : this.JSK$EPB.profile[ValueName];
}

JSKitEPBLib.prototype.getElement = function(Pref,El,ArrKey) {
	var rslt = [];
	if(typeof(El) == 'object') {
		if(El instanceof Array) {
			if(ArrKey) {
				var len = El.length;
				for(var i=0; i<len; i++)
					rslt = rslt.concat(this.getElement(Pref,El[i],ArrKey));
			}
		} else {
			for(var i in El)
				rslt = rslt.concat(this.getElement(Pref,El[i],i));
		}
	} else {
		if(ArrKey) {
			rslt.push({'Name': Pref+ArrKey, 'Value': El});
		}
	}
	return rslt;
}

JSKitEPBLib.prototype.getAsObj = function() {
	var rslt = [];
	var pref = "epb-";
	var epb = this.JSK$EPB;
	if(!epb.profile || !epb.mac) return rslt;
	rslt.push({'Name': pref+"mac",'Value': epb.mac});
	return rslt.concat(this.getElement(pref,epb.profile));
}

JSKitEPBLib.prototype.getURIEncodedSerialize = function() {
	var ser = this.getAsObj();
	var ar = [];
	for(var i=0; i<ser.length; i++) {
		ar.push(ser[i].Name + "=" + encodeURIComponent(ser[i].Value));
	}
	return ar.join("&");
}

JSKitEPBLib.prototype.getAsHash = function(obj) {
	var ser = this.getAsObj();
	obj = obj || {};
	JSKitLib.fmap(ser, function(v) { obj[v.Name] = v.Value; });
	return obj;
}





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





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





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





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





//////////////////// JSRVC
// requestObj
// request: {uri: someuri, param1: val1, param2: val2, ...}
// [transport: ("GET" | "POST")]
// [target: some_DOM_element]
// [variableRequest: [{param1_1: val1_1, param1_2: val1_2, ...},
//			{param2_1: val2_1, param2_2: val2_2,...}, ...]]
// [form: some_form]
// [onreturn: some_callback]
// [randevu : (true | false)]
// [requestId: some request identity]
// [trailer: specifies the name of parameter which should terminate
//						each sub-request of multi-request]

function JSRVC(requestObj) {
	var s = this;
	s.requestId = requestObj.requestId || s.generateRequestId();
	s.requestsInProgress = 0;
	s.requestsQueue = [];
	s.trailer = requestObj.trailer;
	s.processRequest(requestObj);
}

JSRVC.prototype.generateRequestId = function() {
	return ((new Date()).valueOf() + Math.random()).toString();
}

JSRVC.prototype.processRequest = function(requestObj) {
	var s = this;
	s.error = undefined;
	if(s.requestsInProgress) {
		s.requestsQueue.push(requestObj);
		return;
	}
	s.requestObj = requestObj;
	if(s.requestObj.pickup && !s.eventCtx) s.eventCtx = JSKW$Events.registerEventCallback(s.eventCtx, function() {s.eventCallback.apply(s, arguments);}, "randevu_answer");
	var req = s.requestObj;
	s.preProcessRequest();
	if(!req.transport)
		req.transport = req.form ? "POST" : s.getRequestTransport();
	req.target = req.target || document.body;
	var onCompleteCB = req.timeout ? function() {
		s.startTimeoutTimer.call(s);
	} : undefined;
	var handlers = {'onload': s.onLoadRequest, 'onreadystatechange': s.onLoadRequest};
	switch(req.transport) {
	case "GET":
		s.processGETRequest(onCompleteCB, handlers);
		break;
	case "POST":
		s.processPOSTRequest(onCompleteCB, handlers);
		break;
	}
}

JSRVC.prototype.preProcessRequest = function() {
	var req = this.requestObj;
	if(!req.request) req.request = {};
	JSKitLib.fmap(req.epb || {}, function(v, k) { req.request[k] = v; });
	if (req.ref) req.request.ref = req.ref;
	req.request.randevuId = this.requestId;
	if(!req.variableRequest) req.variableRequest = [];
	if(req.pickup) req.request.randevuRnd = Math.random();
}

JSRVC.prototype.calcGetRequest = function() {
	var s = this;
	var req = s.requestObj;
	var reqvar = req.variableRequest;
	var permGETReq = s.serializeRequest(req.request);
	var varGETReq = JSKitLib.fmap(reqvar, function(el, idx){
		return s.serializeRequest(el, '[' + idx + ']');
	});
	return [permGETReq, varGETReq];
}

JSRVC.prototype.getRequestTransport = function() {
	var ser = this.calcGetRequest();
	var permReq = ser[0];
	var varReq = ser[1];
	var firstReqLen = permReq.length +
		(varReq.length>0 ? varReq[0].length : 0);
	var totalReqLen = 0;
	for(var i=0; i<varReq.length; i++)
		totalReqLen += varReq[i].length;
	
	return ((firstReqLen > 1700) || (totalReqLen > 3400) ?
		"POST" : "GET");
}

JSRVC.prototype.startTimeoutTimer = function() {
	var s = this;
	if(s.timeoutTimer) clearTimeout(s.timeoutTimer);
	s.timeoutTimer = setTimeout(function() { s.timeoutExpired(); }, s.requestObj.timeout);
}

JSRVC.prototype.timeoutExpired = function() {
	this.timeoutTimer = undefined;
	this.error = "timeout";
	this.returnAnswer();
}

JSRVC.prototype.returnAnswer = function(answerData) {
	var s = this;
	answerData = answerData || {};
	if(answerData.script) {
		var script = document.createElement('script');
		script.text = answerData.script;
		this.requestObj.target.appendChild(script);
	}
	if(s.requestObj.onreturn) {
		s.requestObj.onreturn.call(s, s.error || "data", answerData.data);
	}
}

JSRVC.prototype.serializeRequest = function(obj, prefix) {
	var s = this;
	var toString = function(k, v) {
		return encodeURIComponent(k) + (prefix || '') + "=" + encodeURIComponent(v);
	};
	var request = JSKitLib.fmap(obj, function(v, k) {
		if (s.trailer != k) return toString(k, v);
	});
	if (s.trailer && typeof(obj[s.trailer]) != "undefined") {
		request.push(toString(s.trailer, obj[s.trailer]));
	}
	return request.join("&");
}

JSRVC.prototype.setElementAttributes = function(obj, attrs) {
	var s = this;
	if (!obj) return;
	JSKitLib.fmap(attrs, function(v, k) {
		obj[k] = function() { v.call(s, obj) };
	});
}

JSRVC.prototype.runScript = function(src, data, handlers) {
	var script = document.createElement('script');
	this.setElementAttributes(script, handlers);
	script.setAttribute("charset", "utf-8");
	script.setAttribute("src",  src + (data ? '?' + data : ''));
	this.requestsInProgress++;
	this.requestObj.target.appendChild(script);
	this.script = script;
}

JSRVC.prototype.processGETRequest = function(onCompleteCB, handlers) {
	var s = this;
	var ser = s.calcGetRequest();
	var reqperm = ser[0];
	var reqpermlen = reqperm.length;
	var reqvar = ser[1];
	var reqvarlen = reqvar.length;
	var currequest = '';
	for(var i=0; i<reqvarlen; i++) {
		currequest += '&' + reqvar[i];
		if(currequest.length + reqpermlen +
			(i+1<reqvarlen ? reqvar[i+1].length : 0) > 2000) {
			s.runScript(s.requestObj.uri,
				reqperm + currequest, handlers);
			currequest = '';
		}
	}
	if((currequest) || (!reqvarlen))
		s.runScript(s.requestObj.uri,
			reqperm + '&' + currequest, handlers);
	if(onCompleteCB) onCompleteCB();
}

JSRVC.prototype.processPOSTRequest = function(onCompleteCB, handlers) {
	var s = this;
	var req = s.requestObj.request;
	var reqvar = s.requestObj.variableRequest;
	var reqvarlen = s.requestObj.variableRequest.length;
	var createForm = function() {
		var iframe = 'js-ifrm-' + Math.random();
		var ifr = JSKitLib.createHiddenIframe(iframe, s.requestObj.target);
		var doc = ifr.contentDocument ? ifr.contentDocument : ifr.document;
		var f = doc.createElement('FORM');
		f.doc = doc;
		if(JSKitLib.isIE()) doc.charset = "utf-8";
		f.target = iframe;
		JSKitLib.timedRetry({
				timeout: 100,
				maxRetries: 50,
				onSuccess: function() {
						doc.body.appendChild(f); },
				pred: function() { return !!doc.body; }
			});
		return f;
	};
	var getForm = function() {
		return (s.requestObj.form && !reqvarlen) ?
			s.requestObj.form : createForm();
	}
	var fillForm = function(form, obj) {
		form.method  = 'POST';
		form.enctype = "application/x-www-form-urlencoded";
		form.acceptCharset = 'UTF-8';
		form.action  = s.requestObj.uri;
		JSKitLib.fmap(obj, function(v, k) {
			var frmel = (form.doc || document).createElement('INPUT');
			frmel.type = "hidden";
			frmel.name = k;
			frmel.value = v;
			form.appendChild(frmel);
		});
	}
	var postRequest = function(pobj, vobj) {
		var form = getForm();
		fillForm(form, pobj);
		if(vobj) fillForm(form, vobj);
		if (form.target) s.setElementAttributes(document.getElementById(form.target), handlers);
		JSKitLib.fmap(handlers, function(v, k) {
			form[k] = v;
		});
		s.requestsInProgress++;
		JSKitLib.timedRetry({
				timeout: 100,
				maxRetries: 50,
				onSuccess: function() {
						form.submit(); },
				pred: function() {
					return (form.parentNode &&
						form.parentNode.nodeType!=11); }
			});
	}
	JSKitLib.fmap(reqvar, function(v) {
		postRequest(req, v);
	});
	if(!reqvarlen) postRequest(req);
	if(onCompleteCB) onCompleteCB();
}

JSRVC.prototype.onLoadRequest = function(el) {
	var s = this;
	if(el.readyState && el.readyState != 'loaded'
		&& el.readyState != 'complete') return;
	el.onreadystatechange = el.onload = null;
	if(!s.requestObj.pickup) {
		s.requestObj.checked = true;
		s.requestsInProgress--;
	}
	s.postProcessRequest();
}

JSRVC.prototype.postProcessRequest = function(source, data) {
	var s = this;
	if(s.requestObj.pickup && source!="pickup") return;
	if(s.requestObj.randevu && !s.error && s.requestObj.transport == "POST") {
		s.processRequest({
			'uri': '//js-kit.com/api/server-answer.js',
			'ref': s.requestObj.ref,
			'epb': s.requestObj.epb,
			'pickup': true,
			'onreturn': s.requestObj.onreturn,
			'target': s.requestObj.target});
		return;
	}
	s.returnAnswer(data);
	if(!s.requestsInProgress) {
		if(s.timeoutTimer) {
			clearTimeout(s.timeoutTimer);
			s.timeoutTimer = undefined;
		}
		if(s.requestsQueue.length && !s.error)
			s.processRequest(s.requestsQueue.pop());
	}
}

JSRVC.prototype.eventCallback = function(eventName, randevuId, status, data) {
	if(this.requestId != randevuId) return;
	this.requestsInProgress--;
	if(this.script && this.script.parentNode) {
		this.script.parentNode.removeChild(this.script);
		this.script = undefined;
	}
	switch(status) {
	case "ready":
		if(this.eventCtx) {
			JSKW$Events.invalidateContext(this.eventCtx);
			this.eventCtx = undefined;
		}
		this.postProcessRequest("pickup", data);
		break;
	case "timeout":
		if(this.error) {
			this.returnAnswer(data);
		} else {
			this.processRequest(this.requestObj);
		}
		break;
	}
}

JSRVC.prototype.cancelRequest = function() {
	this.error = 'canceled';
}



function JSPollBaseModel() {}

JSPollBaseModel.prototype.setProperties = function(properties) {
	JSKitLib.fmap.call(this, this.properties, function(key) { this[key] = properties[key]; });
}

JSPollBaseModel.prototype.generateID = function() {
	return new Date().valueOf();
}

JSPollBaseModel.prototype.toBoolean = function(propertiesList) {
	JSKitLib.fmap.call(this, propertiesList, function(property) { this[property] = (this[property] == "true") ? true : false; });
}

JSPollBaseModel.prototype.getLabelText = function(label) {
	return $J$PL(label);
}

JSPollBaseModel.prototype.render = function() {
	var currentDOM = this.dom;
	var newDOM = this.toDOM();
	if (currentDOM) currentDOM.parentNode.replaceChild(newDOM, currentDOM);
	this.dom = newDOM;
	return newDOM;
}

JSPollBaseModel.prototype.gtmpl = function(t, mObj) {
	var lowercase = function(a, m) { return String(m).toLowerCase(); }
	t = t.replace(/^[^<]*(<.*>)[^>]*$/m, "$1");
	t = t.replace(/(<[\/]?[A-Z]+)/g, lowercase);
	if(mObj && mObj.ID) t = t.replace(/(<[a-z]+)/, '$1 id="' + mObj.ID + '"');
	var self = this;
	t = t.replace(/{Label:([^:}]+[^}]*)}/g,function(a,m){return self.getLabelText(m);});
	return t;
}

JSPollBaseModel.prototype.isDesignMode = function() {
	return (this.config.isAdmin && this.config.designMode);
}

JSPollBaseModel.prototype.toDOMtitle = function() {
	if (this.isDesignMode() && !this.config.disableIPE) {
		this.jsipe_title = new JSIPE2({obj:this, property:"title", title:this.titlesIPE.title, width:this.config.widthIPE});
		return this.jsipe_title.div;
	}
	var container = document.createElement("DIV");
	return container.appendChild(document.createTextNode(this.title));
}

JSPollBaseModel.prototype.toDOMdescription = function() {
	if (this.isDesignMode() && !this.config.disableIPE) {
		this.jsipe_description = new JSIPE2({obj:this, property:"description", title:this.titlesIPE.description, width:this.config.widthIPE});
		return this.jsipe_description.div;
	}
	var container = document.createElement("DIV");
	return container.appendChild(document.createTextNode(this.description));
}

JSPollBaseModel.prototype.getTemplate = function() {
	return this.template;
}

JSPollBaseModel.prototype.parseTemplate = function(template) {
	var content = JSKitLib.html(this.gtmpl(template));
	var components = JSKitLib.mapClass2Object({}, content);
	return {content: content, components: components};
}

JSPollBaseModel.prototype.toDOM = function() {
	var parsedData = this.parseTemplate(this.getTemplate());
	var components = parsedData.components;
	this.dom = parsedData.content;
	for (var identifier in components) {
		var pattern = identifier.match("js-poll-(.*)");
		var element2Call = (pattern) ? "toDOM"+pattern[1] : null;
		if (element2Call && typeof(this[element2Call]) == "function") {
			var node = this[element2Call].call(this, components[identifier]);	
			if (node != null) components[identifier].appendChild(node);
		}
	}
	return parsedData.content;
}

JSPollBaseModel.prototype.getIndexByID = function(elementsArray, id) {
	for (var i = 0; i < elementsArray.length; i++) {
		if (elementsArray[i].id == id) return i;	
	}	
	return null;
}

JSPollBaseModel.prototype.buildControlButton = function(prefix, components, onClickAction, imageURL) {
	var prefix = "js-poll" + prefix;
	JSKitLib.preventSelect(components[prefix+"Label"]);
	JSKitLib.addPNG(components[prefix+"Img"], imageURL);
	JSKitLib.fmap(["Img", "Label"], function(name) { components[prefix+name].onclick = onClickAction; });
}

/*
 *  Polls items constructor
 */
function JSPollItem(itemData, config, parentSection) {
	this.properties = ["id", "title", "extra", "votes", "itemType"];
	// export fields
	this.exportProperties = ["id", "title", "itemType", "votes"]; // itemType = "default" / "free_form" / "user_defined"
	this.setProperties(itemData);
	this.config = config;
	this.parentSection = parentSection;
	this.titlesIPE = {"title": this.getLabelText("itemTitleIPE")};
}

JSPollItem.prototype = new JSPollBaseModel();

JSPollItem.prototype.template 
= '<div class="js-pollItemContainer js-pollItem js-pollItemControl">'
 + '<div class="js-poll-selector js-pollItemSelectorWrap"></div>'
 + '<div class="js-poll-title js-pollItemText"></div>'
 + '<div class="js-poll-removeItem">[<a class="js-pollItemDelA" href="javascript:void(0);">{Label:removeItem}</a>]</div>'
 + '<div class="js-poll-clear"></div>'
+ '</div>';

JSPollItem.prototype.sectionVotedItemTemplate
= '<div class="js-pollItemVotedContainer js-pollItemDisplay">'
+ '<div class="js-poll-votedItemText js-pollItemText"></div>'
 + '<div class="js-poll-userDefinedListSwitch"></div>'
 + '<div class="js-poll-votedItemData"></div>'
 + '<div class="js-poll-votedItemBar js-pollItemDV"></div>'
 + '<div class="js-poll-userDefinedItemsList"></div>'
+ '</div>';

JSPollItem.prototype.userDefinedListSwitch 
= '<div class="js-pollUserDefinedListSwitch">(<a class="js-pollUserDefinedListSwitchA" href="javascript:void(0);"></a>)</div>';

JSPollItem.prototype.userDefinedItemTemplate
= '<div class="js-pollItemContainer js-pollItem js-pollItemControl">'
 + '<div class="js-poll-selector"></div>'
 + '<div class="js-poll-title js-pollItemText"></div>'
 + '<div class="js-poll-userDefinedItem"></div>'
+ '</div>';

JSPollItem.prototype.userDefinedItemDetails
= '<div class="js-pollUserItemInputDiv">'
 + '{Label:specifyYourChoice}<input type="text" name="js-pollUserItemInput" class="js-pollUserItemInput" maxlength="100">'
+ '</div>';

JSPollItem.prototype.getTemplate = function() {
	if (this.parentSection.inShowResultsMode()) return this.sectionVotedItemTemplate;
	if (this.itemType == "free_form") return this.userDefinedItemTemplate;
	return this.template;
}

JSPollItem.prototype.isVisible = function() {
	if ((this.itemType == "default") || (this.itemType == "free_form" && this.parentSection.freeForm)) return true;
	return false;
}

JSPollItem.prototype.countUserDefinedAnswers = function() {
	var count = 0;
	JSKitLib.fmap(this.parentSection.items, function(item) { if (item.itemType == "user_defined") count++; });
	return count;
}

JSPollItem.prototype.toDOMuserDefinedListSwitch = function(container) {
	if (this.itemType != "free_form" || !this.config.isAdmin || this.countUserDefinedAnswers() <= 0) container.style.display = "none";

	var parsedData = this.parseTemplate(this.userDefinedListSwitch);
	var components = parsedData.components;

	var self  = this;
	var label = (this.userItemsListOpened) ? "closeUserItemsList" : "openUserItemsList";
	components["js-pollUserDefinedListSwitchA"].appendChild(document.createTextNode(this.getLabelText(label)));
	components["js-pollUserDefinedListSwitchA"].onclick = function() {
		self.userItemsListOpened = !self.userItemsListOpened;
		self.render();
	}
	return parsedData.content;		
}

JSPollItem.prototype.toDOMuserDefinedItem = function(container) {
	if (this.isDesignMode()) {
		container.appendChild(document.createTextNode(this.getLabelText("freeFormItemNotice")));
		container.className = 'js-pollUserItemNotice';
		return null;
	}

	var parsedData = this.parseTemplate(this.userDefinedItemDetails);
	var components = parsedData.components;

	var self = this;

	var expandTextArea = function() {
	       	container.appendChild(parsedData.content);
       		self.userItemInputField = components["js-pollUserItemInput"];
		self.userItemInputField.value = self.parentSection.userItemText || "";
		self.parentSection.userDefinedItemContainer = container;
		self.parentSection.userDefinedItemContainer.style.display = "block";	
	}

	var collapseTextArea = function() { container.style.display = 'none'; }

	if (self.parentSection.parentPoll.allowRevote && self.parentSection.votes.length > 0) {
		JSKitLib.fmap(self.parentSection.votes, function(voteID) { if (voteID == self.id) expandTextArea(); } );
	}

	this.selector.onclick = function() { (this.checked) ? expandTextArea() : collapseTextArea(); }
	return null;
}

JSPollItem.prototype.toDOMuserDefinedItemsList = function(container) {
	if (this.itemType != "free_form" || !this.config.isAdmin) return null;

	var self = this;
	var containerDisplay = "none";

	if (this.userItemsListOpened) {
		var userItemCount = 0;	
		for (var i=0; i < this.parentSection.items.length; i++) {
			if (this.parentSection.items[i].itemType == "user_defined") {
				var item = document.createElement("DIV");
				item.className = "js-pollUserItemsListElement";
				item.appendChild(document.createTextNode("— " + this.parentSection.items[i].title));			
	       			container.appendChild(item);  
				userItemCount++;
			}
		}
		if (userItemCount > 0) containerDisplay = "block";
	} 
	container.style.display = containerDisplay;
	return null;
}

JSPollItem.prototype.toDOMvotedItemText = function() {
	return document.createTextNode(this.title);
}

JSPollItem.prototype.toDOMvotedItemData = function() {
	return document.createTextNode(this.percentage + "% (" + this.votes + ")");
}

JSPollItem.prototype.toDOMvotedItemBar = function() {
	var div = document.createElement("DIV");
	div.className = "js-pollItemDV";
	div.style.width = this.percentage ? this.percentage + '%' : '0px';
	this.parentSection.parentPoll.setBarColor(div);
	return div;
}

JSPollItem.prototype.toDOMselector = function(container) {
	var self = this;
	var name = "vote_" + this.parentSection.id; 
	var type = (this.parentSection.type == "single") ? "radio" : "checkbox";
	var disabled = false;
	var selected = false;

	if (this.isDesignMode()) { 
		disabled = true;
	} else {
		if (self.parentSection.parentPoll.allowRevote && self.parentSection.votes.length > 0) {
			JSKitLib.fmap(self.parentSection.votes, function(voteID) { if (voteID == self.id) { selected = true; } } );
		}
	}

	var selector;

	if (JSKitLib.isIE()) {
		var selectedProperty = (selected) ? " checked " : "";
		var disabledProperty = (disabled) ? " disabled " : ""; 
		selector = document.createElement('<input type="' + type + '" name="' + name + '"' + selectedProperty + disabledProperty + '>'); 
	} else {
		selector = document.createElement("INPUT");
		selector.type = type;
		selector.name = name;
		selector.disabled = disabled;
		selector.checked  = selected;
	}

	if (this.parentSection.type == "single") {
		selector.onclick = function() {
			if (self.itemType == "default" && self.parentSection.userDefinedItemContainer)	{
				self.parentSection.userDefinedItemContainer.style.display = "none";
			}
		}
	}

	this.selector = selector;
	container.appendChild(this.selector);
	return null;
}

JSPollItem.prototype.toDOMremoveItem = function(container) {
	if (!this.isDesignMode()) return null;	

	var self = this;

	container.onclick = function() {
		var index = self.getIndexByID(self.parentSection.items, self.id);
		self.parentSection.items.splice(index, 1);
		self.parentSection.render();
	}

	this.dom.removeItemButton = container;
	return null;
}

/*
 *  Poll section object constructor
 */
function JSPollSection(initSectionData, config, parentPoll) {
	this.properties = ["id", "title", "description", "votes", "userItemText", "extra", "type", "freeForm", "enabled"];

	// export fields
	this.exportProperties = ["id", "title", "description", "type", "freeForm", "items"];

	this.setProperties(initSectionData);
	this.toBoolean(["freeForm"]);

	this.voted  = (this.votes.length > 0) ? true : false;
	this.config = config; 
	this.items  = this.fromData(initSectionData.items);
	this.parentPoll = parentPoll;
	this.titlesIPE = {"title": this.getLabelText("sectionTitleIPE"), "description": this.getLabelText("sectionDescIPE")};
}

JSPollSection.prototype = new JSPollBaseModel();

JSPollSection.prototype.template 
= '<div class="js-pollSectionContainer">'
 + '<div class="js-poll-title"></div>'
 + '<div class="js-poll-description"></div>'
 + '<div class="js-poll-sectionItems js-pollItems"></div>'
 + '<div class="js-poll-sectionControls"></div>'
+ '</div>';

JSPollSection.prototype.controlsTemplate
= '<div class="js-pollSectionControls">'
   + '<div class="js-designModeControls">'
     + '<div class="js-pollSectionSettingL">' 
       + '<div class="js-pollAddOptionImg js-pollSectionCtrlImg"></div>'
       + '<div class="js-pollAddOptionLabel js-pollSectionCtrlLabel">{Label:addAnswer}</div>'
       + '<div class="js-poll-clear"></div>'
       + '<div class="js-pollRemoveSectionImg js-pollSectionCtrlImg"></div>'
       + '<div class="js-pollRemoveSectionLabel js-pollSectionCtrlLabel">{Label:removeSection}</div>'
       + '<div class="js-poll-clear"></div>'
     + '</div>'
     + '<div class="js-pollSectionSettingR">' 
       + '<div class="js-pollChangeSelectorImg js-pollSectionCtrlImg"></div>'
       + '<div class="js-pollChangeSelectorLabel js-pollSectionCtrlLabel">{Label:multipleAnswers}</div>'
       + '<div class="js-poll-clear"></div>'
       + '<div class="js-pollFreeFormSwitchImg js-pollSectionCtrlImg"></div>'
       + '<div class="js-pollFreeFormSwitchLabel js-pollSectionCtrlLabel">{Label:freeFormAnswers}</div>'
       + '<div class="js-poll-clear"></div>'
     + '</div>'
  + '<div class="js-poll-clear"></div>'
  + '</div>'
+ '</div>';

JSPollSection.prototype.sectionVotedTemplate
= '<div class="js-pollSectionContainer">'
 + '<div class="js-poll-title"></div>'
 + '<div class="js-poll-description"></div>'
 + '<div class="js-poll-sectionResults"></div>'
+ '</div>';

JSPollSection.prototype.inShowResultsMode = function() {
	if (this.parentPoll.showResultsToAdmin) return true;
	if (this.isDesignMode()) return false;
	return (this.parentPoll.showResults || this.voted || this.parentPoll.expired);
}

JSPollSection.prototype.getTemplate = function() {
	if (this.inShowResultsMode()) return this.sectionVotedTemplate;
	return this.template;
}

JSPollSection.prototype.fromData = function(itemsData) {
	return JSKitLib.fmap.call(this, itemsData, function(data) { 
		var item = new JSPollItem(data, this.config, this);
		if (item.itemType == "free_form") this.freeFormItem = item;
		return item;		
	});
}

JSPollSection.prototype.getVisibleItems = function() {
	var freeFormAnswer = null;
	var visibleItems = JSKitLib.fmap.call(this, this.items, function(item) {
		if (item.itemType == "free_form" && this.freeForm) freeFormAnswer = item;
		else if (item.isVisible()) return item;
	});
	if (freeFormAnswer) visibleItems.push(freeFormAnswer);
	return visibleItems;		
}

JSPollSection.prototype.clearUserAnswers = function() {
	var self = this;

	// clean up user defined items if necessary
	if (self.freeForm) return;
	self.userItemText = "";
	self.items = JSKitLib.filter(function(item) { if (item.itemType == "default") return true; return false; }, self.items); 
}

JSPollSection.prototype.resetVotes = function() {
	var self = this;
	JSKitLib.fmap(self.items, function(item) { item.votes = 0; });
}

JSPollSection.prototype.toDOMsectionItems = function(container) {
	var displayItems   = this.getVisibleItems();
	var minItemsAmount = (this.freeForm) ? 2 : 1;

	for (var i = 0; i < displayItems.length; i++) {
		container.appendChild(displayItems[i].toDOM());
		if (this.isDesignMode()) {
			if(displayItems[i-1]) displayItems[i-1].jsipe_title.addNextSibling(displayItems[i].jsipe_title);

			// Deleting is allowed when more then two items are avalable
			if(displayItems.length > minItemsAmount && displayItems[i].itemType == "default") {
				displayItems[i].dom.onmouseover = function() { this.removeItemButton.style.display = "inline";};
				displayItems[i].dom.onmouseout = function() { this.removeItemButton.style.display = "none";};
			}	
		}
	}
	if (this.isDesignMode()) {
		displayItems[displayItems.length-1].jsipe_title.addNextSibling(this.jsipe_title);
		this.jsipe_title.addNextSibling(this.jsipe_description);
		this.jsipe_description.addNextSibling(displayItems[0].jsipe_title);
	}
	return null;
}

JSPollSection.prototype.toDOMsectionResults = function(container) {
	var mode = this.parentPoll.mode;
	if ((mode == "nev" || (mode == "exp" && !this.parentPoll.expired)) && !this.config.isAdmin) return document.createTextNode(this.getLabelText("thanksForVote"));

	// Update values and percentages
	var items = this.getVisibleItems(); 
	var all = 0;
	JSKitLib.fmap(items, function(item) { if (item.votes) all += item.votes; else item.votes = 0; });
	this.voters = all;

	JSKitLib.fmap(items, function(item) { 
		var p = all ? Math.round(100 * item.votes/all) : 0; 
		item.percentage = p; 
		container.appendChild(item.toDOM());
	});
	return null;
}

JSPollSection.prototype.submitVote = function() {
	var sectionVoted  = false;
	var voteData = {sectionID: this.id, items: [], userItemText: ""};
	var visibleItems = this.getVisibleItems();

	for (var i = 0; i < visibleItems.length; i++) {
		if (this.voted) {
			sectionVoted = true;
			voteData.items = this.votes;
			continue;
		}

		if (visibleItems[i].selector.checked) {
			sectionVoted = true;
			visibleItems[i].votes++;
			voteData.items.push(visibleItems[i].id);
			if (visibleItems[i].itemType == "free_form") {	
				voteData.userItemText = JSKitLib.trim(visibleItems[i].userItemInputField.value);
				if (voteData.userItemText) {
					this.items.push(new JSPollItem({id: this.generateID(), title: voteData.userItemText, votes: 1, itemType: "user_defined", extra: []}, this.config, this));
				}
				this.userItemText = voteData.userItemText;
			}
		}
	}

	if (sectionVoted) {
		this.votes = voteData.items;
		return voteData;
	}
	return null;
}

JSPollSection.prototype.toDOMsectionControls = function(container) {
	if (!this.isDesignMode()) {
		container.style.display = "none";
		return null;
	}

	var parsedData = this.parseTemplate(this.controlsTemplate);
	var components = parsedData.components;
	var imagesLocation = this.parentPoll.imagesLocation;

	var self = this;

	//  Add answer button
	var onAddAnswerClick = function() {
		self.items.push(new JSPollItem(self.parentPoll.defaultItemData(self.getVisibleItems().length), self.config, self));
		self.render();
	}
	self.buildControlButton("AddOption", components, onAddAnswerClick, imagesLocation + "add.png");

	// Remove question button
	var onRemoveQuestionClick = function() {
		if (self.parentPoll.sections.length < 2) {
			alert(self.getLabelText("unableToDeleteLastSection"));
			return false;
		}

		if (confirm(self.getLabelText("removeSectionConfirm"))) {
			var index = self.getIndexByID(self.parentPoll.sections, self.id);
			self.parentPoll.sections.splice(index, 1);
			self.parentPoll.render();
		}
	}
	self.buildControlButton("RemoveSection", components, onRemoveQuestionClick, imagesLocation + "delete.png");

	// Change selector button
	var onChangeSelectorClick = function() {
		self.type = (self.type == "single") ? "multi" : "single";
		self.render();
	}
	var status = (self.type == "multi") ? "enabled" : "disabled";
	self.buildControlButton("ChangeSelector", components, onChangeSelectorClick, imagesLocation + status + ".png");
	
	// Free form switch button
	var onFreeFormSwitchClick = function() {
		self.freeForm = !self.freeForm;
		if (self.freeForm) {
			if (!self.freeFormItem) {
				self.freeFormItem = new JSPollItem({id: self.generateID(), title: self.getLabelText("defaultUserItemText"), votes: 0, itemType: "free_form", extra: []}, self.config, self);
			}
			self.items.push(self.freeFormItem);
		} else {
			self.freeFormItem = null;       
		}
		self.render();
	}
	var status = (this.freeForm) ? "enabled" : "disabled";
	self.buildControlButton("FreeFormSwitch", components, onFreeFormSwitchClick, imagesLocation + status + ".png");

	return parsedData.content;
}

/*
 *  Poll object constructor
 */
function JSPoll(target) {
	if (target.pollInitiated) return;

	var self = this;
	this.target = target;
	
	this.widgetsListIndex = pollsWidgetsList.length;
	pollsWidgetsList.push(this);

	this.properties = ["id", "timestamp", "title", "description", "extra", "creationTime", "expirationTime", "mode", "expires", "expired", "resultColor", "allowRevote"];

	// export fields
	this.exportProperties = ["id", "timestamp", "title", "description", "mode", "expires", "resultColor", "allowRevote", "sections"];

	this.colors = { ruby: '#e81629',   blue: '#4080bf', emerald: '#40bfa9',
			fire: '#e84916',   gold: '#eaa827', green: '#40bf40',
			indigo: '#4060bf', red: '#e82616',  violet: '#4930ce' };

	var wl = window.location;
	this.domain = "//js-kit.com";
	this.uri = wl.protocol + this.domain + '/multipoll'; 

	this.imagesLocation = wl.protocol + this.domain + "/images/polls/";

	this.config = JSKitLib.readConfig("polls",
		target,
		{},
		'domain',
		'path',
		'permalink'
	);
	if (target.jsk$msg) this.config.path += "::nav";
	this.pathOverride = this.config.path;
	this.ref = JSKitLib.getRef(this);
	this.adminConsoleWidth = 350;

	target.pollInitiated = true;

	this.showDataLoading(target);

	// call data from server 
	this.serverRequest("get");

	JSKitLib.fmap(["open", "close"], function(action) {
		self.eventCtx = JSKW$Events.registerEventCallback(
			self.eventCtx,
			function(eventName, target) {
				if (target && target == self.target) self[action + "AdminConsole"]();
			},
			"JSKitPolls_" + action + "AdminConsole"
		);
	});
}

JSPoll.prototype = new JSPollBaseModel();

JSPoll.prototype.template
 = '<div class="js-pollContainer js-PollBg">'
   + '<div class="js-poll-title js-pollSubject"></div>'
   + '<div class="js-poll-description"></div>'
   + '<div class="js-poll-pollSections"></div>'
   + '<div class="js-poll-pollControls"></div>'
   + '<div class="js-poll-usersControls js-pollSubmitRegion"></div>'
   + '<div class="js-poll-designModeSwitch"></div>'
   + '<div class="js-poll-byJSKit">(<a href="http://js-kit.com/polls?wow_p" target="js-kit">Powered by JS-Kit</a>)</div>'
   + '<div class="js-poll-clear"></div>'
 + '</div>';

JSPoll.prototype.switchDesignModeButton
 = '<div class="js-pollDesignModeSwitch js-pollConfigure"><a class="js-pollDesignModeSwitchA js-pollConfigureA" href="javascript:void(0);">{Label:configurePoll}</a></div>';

JSPoll.prototype.userControlsTemplate
 = '<div class="js-pollUserControlsSection">'
 + '<input class="js-pollSubmitVoteButton" type="button" value="{Label:submit}">'
 + '<input class="js-pollShowResultsButton" type="button" value="{Label:viewResults}">'
 + '<input class="js-pollRevoteButton" type="button" value="{Label:reVote}">'
 + '</div>';

JSPoll.prototype.adminConsoleTemplate
= '<div class="js-pollAdminConsole">'
+ '<div class="js-pollAdminConsoleTitle">{Label:pollsAdminConsoleTitle}</div>'
+ '<div class="js-pollAdminConsoleControls">'
 + '<div class="js-pollsControlsContainer">'
 + '<div class="js-pollBaseSettings">'
 + '<div class="js-pollSectionAdd js-pollSetting">'
   + '<div class="js-pollSectionAddImg js-pollControlsImg"></div>'
   + '<div class="js-pollSectionAddLabel js-pollControlsButton">{Label:addSection}</div>'
   + '<div class="js-poll-clear"></div>'
 + '</div>'
 + '<div class="js-pollRevoteModeSwitch js-pollSetting">'
   + '<div class="js-pollRevoteSwitchImg js-pollControlsImg"></div>'
   + '<div class="js-pollRevoteSwitchLabel js-pollControlsButton">{Label:allowRevoting}</div>'
   + '<div class="js-poll-clear"></div>'
 + '</div>'
 + '<div class="js-pollModeSwitch js-pollSetting">'
   + '<div class="js-pollModeImg js-pollControlsImg"></div>'
   + '<div class="js-pollControlsButton">'
     + '<select class="js-pollMode js-pollControl">'
       + '<option value="imm">Show results after voter submits answer</option>'
       + '<option value="vwv">Allow voters to view results without voting</option>'
       + '<option value="exp">Show results only after poll is closed</option>'
       + '<option value="nev">Never show poll results to voters</option>'
     + '</select>'
   + '</div>'
   + '<div class="js-poll-clear"></div>' 
 + '</div>'
 + '<div class="js-pollExpireSwitch js-pollSetting">'
   + '<div class="js-pollExpireImg js-pollControlsImg"></div>'
   + '<div class="js-pollControlsButton">'
     + '<select class="js-pollExpire js-pollControl">'
       + '<option value="1h">Close the poll in 1 hour</option>'
       + '<option value="24h">Close the poll after 1 day</option>'
       + '<option value="72h">Close the poll after 3 days</option>'
       + '<option value="168h">Close the poll after 1 week</option>'
       + '<option value="336h">Close the poll after 2 weeks</option>'
       + '<option value="0h" selected="on">Never close the poll</option>'
     + '</select>'
   + '</div>'
   + '<div class="js-poll-clear"></div>'
 + '</div>'
 + '<div class="js-pollResultsColorSwitch js-pollSetting">'
 + '<div class="js-pollResultsColorImg js-pollControlsImg"></div>'
   + '<div class="js-pollColorSwitch">'
     + '<div class="js-pollResultColorLabel">{Label:resultColor}</div><div class="js-pollItemDVBg js-pollColor"><div class="js-pollItemDV"></div></div><div class="js-poll-clear"></div>'
   + '</div>'
 + '</div>'
 + '<div class="js-pollHelp js-pollSetting">'
   + '<div class="js-pollHelpImg js-pollControlsImg"></div>'
   + '<div class="js-pollHelpLabel js-pollControlsButton">{Label:help}</div>'
   + '<div class="js-poll-clear"></div>'
 + '</div>'
 + '<div class="js-poll-clear"></div>' 
 + '</div>' 
 + '<div class="js-pollMainControls">'
   + '<div class="js-pollControlLeftSide">'
     + '<input type="button" class="js-pollShowResultsButton js-pollMainControlButton" value="{Label:viewResults}" />'
   + '</div>'
   + '<div class="js-pollControlRightSide">'
     + '<input type="button" class="js-pollCancelButton js-pollMainControlButton" value="{Label:cancel}" />'
     + '<input type="button" class="js-pollSaveButton js-pollMainControlButton" value="{Label:saveChanges}" />'
   + '</div>'
   + '<div class="js-poll-clear"></div>' 
 + '</div>'
 + '</div>'
 + '</div>';

JSPoll.prototype.dataLoadingTemplate
 = '<div class="js-pollDataLoading" style="overflow: hidden; padding: 5px;"><div style="float: left;"><img class="js-pollDataLoadingImg"></div><div style="float: left; padding-left: 7px; padding-top: 2px; font-size: 10px;">{Label:loading}</div></div>';

JSPoll.prototype.serverRequest = function(action, data) {
	var self = this;
	data = JSKitLib.appendExternalParams("polls", action, data || {});
	data.jx = this.widgetsListIndex;
	data.p = self.pathOverride;
	var request = {
		"ref" : self.ref,
		"uri" : self.uri + "." + action,
		"epb" : JSKitEPB.getAsHash(),
		"target" : self.target,
		"request" : data 
	};
	new JSRVC(request);
}

// server callback function
JSPoll.prototype.initFromData = function(initPollData, config) {
	var self = this;
	config.designMode = false;
	if (initPollData == null) {
		if (!config.isAdmin) {
			this.target.innerHTML = "";
			return;
		} else config.designMode = true;

		var initPollData = this.defaultPollData();
		this.isNewPoll = true;
	}
	JSKitLib.fmap(config, function(v, k) { self.config[k] = v; });
	this.setProperties(initPollData);
	this.toBoolean(["allowRevote"]);	

	this.sections = this.fromData(initPollData.sections);
	this.titlesIPE = {"title": this.getLabelText("pollTitleIPE"), "description": this.getLabelText("pollDescIPE")};

	this.config.widthIPE = (this.target.offsetWidth > 230) ? "150px" : "50px";
	this.target.innerHTML = "";
	this.target.appendChild(this.toDOM());
	if (this.isDesignMode() && !this.target.jsk$supressAdminConsole) JSKitLib.deferCall(function() { self.openAdminConsole(); });
}

JSPoll.prototype.toDOMpollSections = function(container) {
	if (!this.config.isAdmin) {
		if (this.expired && (this.mode == "nev" || (this.checkSectionsVotes() == "none" && this.mode != "vwv"))) return this.showMessage("pollClosed");
		if (!this.expired && (this.checkSectionsVotes() == "all" && (this.mode == "nev" || this.mode == "exp"))) return this.showMessage("allSectionsVoted");
	}
	if (this.target.jsk$isEmbedded) this.dom.style.border = "0px"; 
	JSKitLib.fmap(this.sections, function(section) { container.appendChild(section.toDOM()); });
	return null;
}

JSPoll.prototype.showMessage = function(label) {
	var self = this;
	var container = document.createElement("DIV");
	container.className = "js-pollMessage";
	container.appendChild(document.createTextNode(self.getLabelText(label)));	
	return container;
}

JSPoll.prototype.showDataLoading = function(target) {
	var parsedData = this.parseTemplate(this.dataLoadingTemplate);
	var dataLoadingTemplate = parsedData.content;
	parsedData.components["js-pollDataLoadingImg"].src = "//cdn.js-kit.com/images/loading.gif";
	target.appendChild(dataLoadingTemplate);
}

JSPoll.prototype.setBarColor = function(bar) {
	bar.style.background = '';
	bar.style.backgroundColor = this.colors[this.resultColor];
	JSKitLib.pngBar(this.resultColor, bar);
}

JSPoll.prototype.switchDesignMode = function(dataRefreshRequired) {
	if (dataRefreshRequired) {
		this.target.innerHTML = "";
		this.serverRequest("get");
	} else {
		this.config.designMode = !this.config.designMode;
		this.render();
	}
	this.toggleAdminConsole();
}

JSPoll.prototype.toDOMdesignModeSwitch = function() {
	if (this.config.isAdmin == false || this.isDesignMode()) return null;

	var parsedData = this.parseTemplate(this.switchDesignModeButton);
	var components = parsedData.components;

	var self = this;

	components["js-pollDesignModeSwitchA"].onclick = function() {
		if (self.isDesignMode()) {
			if (!confirm(self.getLabelText("cancelPollChangesConfirm"))) return false;
		}
		self.switchDesignMode();
	}
	return parsedData.content;		
}

JSPoll.prototype.submitVote = function() {
	var self = this;
	var pollVoted = true;
	var voteDataRaw = {pollID: this.id, votes: []};
	var notVotedSectionTitle = "";

	if (this.allowRevote && this.checkSectionsVotes() == "none") {
		JSKitLib.fmap(self.sections, function(section) {
			var userDefinedItemIdx  = null;
			var userDefinedItemText = JSKitLib.trim(section.userItemText);
			JSKitLib.fmap(section.items, function(item, idx) {
				if (section.votes.length > 0) {
					JSKitLib.fmap(section.votes, function(voteID) { if (voteID == item.id && item.votes > 0) item.votes--; } );
				}
				if (item.itemType == "user_defined" && JSKitLib.trim(item.title) == userDefinedItemText) userDefinedItemIdx = idx;
			});
			if (userDefinedItemIdx) section.items.splice(userDefinedItemIdx, 1);
			section.voted = false;
		});	
	}

	for (var i = 0; i < this.sections.length; i++) {
		var sectionVoteData = this.sections[i].submitVote();			
		if (sectionVoteData != null) { 
			this.sections[i].voted = true;
			voteDataRaw.votes.push(sectionVoteData);
		} else { 
			pollVoted = false;
			notVotedSectionTitle = this.sections[i].title;
			break;
		}
	}

	if (!pollVoted) {
		alert(this.getLabelText("noOptionSelectedStart") + " \"" + notVotedSectionTitle + "\" " + this.getLabelText("noOptionSelectedEnd"));
		return false;
	} 

	this.showResults = true;
	this.render();

	// Collect data and send vote to server
	this.serverRequest("vote", {"voteData": JSKitLib.Object2JSON(voteDataRaw), "permalink": self.config.permalink});
}

JSPoll.prototype.savePollChanges = function() {
	if (!confirm(this.getLabelText("savePollConfirm"))) return false;

	var self = this;

	// clean up user defined items if necessary
	JSKitLib.fmap(this.sections, function(section) { section.clearUserAnswers(); section.resetVotes(); });

	// Collect data and send poll changes to the server
	this.serverRequest("put", {"pollData" : JSKitLib.Object2JSON(self)});

	this.isNewPoll = false;
	this.showResults = false;
	this.switchDesignMode();
}

JSPoll.prototype.checkSectionsVotes = function() {
	var sectionsVotedCount = 0;
	JSKitLib.fmap(this.sections, function(section) { if (section.voted) sectionsVotedCount++; });
	return (sectionsVotedCount == this.sections.length) ? "all" : (sectionsVotedCount == 0) ? "none" : "some";
}

JSPoll.prototype.toDOMbyJSKit = function(container) {
	if (this.target.jsk$notShowBjs || this.config.whitelabel) container.style.display = "none";
}

JSPoll.prototype.toDOMusersControls = function() {
	if (this.isDesignMode() || this.expired) return null;

	var self = this;
	var parsedData = this.parseTemplate(this.userControlsTemplate);
	var components = parsedData.components;
	var sectionsVotes = this.checkSectionsVotes();

	components["js-pollRevoteButton"].style.display = 'none';
	if (sectionsVotes == "all") {
		components["js-pollSubmitVoteButton"].style.display = 'none';
		if (self.allowRevote && (!self.isDesignMode() || !self.showResults)) {
			components["js-pollRevoteButton"].style.display = 'inline';
			components["js-pollRevoteButton"].onclick = function() {	
				JSKitLib.fmap(self.sections, function(section) { section.voted = false; });
				self.showResults = false;
				self.render();
			}
		}
	}

	if (self.showResults) {
		components["js-pollSubmitVoteButton"].style.display = 'none';
		components["js-pollShowResultsButton"].value = self.getLabelText("backToVoteForm");
	}

	if ((self.mode != 'vwv') || sectionsVotes == "all") components["js-pollShowResultsButton"].style.display = 'none';

	components["js-pollSubmitVoteButton"].onclick = function() {
		self.submitVote();
	}

	components["js-pollShowResultsButton"].onclick = function() {
		self.showResults = !self.showResults;	
		self.render();
	}
	return parsedData.content;	
}

JSPoll.prototype.toggleAdminConsole = function() {
	this[(this.adminConsole ? "close" : "open") + "AdminConsole"]();
}

JSPoll.prototype.closeAdminConsole = function() {
	if (!this.adminConsole) return;
	this.adminConsole.parentNode.removeChild(this.adminConsole);
	this.adminConsole = undefined;
}

JSPoll.prototype.openAdminConsole = function(rerenderingMode) {
	if (!this.isDesignMode()) return; 

	this.jsipe_title.addNextSibling(this.jsipe_description);
	this.jsipe_description.addNextSibling(this.jsipe_title);

	var parsedData = this.parseTemplate(this.adminConsoleTemplate);
	var components = parsedData.components;

	var setOption = function(sel, value) {
		if(!sel || !value) return;
		JSKitLib.fmap(sel.options, function(opt, i) { if(opt.value === value) sel.selectedIndex = i; });
	}

	var self = this;

	// Add question button
	var onAddQuestionClick = function() {
		self.sections.push(new JSPollSection(self.defaultSectionData(self.sections.length), self.config, self));
		self.render();
	}
	self.buildControlButton("SectionAdd", components, onAddQuestionClick, imagesLocation + "add.png");

	// Enable/Disable revote mode button
	var status = (self.allowRevote) ? "enabled" : "disabled";
	var onRevoteButtonClick = function(name) { 
		self.allowRevote = !self.allowRevote;
		var status = (self.allowRevote) ? "enabled" : "disabled"; 
		JSKitLib.addPNG(components["js-pollRevoteSwitchImg"], self.imagesLocation + status + ".png");
	}
	self.buildControlButton("RevoteSwitch", components, onRevoteButtonClick, imagesLocation + status + ".png");

	// Switch mode selector
	setOption(components["js-pollMode"], self.mode);
	JSKitLib.addPNG(components["js-pollModeImg"], self.imagesLocation + "time.png");
	components["js-pollMode"].onchange = function() {
		self.mode = this.value;
	}

	// Switch expiration time selector
	setOption(components["js-pollExpire"], self.expires);		
	JSKitLib.addPNG(components["js-pollExpireImg"], self.imagesLocation + "chart_bar.png");
	components["js-pollExpire"].onchange = function() {
		self.expires = this.value;
	}

	// Results color switch
	JSKitLib.addPNG(components["js-pollResultsColorImg"], self.imagesLocation + "palette.png");
	var clr = components['js-pollColor'];
	var cdv = components['js-pollItemDV'];
	clr.onclick = function() {
		if(!self.colorsArray) {
			self.colorsArray = JSKitLib.foldl([], self.colors, function(colorHex, acc, color) {
				if(self.resultColor === color) self.colorSelected = acc.length;
				acc.push(color);
			});
		}
		self.colorSelected++;
		self.resultColor = self.colorsArray[self.colorSelected % self.colorsArray.length];
		self.setBarColor(cdv);
		clr.selectedIndex = 0;
		clr.options = [{value: self.resultColor}];
		return false;
	}
	this.setBarColor(cdv);

	// Help button
	var onHelpButtonClick = function() { window.open("http://wiki.js-kit.com/FAQ+-+Polls", "JSKit Polls Service"); }
	self.buildControlButton("Help", components, onHelpButtonClick, imagesLocation + "help.png");

	// Show/Hide results button
	var label = (self.showResultsToAdmin) ? "closeResultsForm" : "viewResults";
	components["js-pollShowResultsButton"].value = this.getLabelText(label);
	components["js-pollShowResultsButton"].onclick = function() {
		self.showResultsToAdmin = !self.showResultsToAdmin;
		self.config.disableIPE  = self.showResultsToAdmin;
		self.render();
		self.openAdminConsole(true);
	}

	// Cancel button
	components["js-pollCancelButton"].onclick = function() {
		if (self.isDesignMode()) {
			if (!confirm(self.getLabelText("cancelPollChangesConfirm"))) return false;
		}
		self.showResultsToAdmin = false;
		self.switchDesignMode(true);
	}

	// Save poll button
	components["js-pollSaveButton"].onclick = function() {
		self.savePollChanges();
	}

	var buttonsStatus = {"Save": this.showResultsToAdmin, "Cancel": this.isNewPoll || this.showResultsToAdmin, "ShowResults": this.isNewPoll};
	JSKitLib.fmap(buttonsStatus, function(disabled, name) { components["js-poll" + name + "Button"].disabled = (disabled) ? "disabled": ""; });	
	components["js-pollBaseSettings"].style.display = (this.showResultsToAdmin) ? "none" : "block";

	var findPosition = function() {
		var targetPosition = JSKitLib.findPos(self.target);
		return (targetPosition[0] < self.adminConsoleWidth + 10) ?
			(document.body.clientWidth < targetPosition[0] + self.target.offsetWidth + self.adminConsoleWidth + 10) ?
			{"x" : targetPosition[0], "y" : targetPosition[3] + 10}:
			{"x" : targetPosition[0] + self.target.offsetWidth + 10, "y" : targetPosition[1]}:
			{"x" : targetPosition[0] - self.adminConsoleWidth - 10, "y" : targetPosition[1]}
	};

	var position = (rerenderingMode && this.adminConsole) ?
		{"x" : self.adminConsole.offsetLeft, "y" : self.adminConsole.offsetTop} : findPosition();

	this.closeAdminConsole(); 
	this.adminConsole = parsedData.content;
	JSKitLib.addStyle(this.adminConsole, "left:" + position.x + "px; top:" + position.y + "px; width:" + self.adminConsoleWidth + "px;");
	document.body.appendChild(this.adminConsole); 
	JSKitLib.setOpacity(this.adminConsole, "0.9");
	new JSDL(this.adminConsole, [components["js-pollAdminConsoleTitle"]]);
	return this.adminConsole;
}

JSPoll.prototype.fromData = function(sectionsData) {
	return JSKitLib.fmap.call(this, sectionsData, function(data) { return new JSPollSection(data, this.config, this); });
}

JSPoll.prototype.defaultItemData = function(currentItemsCount) {
	return {id: this.generateID() + currentItemsCount, title: 'New Answer ' + (currentItemsCount + 1), votes: 0, itemType: "default", extra: []};
}

JSPoll.prototype.defaultSectionData = function(currentSectionsCount) {
	return {id: this.generateID() + currentSectionsCount, title: 'New question #' + (currentSectionsCount + 1), description: 'Question description', votes: [], userItemText: "", type: 'single', freeForm: false, enabled: true, extra: [], items: [this.defaultItemData(0), this.defaultItemData(1)]};
}

JSPoll.prototype.defaultPollData = function() {
	return {id: 0, timestamp: 0, title: "Default poll title", description: "Default poll description", extra: [], mode: "imm", expires: "336h", expired: false, resultColor: "blue", sections: [this.defaultSectionData(0)]};
}

/* Prepare polls container(s) and init application(s) */
var divs = JSKitLib.fmap(document.getElementsByTagName("div"), function(element) { return element; });
JSKitLib.fmap(divs, function(element) {
	if(element.className.match(/js-kit-poll/)) new JSPoll(element);
});

/* Handling callbacks from other widgets */
if (typeof(JSPC$Callbacks) != "undefined") {
	var cbapply = function(cb){ cb() };
	JSKitLib.map(cbapply, JSPC$Callbacks);
	JSPC$Callbacks = [];
	JSPC$Callbacks.push = cbapply;
}

var imagesLocation = (pollsWidgetsList.length > 0) ? pollsWidgetsList[0].imagesLocation : window.location.protocol + "//js-kit.com/images/polls/";
var zoomCSS = JSKitLib.isIE() ? "zoom:1;" : "";
JSKitLib.addCss(
  ".js-kit-poll { text-align: left; padding: 1px; }"
+ ".js-poll-title { display: inline; }"
+ ".js-poll-removeItem { display: none; margin-left: 3px; float: left; }"
+ ".js-poll-userDefinedItem { display: block; }"
+ ".js-poll-userDefinedItemsList { padding-top: 5px; }"
+ ".js-pollMessage { margin: 7px; font-size: 14px; }"
+ ".js-pollSectionControls { background: #ffffd1; padding: 5px; }"
+ ".js-pollButtonLabel { margin-left: 20px; color: #0000ff; }"
+ ".js-pollControlsButton { width: 80%; color: #0000ff; float: left; font-size: 14px; margin: " + (JSKitLib.isIE() ? "0": "2") + "px 0px 0px " + (JSKitLib.isPreIE7() ? "15" : "25") + "px; }"
+ ".js-pollSectionCtrlLabel { cursor: pointer; font-size: 10px; color: #0000ff; float: left; margin: 4px 0px 0px " + (JSKitLib.isPreIE7() ? "12" : "25") + "px; }"
+ ".js-pollSetting { " + zoomCSS + " margin: 3px 0px; " + (JSKitLib.isIE() ? "line-height: 19px;" : "") + " }"
+ ".js-pollRevoteModeSwitch { " + (JSKitLib.isPreIE7() ? "margin-top: 3px;" : "") + " }"
+ ".js-pollSectionAdd { margin-bottom: 0px; }"
+ ".js-pollControlLeftSide { float: left; }"
+ ".js-pollControlRightSide { float: right; }"
+ ".js-pollBaseSettings { " + zoomCSS + " background: #ffffd1; padding: 5px; }"
+ ".js-pollControlsImg { width: 16px; height: 16px; float: left; margin: 2px -25px 0px 3px; }"
+ ".js-pollSectionCtrlImg { width: 16px; height: 16px; float: left; margin: 2px -25px 0px 3px; cursor: pointer; }"
+ ".js-pollMainControls { padding: 5px 0px 5px 0px;} "
+ ".js-pollResultColorLabel { float: left; color: #000000; font-size: 12px; margin: 5px 10px 0px 0px; }"
+ ".js-pollButtonImageContainer { " + zoomCSS + " display: inline; font-size: 15px; padding: 0px 20px 0px 0px; cursor: pointer; }"
+ ".js-pollSectionSettingL { margin: 3px 0px; padding-right: 5px; width: 50%; float: left; }"
+ ".js-pollSectionSettingR { margin: 3px 0px; width: 48%; float: left; }"
+ ".js-poll-usersControls { float: left; margin: 0px 0px 0px 5px; }"
+ ".js-poll-designModeSwitch { float: right; }"
+ ".js-pollSectionAddLabel, .js-pollHelpLabel, .js-pollSectionAddImg, .js-pollRevoteSwitchLabel, .js-pollColor, .js-pollRevoteSwitchImg, .js-pollHelpImg { cursor: pointer; }"
+ ".js-pollContainer { border: 1px solid #c0c0c0; padding: 5px; margin: 5px; }"
+ ".js-pollContainer .js-poll-title { font-size: 18px; font-weight: bold; }"
+ ".js-pollContainer .js-poll-description { font-size: 11px; font-style: italic; margin: 3px 0px 0px 0px; }"
+ ".js-pollSectionContainer { " + zoomCSS + " border: 1px dotted #c0c0c0; padding: 5px; margin: 5px; }"  
+ ".js-pollSectionContainer .js-poll-title { font-size: 14px; font-weight: bold; vertical-align:middle; }"
+ ".js-pollItemContainer { " + zoomCSS + " display: block; vertical-align: middle; clear: both; line-height: 25px; overflow: hidden; }"
+ ".js-poll-selector { float: left; font-size: 14px; vertical-align: middle; margin-right: -25px; padding: " + (JSKitLib.isIE() ? "3" : (JSKitLib.isOpera() ? "0" : "1")) + "px 5px 0px 0px; width: 20px; }"
+ ".js-pollItemContainer .js-poll-title { font-size: 14px; font-weight: normal; margin: 0px 0px 0px 25px; float: left; }"
+ ".js-pollAdminConsole { position: absolute; z-index: 12000; background: #DDDDAA; top: 100px; left: 100px; border: 1px solid #AFAFAF; }"
+ ".js-pollAdminConsoleTitle { background: #DDDDAA; text-align: center; padding: 5px; color: #000000; font-weight: bold; }"
+ ".js-pollAdminConsoleControls { background: #FFFFD1; padding: 5px; }"
+ ".js-poll-sectionControls { clear: both; margin: 5px; }"
+ ".js-poll-byJSKit { clear: both; margin-right: .3em; text-align: right; color: #808080; font-size: 7pt; font-family: Verdana, Helvetica; }"
+ ".js-poll-byJSKit a { text-decoration: none; color: #8080a0; }"
+ ".js-pollResultsColorImg { margin-top: " + (JSKitLib.isIE() ? "5" : "3") + "px; }"
+ ".js-pollSectionButton { margin-left: 1em; line-height: 16px; font-size: 10px; }"
+ ".js-pollControl { margin: 0px; width: 100%; padding: 0px; }"
+ ".js-pollDesignModeSwitch { margin: 5px; }"
+ ".js-pollUserItemInput { display: block; }"
+ ".js-pollUserItemInputDiv { clear: both; display: block; margin-left: 20px; font-size: 12px; }"
+ ".js-pollUserItemNotice { clear: both; display: block; margin-left: 20px; font-size: 10px; line-height: 12px; }"
+ ".js-pollUserItemsListElement { padding-left: 10px; font-size: 10px; }"
+ ".js-pollItemVotedContainer { clear: both; display: block; padding: 5px 0; }"
+ ".js-poll-votedItemText { text-align: left; font-size: 14px; float: left; }"
+ ".js-pollUserDefinedListSwitch { margin-left: 5px; float: left; font-size: 14px; }"
+ ".js-pollUserDefinedListSwitchA { text-decoration: none; }"
+ ".js-poll-votedItemData { text-align: right; font-size: 7pt; float: right; padding-top: 3px; }"
+ ".js-pollItemDVT { position: absolute; bottom: 16px; right: 0; font-size: 7pt; font-family: Verdana; margin-left: 1em; }"
+ ".jsipe-applyButton { " + zoomCSS + " cursor: pointer; display: inline; padding-right: 20px; margin-left: 5px; }"
+ ".jsipe-onmouseover { background: #ffffd1; cursor: pointer; }"
+ ".js-pollItemDVL { width: 2px; height: 12px; position:absolute; left:-2px; top:0;" + JSKitLib.pngBar('lshade', null, true) + "}"
+ ".js-pollItemDVR { width: 2px; height: 12px; position:absolute; right:-2px; top:0;" + JSKitLib.pngBar('rshade', null, true) + "}"
+ ".js-pollItemDVBg { width: 100%; height: 12px; position: relative; margin-top: 2px;" + JSKitLib.pngBar('clear') + "}"
+ ".js-pollItemDV { clear: both; width: 100%; height: 12px; font-size: 2pt; background-color: #FFFFFF; " + JSKitLib.pngBar('clear') + "}"
+ ".js-pollColorSwitch { margin-left: 25px; }"
+ ".js-pollColorSwitch .js-pollItemDVBg { width: 40%; float: left; margin-top: " + (JSKitLib.isIE() ? "9" : "6") + "px; }"
+ ".js-pollColorSwitch .js-pollItemDV { width: 75%; }"
+ ".js-designModeControls { " + zoomCSS + " }"
+ ".js-poll-clear { clear: both; }"
+ ".js-nsgecko { -moz-user-select: none; }", "pollCSS"
);
