function PrevNext(item_root, click_root, prev_next_root, num_per_page, prev_next_areas) {
    this.MAX_VISIBLE_PARTS = num_per_page;
	this.setRoots(item_root, click_root);
	this.current_index = 0;
	this.next_elem = document.createElement('div');
	Tools.setBox(this.next_elem, prev_next_areas.next);
	this.prev_elem = document.createElement('div');
	Tools.setBox(this.prev_elem, prev_next_areas.prev);
	$(this.next_elem).addClass('button');
	Tools.addHoverEffect(this.next_elem, 'images/metal/metal_button_page_next.png', '42');
	$(this.prev_elem).addClass('button');
	Tools.addHoverEffect(this.prev_elem, 'images/metal/metal_button_page_prev.png', '42');
	var prev_next = this;
	$(this.next_elem).click(function() {
		prev_next.next();
	});
	$(this.prev_elem).click(function() {
		prev_next.previous();
	});
	Tools.append(prev_next_root, this.prev_elem);
	Tools.append(prev_next_root, this.next_elem);

	this.page_text_elem = document.createElement('div');
	$(this.page_text_elem).addClass('page-counter');
	Tools.setBox(this.page_text_elem, prev_next_areas.page);
	Tools.append(prev_next_root, this.page_text_elem);

	this.adjustAll();
}

PrevNext.prototype.setRoots = function(item_root, click_root) {
	this.root = item_root;
	this.click_root = click_root;
}

PrevNext.prototype.next = function() {
	if (!this.canNext())
		return;
	this.current_index = this.current_index + this.MAX_VISIBLE_PARTS;
	this.adjustAll();
};

PrevNext.prototype.previous = function() {
	if (!this.canPrevious())
		return;
	this.current_index = this.current_index - this.MAX_VISIBLE_PARTS;
	this.adjustAll();
};

PrevNext.prototype.adjustVisibility = function(index, elem, click) {
	if (index >= this.current_index + this.MAX_VISIBLE_PARTS || index < this.current_index) {
		Tools.hide(elem);
		Tools.hide(click);
	} else {
		Tools.show(elem);
		Tools.show(click);
	}
};

PrevNext.prototype.enableButton = function(button) {
	Tools.enableHoverEffect(button, '42');
};

PrevNext.prototype.disableButton = function(button) {
	Tools.disableHoverEffect(button, '42');
};

PrevNext.prototype.canPrevious = function() {
	return this.current_index > 0;
};

PrevNext.prototype.canNext = function() {
	return this.current_index < this.getMaxIndex() - (this.MAX_VISIBLE_PARTS - 1);
};

PrevNext.prototype.getMaxIndex = function() {
	if (!this.root)
		return 0;
	var parts = $(this.root).children();
	return parts.size() - 1;
};

PrevNext.prototype.adjustAll = function() {
	this.current_index = Math.min(Math.max(0, this.current_index), this.getMaxIndex());
	if (this.root) {
		var parts = $(this.root).children();
		var click_parts = $(this.click_root).children();
		for (var i = 0; i < parts.size(); i++) {
			this.adjustVisibility(i, parts[i], click_parts[i]);
		}
	}
	if (!this.canNext())
		this.disableButton(this.next_elem);
	else
		this.enableButton(this.next_elem);
	if (!this.canPrevious())
		this.disableButton(this.prev_elem);
	else
		this.enableButton(this.prev_elem);
	var current_page = Math.ceil((this.current_index + 1)/this.MAX_VISIBLE_PARTS);
	current_page = current_page > 0 ? current_page : 1;
	var page_count = Math.ceil((this.getMaxIndex() + 1)/this.MAX_VISIBLE_PARTS);
	page_count = page_count > 0 ? page_count : 1;
	$(this.page_text_elem).html("<p>Page " + current_page + "/" + page_count + "</p>");
};

