function UserList(){
	this.users = {};
}

UserList.prototype = new EventEmitter();

UserList.prototype.newMessage = function(msg){
	var a = msg.action,
	me = this;
	
	if(a == "join"){
		$.extend(me.users, msg.users);
		me.emit('join', msg.users);
		
	} else if(a == "part"){
		var users = me.users;
		$.each(msg.users, function(id, user){if(users[id]) delete users[id]});
		me.emit('part', msg.users);
		
	} else if(a == "who"){
		me.users = msg.users || {};
		me.emit('who', me.users);
		
	} else if(a == "batch"){
		$.each(msg.messages, function(msg){
			me.newMessage(msg);
		});
	}
}

// iteration must halt when f returns false
UserList.prototype.each = function(f){
	$.each(this.users,f);	
}

function UserListUI(ul, container, top){
	if(!ul) return;
	var user_divs = {},
	self = this,
	// Single Anonymous user for the userlist
	anonymous = {el: null, count:0},
	sorted = [];
	
	ul.on('join', function(users){
		$.each(users, function(id, user){
			user.id = id;
			addUser(user);
		});
		updateUserCount();
	});

	ul.on('part', function(users){
		$.each(users, function(id, user){
			user.id = id;
			if(id == 'anonymous')
				removeAnonymous(user);
			else
				removeUser(user);
		});
		updateUserCount();
	});
	
	ul.on('who', function(users){
		clearUserList();
		$.each(users, function(id, user){
			user.id = id;
			addUser(user);
		});
		updateUserCount();
	});
	
	function addUser(user){
		if(user.id == 'anonymous') return addAnonymous(user);
		
		if(user_divs[user.id]) return;
		
		var name_div = user.el = $('<a>');
		name_div.attr({
			id:'user_' + user.id,
			title: user.name,
			href: '/users/' + user.id,
			target: "_blank",
			style: 'color:' + UI.Colors.forUser(user.id) + ';',
			'class': 'user'
		});
		name_div.text(user.name);

		var insert_after = addToSortedList(user);
		if(insert_after)
			insert_after.el.after(name_div);
		else
			container.prepend(name_div);
		user_divs[user.id] = name_div;
		
		self.emit('new_user', user, name_div);
	}
	
	function addAnonymous(user){
		var a = anonymous;
		if(!a.el){
			a.el = $('<div>');
			a.id = user.id;
			user_divs[a.id] = a.el;
			a.el.attr({
				'class': 'user anon'
			});
			a.count = 0;
			top.prepend(a.el);
		}
		
		a.count += user.count;
		
		a.el.text("Anonymous ("+ a.count +")");
	}
	
	function removeAnonymous(user){
		var a = anonymous;
		if(!a.el) return;

		a.count -= user.count;
	
		if(a.count <= 0){
			removeUser(a);
			a.el = null;
			a.count = 0;
		}else{
			a.el.text("Anonymous ("+ a.count +")");
		}
	}
	
	function addToSortedList(user){
		sorted.push(user);
		sorted.sort(function(a,b){
			return a.name.localeCompare(b.name);
		});
		var i=sorted.indexOf(user);
		return i > 0 ? sorted[i-1] : null;
	}
	
	function removeUser(user){
		if(user_divs[user.id]){
			user_divs[user.id].remove();
			sorted = sorted.filter(function(each){
				return user.id != each.id;
			});
			delete user_divs[user.id];
		}
	}
	
	function clearUserList(){
		for(var i in user_divs){
			user_divs[i].remove();
		}
		anonymous.el = null;
		user_divs = {};
		sorted = [];
	}
	
	function updateUserCount(){
		$('#user_count').text('(' + (sorted.length + anonymous.count) + ')');
	}
}

Util.inherits(UserListUI, EventEmitter);

@@ -1512,24 +1512,45 @@
  = user.el =
+ $('%3Cdiv%3E'),%0A%09%09link =
  $('%3Ca%3E');%0A%09
@@ -1548,16 +1548,19 @@
 '%3Ca%3E');%0A
+%09%09%0A
 %09%09name_d
@@ -1590,24 +1590,91 @@
  + user.id,%0A
+%09%09%09'class': 'user'%0A%09%09%7D);%0A%09%09name_div.append(link);%0A%09%09%0A%09%09link.attr(%7B%0A
 %09%09%09title: us
@@ -1786,36 +1786,16 @@
 d) + ';'
-,%0A%09%09%09'class': 'user'
 %0A%09%09%7D);%0A%09
@@ -1795,24 +1795,20 @@
 %09%09%7D);%0A%09%09
-name_div
+link
 .text(us
@@ -1817,16 +1817,18 @@
 .name);%0A
+%09%09
 %0A%09%09var i

Make user list contain divs instead of anchor tags