$.fn.multiSelect = function(to, options) {
	// support v0.1 syntax
	if (typeof options == "string")
		options = {trigger: "#"+options};
	
	options = $.extend({
		trigger: null,     // selector of elements whose 'click' event should invoke a move
		autoSubmit: true,  // true => select all child <option>s on parent form submit (if any)
		beforeMove: null,  // before move callback function
		afterMove: null    // after move callback
	}, options);

	// for closures
	var $select = this;
	
	// make form submission select child <option>s
	if (options.autoSubmit)
		this.parents("form").submit(function() { selectChildOptions($select); });
	

	// create the closure
	var moveFunction = function() { moveOptions($select, to, options.beforeMove, options.afterMove); };
	
	// attach double-click behaviour
	this.dblclick(moveFunction);
	
	// trigger element behaviour
	if (options.trigger)
		jQuery(options.trigger).click(moveFunction);
	
	return this;

   
	// moves the options
	function moveOptions(from, toSel, beforeMove, afterMove) {
      if (beforeMove && !beforeMove())
			return;
		
		jQuery("option:selected", from).each(function() {
         jQuery(this)
            .attr("selected", false)
            .appendTo(toSel);
      });
		
		afterMove && afterMove();
   }
	
	
	// selects all child options
	function selectChildOptions($select) {
		$select.children("option").each(function() {
			this.selected = true;
		});
	}
};

$.fn.sortOptions = function(ascending)
{
	this.each(
		function()
		{
			if(this.nodeName.toLowerCase() != "select") return;
			// default sort is ascending if parameter is undefined
			ascending = typeof ascending == "undefined" ? true : ascending;
			// get number of options
			var optionsLength = this.options.length;
			// create an array for sorting
			var sortArray = [];
			// loop through options, adding to sort array
			for(var i = 0; i<optionsLength; i++)
			{
				sortArray[i] =
				{
					value: this.options[i].value,
					text: this.options[i].text
				};
			}
			// sort items in array
			sortArray.sort(
				function(option1, option2)
				{
					// option text is made lowercase for case insensitive sorting
					option1text = option1.text.toLowerCase();
					option2text = option2.text.toLowerCase();
					// if options are the same, no sorting is needed
					if(option1text == option2text) return 0;
					if(ascending)
					{
						return option1text < option2text ? -1 : 1;
					}
					else
					{
						return option1text > option2text ? -1 : 1;
					}
				}
			);
			// change the options to match the sort array
			for(var i = 0; i<optionsLength; i++)
			{
				this.options[i].text = sortArray[i].text;
				this.options[i].value = sortArray[i].value;
			}
		}
	)
	return this;
}