var Tools = {
	TOWN_WIDTH: 960,
	TOWN_HEIGHT: 600,
	MENU_WIDTH: 160,
	TOPBAR_HEIGHT: 32,

	rpc: function(action, args, success_func, error_func) {
		var url = '/rpc/' + action;
		if (!args)
			args = {}
		$.ajax({url: url, type: 'POST', dataType: 'json', data: args, error: error_func, success: function(data) {
			if (data) {
				var piggyback = data.piggyback;
				if (piggyback) {
					EntityListeners.callListeners(piggyback);
					data = data.result;
				}
			}
			if (success_func)
				success_func(data);
		}});
	},
	createAppletFrame: function(code, archive, width, height, params) {
		var iframe = document.createElement('iframe');
		$(iframe).css('width', width + "px");
		$(iframe).css('height', height + "px");
		$(iframe).css('border', "0");
		$(iframe).attr('src', '/files/empty_frame.html');
		$(iframe).attr('frameBorder', '0');
		$(iframe).attr('border', '0');
		$(iframe).attr('allowtransparency', 'true');
		$(iframe).attr('scrolling', 'no');
		$(iframe).load(function() {
			$(iframe).unbind();
			var oDoc = iframe.contentWindow || iframe.contentDocument;
			if (oDoc.document) {
				oDoc = oDoc.document;
			}
			var html = Service.getAppletHtml(code, archive, width, height, params);
			$(oDoc.body).html(html);
		});
		return iframe;
	},
	getRedirectURL: function(url) {
		var halves = String(window.location).split('?');
		if (halves[1]) {
			if (String(url).indexOf('?') == -1)
				url += '?';
			else
				url += '&';
			url += halves[1];
		}
		return url;
	},
	getURLVar: function(urlVarName) {
		var urlHalves = String(document.location).split('?');
		var urlVarValue = '';
		if(urlHalves[1]){
			var urlVars = urlHalves[1].split('&');
			for(var i=0; i<=(urlVars.length); i++){
				if(urlVars[i]){
					var urlVarPair = urlVars[i].split('=');
					if (urlVarPair[0] && urlVarPair[0].toLowerCase() == urlVarName.toLowerCase()) {
						urlVarValue = decodeURIComponent(urlVarPair[1]);
					}
				}
			}
		}
		return urlVarValue;
	},
	redirect: function(url) {
		window.location = Tools.getRedirectURL(url);
	},
	redirectLogin: function(session_id, remember) {
		  var days = null;
		  if (remember) {
			  days = settings.session_expiry_days;
		  }
		  Tools.setCookie("session_id", session_id, days);
		  Tools.redirect('/main');
	},
	getAnalyticsTracker: function() {
		return pageTracker;
	},
	registerEnter: function(element, callback) {
		$(element).keyup(function(e) {
			return Tools.getKeyCode(e) != 13;
		});
		$(element).keydown(function(e) {
			if (Tools.getKeyCode(e) == 13) {
				callback();
				return false;
			}
		});
		$(element).keypress(function(e) {
			return e.which != 13;
		});
	},

	createElement: function(tag, parent_element, text, classes) {
		var element = document.createElement(tag);
		if (text) {
			$(element).html(text);
		}
		if (classes) {
			$(element).addClass(classes);
		}
		Tools.append(parent_element, element);
		return element;
	},

	createNumberInput: function(num_digits) {
		var input_element = document.createElement('input');
		$(input_element).attr('type', 'text');
		$(input_element).keypress(function(evt) {
			evt = (evt) ? evt : window.event;
			if (evt.which) {
				return (evt.which >= 48 && evt.which <= 57 && $(input_element).val().length < num_digits) || evt.which == 8 || evt.which == 13;
			} else {
				return evt.keyCode == 9 || evt.keyCode == 37 || evt.keyCode == 39 || evt.keyCode == 46 || evt.keyCode == 13;
			}
		});
		return input_element;
	},

	createRadioElement: function(name, checked) {
		var rdo;
		try {  
			rdo = document.createElement('<input type="radio" name="' + name + '"' + (checked ? ' checked="true" ' : '') + ' />');
		} catch(err) {
			rdo = document.createElement('input');
			if (checked)
				$(rdo).attr('checked', true);
		}
		$(rdo).attr('type', 'radio');
		$(rdo).attr('name', name);
		return rdo;
	},

	createLink: function(pre, a, post, f) {
		var link_elem = document.createElement('div');
		var pre_elem = document.createElement('span');
		$(pre_elem).text(pre);
		Tools.append(link_elem, pre_elem);
		var a_elem = document.createElement('a');
		$(a_elem).text(a);
		$(a_elem).attr('href', '#');
		$(a_elem).click(function() {
			f();
			return false;
		});
		Tools.append(link_elem, a_elem);
		var post_elem = document.createElement('span');
		$(post_elem).text(post);
		Tools.append(link_elem, post_elem);
		return link_elem;
	},

	switchTypeSafely: function(elem, type) {
		try {
			elem.type = type;
		} catch(e) { 
		}
	},

	setupDynamicInlineInput: function(elem, inline_text) {
		var allow_type_change = $(elem).attr('type') == 'password';
		var cleared;
		var on_blur = function() {
			cleared = $(elem).val() == '';
			if (cleared) {
				$(elem).val(inline_text);
				if (allow_type_change)
					Tools.switchTypeSafely(elem, 'text');
			}
		};
		on_blur();
		$(elem).focus(function() {
			if (cleared) {
				$(elem).val('');
				if (allow_type_change)
					Tools.switchTypeSafely(elem, 'password');
			}
		});
		$(elem).blur(on_blur);
	},

	setupInlineInput: function(fake_elem, real_elem) {
		$(fake_elem).focus(function() {
			$(fake_elem).css("display", "none");
			$(real_elem).css("display", "inline");
			$(real_elem).focus();
		});
		$(real_elem).blur(function() {
			if ($(real_elem).val() == '') {
				$(fake_elem).css("display", "inline");
				$(real_elem).css("display", "none");
			}
		});
	},

	createClearElement: function() {
		var clear_elem = document.createElement('div');
		$(clear_elem).css('clear', 'both');
		return clear_elem;
	},

	createListenerElement: function() {
		var listener_elem = document.createElement('div');
		$(listener_elem).css('display', 'none');
		return listener_elem;
	},
	createDynamicUserElement: function(user_id, avatar_size) {
		var user_info = Tools.createUserElement(avatar_size);
		Tools.addEntityListener(user_info.user_elem, user_id, function(user) {
			user_info.rebuilder(user);
		});
		return user_info.user_elem;
	},
	createUserElement: function(avatar_size) {
		var user_elem = document.createElement('div');
		var avatar_elem = document.createElement('div');
		var name_elem = document.createElement('div');
		$(user_elem).addClass('user');
		$(name_elem).addClass('username');
		var avatar_info = Tools.insertDynamicAvatar(avatar_elem, avatar_size);
		var rebuilder = function(user) {
			$(name_elem).text(user.name);
			$(name_elem).css('overflow', 'hidden');
			avatar_info.rebuilder(user);
		};
		Tools.append(user_elem, avatar_elem);
		Tools.append(user_elem, name_elem);
		return {user_elem: user_elem, rebuilder: rebuilder};
	},
	getFontSize: function(text, min_size, max_size) {
		if (text.length > 18) {
			return min_size;
		} else {
			return max_size
		}
	},
	getAvatarMaps: function(user) {
		var instance_map = {};
		for (var i = 0; i < user.instances.length; i++)
			instance_map[i] = user.instances[i];
		var parts_map = {};
		for (var i = 0; i < user.types.length; i++)
			parts_map[user.types[i]] = user.type_values[i];
		var color_map = {};
		for (var i = 0; i < user.color_groups.length; i++)
			color_map[user.color_groups[i]] = user.color_values[i];
		return {'instance_map': instance_map, 'parts_map': parts_map, 'color_map': color_map};
	},
	insertAvatar: function(parent_elem, user_id, size) {
		var avatar_info = Tools.insertDynamicAvatar(parent_elem, size);
		Tools.addEntityListener(avatar_info.listener_elem, user_id, function(user) {
			avatar_info.rebuilder(user);
		});
	},
	insertDynamicAvatar: function(parent_elem, size) {
		Tools.empty(parent_elem);
		var listener_elem = document.createElement('div');
		var color_tracker;
		var rebuilder = function(user) {
			Tools.empty(listener_elem);
			var avatar_maps = Tools.getAvatarMaps(user);
			var color_tracker = GWTTools.insertAvatar(listener_elem, avatar_maps.parts_map, avatar_maps.instance_map, size);
			for (var i = 0; i < user.color_groups.length; i++)
				color_tracker(user.color_groups[i], user.color_values[i]);
		};
		Tools.append(parent_elem, listener_elem);
		return {rebuilder: rebuilder, listener_elem: listener_elem};
	},

	trackSetValue: function(elem) {
		return {
			onremove: function() {
			   $(elem).text('');
			},
			onset: function(value) {
			   $(elem).text(String(value));
			}
		};
	},

	appendInput: function(element, input_text, input_type) {
		var input_element = document.createElement('input');
		var input_label = document.createElement('div');
		$(input_element).attr('type', input_type);
		$(input_label).text(input_text);
		$(input_label).addClass('label');
		$(element).append(input_label);
		$(element).append(input_element);
		return input_element;
	},

	appendInputRowToTable: function(element, input_text, input_type) {
		var tr_elem = document.createElement('tr');
		$(element).append(tr_elem);

		var td_elem = document.createElement('td');
		$(tr_elem).append(td_elem);
		var input_label = document.createElement('div');
		$(input_label).text(input_text);
		$(input_label).addClass('label');
		$(td_elem).append(input_label);

		td_elem = document.createElement('td');
		$(tr_elem).append(td_elem);
		var input_element = document.createElement('input');
		$(input_element).attr('type', input_type);
		$(td_elem).append(input_element);
		return input_element;
	},

	setSize: function(element, width, height) {
		$(element).css({width:width+"px", height:height+"px"});
	},

	setPos: function(element, x, y) {
		$(element).css({position:"absolute", left:x+"px", top:y+"px"});
	},

	getHostname: function() {
		var host = window.location.hostname;
		return host.substring(host.indexOf('.') + 1);
	},

	toDownloadURL: function(url) {
		return "http://download." + Tools.getHostname() + "/" + url;
	},

	setAbsoluteCentered: function(element, width, height) {
		Tools.setPos(element, (Tools.TOWN_WIDTH - width)/2, (Tools.TOWN_HEIGHT - height)/2);
	},

	createScrollPiece: function(popup, name, width, height, x, y) {
		var piece = document.createElement('div');
		$(piece).css({background: "transparent url("+Tools.toDownloadURL("images/scroll/scroll_gui_"+name+".png")+")", position:"absolute"});
		$(piece).css({width:width+"px", height:height+"px"});
		$(piece).css({left:x+"px", top:y+"px"});
		$(popup).append(piece);
	},

	createScroll: function(popup, width, height) {
		var left_width = 53;
		var right_width = 60;
		var top_height = 88;
		var buttom_height = 67;
		var buttom_left_height = 125;
		var buttom_right_height = 125;
		Tools.createScrollPiece(popup, "TL", left_width, height-buttom_left_height, 0, 0);
		Tools.createScrollPiece(popup, "TR", right_width, height-buttom_right_height, width - right_width, 0);
		Tools.createScrollPiece(popup, "BL", left_width, buttom_left_height, 0, height - buttom_left_height);
		Tools.createScrollPiece(popup, "BR", right_width, buttom_right_height, 0 + width - right_width, height - buttom_left_height);
		Tools.createScrollPiece(popup, "T", width - left_width - right_width, top_height, left_width, 0);
		Tools.createScrollPiece(popup, "B", width - left_width - right_width, buttom_height, left_width, height - buttom_height);
		Tools.createScrollPiece(popup, "C", width - left_width - right_width, height - top_height - buttom_height, left_width, top_height);
		var content = document.createElement('div');
		var left_offset = 60;
		var right_offset = 60;
		var top_offset = 50;
		var buttom_offset = 20;
		$(content).css({position:"absolute", left:left_offset + "px", top:top_offset + "px", width:(width - left_offset - right_offset)+"px", height:(height - top_offset - buttom_offset)+"px"});
		Tools.append(popup, content);
		return content;
	},

	createPopup: function(width, height) {
		var popup_parent = document.createElement('div');
		$(popup_parent).addClass('ghosted');
		var popup = document.createElement('div');
		Tools.setAbsoluteCentered(popup, width, height);
		var content = Tools.createScroll(popup, width, height);
		Tools.append(popup_parent, popup);
		return {popup_parent: popup_parent, popup: content};
	},

	setCentered: function(element, height) {
		$(element).css('margin', (Tools.TOWN_HEIGHT - height)/2 + 'px auto 0 auto');
	},

	getCookie: function(c_name) {
		if (document.cookie.length>0) {
			c_start=document.cookie.indexOf(c_name + "=");
			if (c_start!=-1) { 
				c_start=c_start + c_name.length+1; 
				c_end=document.cookie.indexOf(";",c_start);
				if (c_end==-1) c_end=document.cookie.length;
				return unescape(document.cookie.substring(c_start,c_end));
			} 
		}
		return null;
	},

	addEntityListener: function(element, entity_key, listener, params, error_listener) {
		Tools.addHierarchyListener(element,
			function() {
				EntityListeners.addListener(entity_key, listener, params, error_listener);
			},
			function() {
				EntityListeners.removeListener(entity_key, listener, error_listener);
			}
		);
	},

	addSubscriptions: function(element, sets) {
		Tools.addHierarchyListener(element,
			function() {
				Service.subscribeToLivesets(sets);
			},
			function() {
				Service.unsubscribeFromLivesets(sets);
			}
		);
	},

	addSetListener: function(element, set_type, listener) {
		Tools.addHierarchyListener(element,
			function() {
				Livesets.addSetListener(set_type, listener);
			},
			function() {
				Livesets.removeSetListener(set_type, listener);
			}
		);
	},

	addValueListener: function(element, set_type, value_id, listener) {
		Tools.addHierarchyListener(element,
			function() {
				Livesets.addValueListener(set_type, value_id, listener);
			},
			function() {
				Livesets.removeValueListener(set_type, value_id, listener);
			}
		);
	},

	getAffiliate: function() {
		return Tools.getURLVar('affiliate');
	},

	getSessionID: function() {
		var session_id = Tools.internalGetSessionID();
		if (session_id == null || session_id == "")
			return null;
		var halves = String(session_id).split('|');
		var affiliate = halves[1];
		var url_affiliate = Tools.getAffiliate();
		if ((affiliate || url_affiliate) && affiliate != url_affiliate)
			return null;
		else
			return session_id;
	},

	internalGetSessionID: function() {
		return Tools.getCookie("session_id");
	},

	checkSession: function(success_func, fail_func) {
		var session_id = Tools.getSessionID();
		if (session_id != null) {
			Tools.rpc('get_user_id', {}, function() {
					success_func(session_id);
				},
				fail_func
			);
		} else {
			fail_func();
		}
	},

	setCookie: function(c_name,value,expiredays) {
		var exdate = new Date();
		exdate.setDate(exdate.getDate() + expiredays);
		document.cookie = c_name + "=" + escape(value)+
			((expiredays==null) ? "" : "; expires="+exdate.toGMTString()) + "; path=/";
	},

	getKeyCode: function(e) {
		return (window.event) ? event.keyCode : e.keyCode;
	},

	hide: function(element) {
		$(element).css("display", "none");
	},

	show: function(element) {
		$(element).css("display", "");
	},

	empty: function(element) {
		$(element).children().each(function() {
			Tools.remove(this);
		});
	},

	after: function(elem1, elem2) {
		var had_html_parent = Tools.hasHTMLParent(elem2);
		$(elem1).after(elem2);
		if (!had_html_parent)
			Tools.callHierarchyAdded(elem2);
	},

	insertBefore: function(p, element) {
		var had_html_parent = Tools.hasHTMLParent(element);
		$(element).insertBefore(p);
		if (!had_html_parent)
			Tools.callHierarchyAdded(element);
	},

	prepend: function(p, element) {
		var had_html_parent = Tools.hasHTMLParent(element);
		$(p).prepend(element);
		if (!had_html_parent)
			Tools.callHierarchyAdded(element);
	},

	append: function(p, element) {
		var had_html_parent = Tools.hasHTMLParent(element);
		$(p).append(element);
		if (!had_html_parent) {
			Tools.callHierarchyAdded(element);
		}
	},

	loadScript: function(url, load_func) {
		var e = document.createElement('script');
		e.src = url;
		e.type = "text/javascript";
		$(e).load(load_func);
		Tools.append(document.body, e);
	},

	callHierarchyAdded: function(element) {
		if (Tools.hasHTMLParent(element)) {
			Tools.traverseChildren(element, function() {
				if (this.onadd != null) {
					this.onadd();
				}
			});
		}
	},

	hasHTMLParent: function(element) {
		var parents = $(element).parents();
		return parents.length > 0 && parents[parents.length - 1].tagName == "HTML";
	},

	callHierarchyRemoved: function(element) {
		if (Tools.hasHTMLParent(element)) {
			Tools.traverseChildren(element, function() {
				if (this.onremove != null)
					this.onremove();
			});
		}
	},

	remove: function(element) {
		Tools.callHierarchyRemoved(element);
		$(element).remove();
	},

	addHierarchyListener: function(part_div, add_listener, remove_listener) {
		var listeners = part_div.hierarchylisteners;
		if (listeners == null) {
			listeners = [];
			part_div.hierarchylisteners = listeners;
		}
		listeners.push(
			{
				onadd : add_listener,
				onremove : remove_listener
			}
		);
		if (Tools.hasHTMLParent(part_div) && add_listener)
			add_listener();
	},

	traverseChildren: function(element, func) {
		var listeners = element.hierarchylisteners;
		if (listeners != null) {
			$.each(listeners, func);
		}
		$(element).children().each(function() {
			Tools.traverseChildren(this, func);
		});
	},
	createBoxFromBox: function(box, dx, dy) {
		return {x:box.x+dx, y:box.y+dy, width:box.width, height:box.height};
	},
	createBox: function(box, p) {
		var elem = document.createElement("div");
		Tools.setBox(elem, box);
		Tools.append(p, elem);
		return elem;
	},
	createBoxColor: function(color_string, box, p) {
		var color = Tools.createBox(box, p);
		$(color).css("background-color", color_string);
		return color;
	},
	createBoxImage: function(image_url, box, p) {
		var image = Tools.createBox(box, p);
		$(image).css("background", "url(" + Tools.toDownloadURL(image_url) + ") no-repeat");
		return image;
	},
	createImage: function(info) {
		var image = document.createElement("img");
		image.src = Tools.toDownloadURL(info.image_normal);
		Tools.setPos(image, info.image_x, info.image_y);
		return image;
	},

	createHoverImage: function(info, style) {
		var a = document.createElement("a");
		if (style) {
			$(a).addClass(style);
		}
		$(a).css("background-image", "url(" + Tools.toDownloadURL(info.image_normal) + ")");
		Tools.setPos(a, info.image_x, info.image_y);
		return a;
	},

	getColorMap: function() {
		var color_to_value = {};
		var colors = avatars.colors;
		for (var i = 0; i < colors.length; i++) {
			color_to_value[colors[i].name] = colors[i];
		}
		return color_to_value;
	},

	getGroupMap: function() {
		var name_to_group = {};
		var groups = avatars.color_groups;
		for (var i = 0; i < groups.length; i++) {
			var group = groups[i];
			name_to_group[group.name] = group;
		}
		return name_to_group;
	},

	getMissionMap: function() {
		var base_to_mission = {};
		var f = function() {
			base_to_mission[this.gamebase] = this;
		};
		jQuery.each(missions.multiplayer_maps, function() {
			jQuery.each(this.missions, f);
		});
		jQuery.each(missions.singleplayer_maps, function() {
			jQuery.each(this.missions, function() {
				jQuery.each(this.parts, f);
			});
		});
		return base_to_mission;
	},

	getPartMap: function() {
		var name_to_part = {};
		var parts = avatars.parts;
		for (var i = 0; i < parts.length; i++) {
			name_to_part[parts[i].name] = parts[i];
		}
		return name_to_part;
	},

	contractToURL: function(contract, user_id) {
	   return 'https://www.plimus.com/jsp/buynow.jsp?contractId=' + contract + '&custom1=' + user_id;
	},

	createTable: function(caption_text, head_labels, head_classes) {
		var table = document.createElement('table');
		var caption = document.createElement('caption');
		$(caption).text(caption_text);
		Tools.append(table, caption);
		if (head_labels) {
			var thead = document.createElement('thead');
			Tools.append(table, thead);
			var tr = document.createElement('tr');
			Tools.append(thead, tr);
			for (var i = 0; i < head_labels.length; i++) {
				var th = document.createElement('th');
				$(th).text(head_labels[i]);
				if (head_classes) {
					$(th).addClass(head_classes[i]);
				}
				Tools.append(tr, th);
			}
		}
		var tbody = document.createElement('tbody');
		Tools.append(table, tbody);
		return {table: table, tbody: tbody};
	},

	createBuy: function(user_id, cost_oddies, cost_points, disabled, buy_function) {
		return Tools.doCreateBuy(user_id, {oddies: cost_oddies, points: cost_points}, 'BUY IT', true, buy_function, disabled);
	},

	addHoverEffect: function(elem, image, image_height, info) {
		$(elem).css("background-image", "url(" + Tools.toDownloadURL(image) + ")");
		$(elem).css("background-attachment", "scroll");
		$(elem).css("background-color", "transparent");
		$(elem).css("background-repeat", "no-repeat");
		Tools.enableHoverEffect(elem, image_height, info);
	},

	enableHoverEffect: function(elem, image_height, info) {
		$(elem).unbind("mouseenter");
		$(elem).unbind("mouseleave");
		$(elem).css("cursor", "pointer");
		var mouse_leave = function() {
			$(elem).css("background-position", "0px 0px");
			if (info) {
				$(elem).css("color", info.color_normal);
			}
		};
		$(elem).bind("mouseenter", function() {
			$(elem).css("background-position", "0px -"+image_height+"px");
			if (info) {
				$(elem).css("color", info.color_active);
			}
		});
		$(elem).bind("mouseleave", mouse_leave);
		mouse_leave();
	},

	disableHoverEffect: function(elem, image_height) {
		$(elem).unbind("mouseenter");
		$(elem).unbind("mouseleave");
		$(elem).css("cursor", "default");
		$(elem).css("color", "#222");
		$(elem).css("background-position", "0px -"+image_height*2+"px");
	},

	doCreateBuy: function(user_id, cost, buy_button_msg, can_buy_unique, buy_function, disable_button) {
		var buy_button = document.createElement('div');
		$(buy_button).text(buy_button_msg);
		Tools.addHoverEffect(buy_button, "images/metal/metal_button_buy.png", town.armory_area_button_buy.height, theme.blue_button);
		$(buy_button).addClass("huge-button");
		Tools.hide(buy_button);
		return Tools.createCustomBuy(user_id, cost, can_buy_unique, function(can_buy) {
			Tools.show(buy_button);
			$(buy_button).unbind("click");
			if (can_buy && can_buy_unique && !disable_button) {
				$(buy_button).click(buy_function);
				Tools.enableHoverEffect(buy_button, town.armory_area_button_buy.height);
			} else {
				Tools.disableHoverEffect(buy_button, town.armory_area_button_buy.height);
			}
			return buy_button;
		});
	},

	setBox: function(elem, box) {
		Tools.setSize(elem, box.width, box.height);
		Tools.setPos(elem, box.x, box.y);
	},

	createCustomBuy: function(user_id, cost, can_buy_unique, buy_button_func) {
		var buy_messages = document.createElement('div');
		var button_container = document.createElement('div');
		var buy_listener = function(user) {
			var oddies = user.oddies;
			var points = user.points;
			var paying = user.paying;
			Tools.empty(buy_messages);
			var buy_button = buy_button_func(points >= cost.points && oddies >= cost.oddies && (!cost.paying || paying));
			if (buy_button)
				Tools.append(button_container, buy_button);
			if (can_buy_unique) {
				if (points < cost.points) {
					var insuf_elem = document.createElement('div');
					$(insuf_elem).addClass('insufficient');
					$(insuf_elem).text('Not enough points.');
					Tools.append(buy_messages, insuf_elem);
				}
				if (cost.paying && !paying) {
					var insuf_elem = document.createElement('div');
					$(insuf_elem).addClass('insufficient');
					$(insuf_elem).text("Only available for paying users.");
					var buy_more = Tools.createLink(' - buy (not trade) oddies in the ', 'bank', '', function() {
						Menu.navigate('bank');
					});
					Tools.append(insuf_elem, buy_more);
					Tools.append(buy_messages, insuf_elem);
				}
				if (oddies < cost.oddies) {
					var insuf_elem = document.createElement('div');
					$(insuf_elem).addClass('insufficient');
					$(insuf_elem).text('Not enough oddies.');
					var buy_more = Tools.createLink(' - buy more in the ', 'bank', '', function() {
						Menu.navigate('bank');
					});
					Tools.append(insuf_elem, buy_more);
					Tools.append(buy_messages, insuf_elem);
				}
			} else {
				var insuf_elem = document.createElement('div');
				$(insuf_elem).addClass('insufficient');
				$(insuf_elem).text('You already own this item.');
				Tools.append(buy_messages, insuf_elem);
			}
//var kids = $(buy_messages).children();
//var len = kids.addClass("hilite").length;
//console.log(len + " children");
		};
		Tools.addEntityListener(buy_messages, user_id, buy_listener);
		return {"messages": buy_messages, "button": button_container};
	},

	getGender: function(user_id) {
	    return EntityListeners.getEntity(user_id).gender;
	},
	createPriceElement: function(oddies, points) {
		var price_elem = document.createElement('div');
		$(price_elem).addClass('price');
		var text_elem = document.createElement('span');
		$(text_elem).text("Price:");
		Tools.append(price_elem, text_elem);
		var oddies_elem = document.createElement('span');
		$(oddies_elem).addClass('oddies');
		$(oddies_elem).text(oddies);
		Tools.append(price_elem, oddies_elem);
		var points_elem = document.createElement('span');
		$(points_elem).addClass('points');
		$(points_elem).text(points);
		Tools.append(price_elem, points_elem);
		return price_elem;
	},
	showItem: function(listener_elem, user_id, item, show_func, remove_func) {
		if (item.depends != null) {
			Tools.addEntityListener(listener_elem, user_id, function(user) {
				if (jQuery.inArray(item.depends, user.bought_items) == -1) {
					remove_func();
				} else {
					show_func();
				}
			});
		} else {
			show_func();
		}
	},
	createColorChooser: function(color_to_value, default_color, group, offset_y, color_func) {
		var root = document.createElement('div');
		var color_group_elem;
		var click_group_elem;
		var elem_width = town.palette_swatch_highlight_area.width;
		var elem_height = town.palette_swatch_highlight_area.height;
		if (group.values.length == 8) {
			var offset_box_frame = Tools.createBoxFromBox(town.palette_8_area, 0, offset_y);
			var offset_box_swatchs = Tools.createBoxFromBox(town.palette_8_swatch_area, 0, offset_y);
			color_group_elem = Tools.createBox(offset_box_swatchs, root);
			Tools.createBoxImage("images/town/palette_8.png", offset_box_frame, root);
			click_group_elem = Tools.createBox(offset_box_swatchs, root);
		} else {
			var offset_box_frame = Tools.createBoxFromBox(town.palette_24_area, 0, offset_y);
			var offset_box_swatchs = Tools.createBoxFromBox(town.palette_24_swatch_area, 0, offset_y);
			color_group_elem = Tools.createBox(offset_box_swatchs, root);
			Tools.createBoxImage("images/town/palette_24.png", offset_box_frame, root);
			click_group_elem = Tools.createBox(offset_box_swatchs, root);
		}
		for (var i = 0; i < group.values.length; i++) {
			(function() {
			var color = group.values[i];
			var value = color_to_value[color].value;
			var val_elem = document.createElement('div');
			Tools.setSize(val_elem, elem_width, elem_height);
			$(val_elem).addClass('color-block');
			$(val_elem).css('background-color', 'rgb(' + value[0] + ',' + value[1] + ',' + value[2] + ')');
			Tools.append(color_group_elem, val_elem);

			var val_elem_click = document.createElement('div');
			Tools.setSize(val_elem_click, elem_width, elem_height);
			$(val_elem_click).addClass('color-block');
			Tools.append(click_group_elem, val_elem_click);
			$(val_elem_click).mousedown(function() {
				color_func(group, color);
			});
			if (color == default_color) {
				var val_elem_highlight = Tools.createBoxImage("images/town/palette_swatch_highlight.png", town.palette_swatch_highlight_area, val_elem_click);
				$(val_elem_highlight).css({position:"relative", left:"0px", top:"0px"});
			}
			})();
		}
		Tools.append(color_group_elem, Tools.createClearElement());
		return root;
	}
}
