function copyOption(sourceSelect, targetSelect, keepLabel) {
    var sourceOptions = sourceSelect.options;    
    var canMove;
    var option;
    
    // find which ones are selected...
    var selectedIds = new Array ();
    var index = 0;
    for (var i = 0; i < sourceSelect.length; i++) {
        option = sourceOptions[i];
        if (option.selected) {
            canMove = (option.text != keepLabel);
            if (canMove) {
                // make sure we don't move any options that are already there
                for (var j = 0; j < targetSelect.length; j++) {
                    if (targetSelect[j].value == option.value) {
                        canMove = false;
                        break;
                    }
                }
            }

            // if this option can be moved we add it to our array of elements to move
            if (canMove) {
                selectedIds[index] = i;
                index++;
            } else {
                // if we can't move this option, then unselect it
                option.selected = false;
            }
        }
    }

    // move them over one by one
    var targetOptions = targetSelect.options;
    if (selectedIds.length > 0) {
        targetSelect.selectedIndex = -1;
        for (var i = 0; i < selectedIds.length; i++) {
            option = new Option(sourceOptions[selectedIds[i]].text, sourceOptions[selectedIds[i]].value);
            
            // replace the target value if its the last one
            if (targetOptions.length == 1 && targetOptions[0].text == keepLabel) {
                targetOptions[0] = option;
//                targetOptions[0].selected = true;
            } else {
                targetOptions[targetOptions.length] = option;
//                targetOptions[targetOptions.length-1].selected = true;
            }
        }
    }

    // notify the Select Elements that their contents have changed
    if (targetSelect["onchange"]) {
        targetSelect.onchange();
    }   
}

function removeOption(sourceSelect, keepLabel) {
    var sourceOptions = sourceSelect.options;    
    var canMove;
    var option;
    
    // find which ones are selected...
    var selectedIds = new Array ();
    var index = 0;
    for (var i = 0; i < sourceSelect.length; i++) {
        option = sourceOptions[i];
        if (option.selected) {
            canMove = (option.text != keepLabel);
						
            // if this option can be moved we add it to our array of elements to move
            if (canMove) {
                selectedIds[index] = i;
                index++;
            } else {
                // if we can't move this option, then unselect it
                option.selected = false;
            }
        }
    }
   
		// remove selected values from the source, starting with the last one selected
    for (var i = selectedIds.length - 1; i > -1; i--) {
        sourceSelect.remove(selectedIds[i]);
    }

    // Workaround here for a bug in IE:
    // If you have a select element with many values, and you've scrolled to 
    // the bottom and move an option from the top-most element you can now see,
    // IE would not refresh the select element, leaving a hole in the list. 
    // By forcing the select element disabled and back, it seems to refresh the
    // element properly.
    sourceSelect.disabled = true;
    sourceSelect.disabled = false;

    // make sure we don't get an empty list
    if (sourceOptions.length == 0) {
        sourceOptions[0] = new Option (keepLabel, '');
    }
}


function moveOption (sourceSelect, targetSelect, 
                     keepSourceLabel, unmovableSourceValues, 
                     keepTargetLabel) {

    var sourceOptions = sourceSelect.options;
    
    var canMove;
    var option;
    
    // find which ones are selected...
    var selectedIds = new Array ();
    var index = 0;
    for (var i = 0; i < sourceSelect.length; i++) {
        option = sourceOptions[i];
        if (option.selected) {
            canMove = (option.text != keepSourceLabel);
            if (canMove && unmovableSourceValues != null) {
                // make sure we don't move any options defined as unmovable
                for (var j = 0; j < unmovableSourceValues.length; j++) {
                    if (unmovableSourceValues[j] == option.value) {
                        canMove = false;
                        break;
                    }
                }
            }

            // if this option can be moved we add it to our array of elements to move
            if (canMove) {
                selectedIds[index] = i;
                index++;
            } else {
                // if we can't move this option, then unselect it
                option.selected = false;
            }
        }
    }

    // move them over one by one
    var targetOptions = targetSelect.options;
    if (selectedIds.length > 0) {
        targetSelect.selectedIndex = -1;
        for (var i = 0; i < selectedIds.length; i++) {
            option = new Option (sourceOptions[selectedIds[i]].text, sourceOptions[selectedIds[i]].value);
            
            // replace the target value if its the last one
            if (targetOptions.length == 1 && targetOptions[0].text == keepTargetLabel) {
                targetOptions[0] = option;
//                targetOptions[0].selected = true;
            } else {
                targetOptions[targetOptions.length] = option;
//                targetOptions[targetOptions.length-1].selected = true;
            }
        }
    }

    // notify the Select Elements that their contents have changed
    if (targetSelect["onchange"]) {
        targetSelect.onchange();
    }
    if (sourceSelect["onchange"]) {
        sourceSelect.onchange();
    }

    // remove selected values from the source, starting with the last one selected
    for (var i = selectedIds.length - 1; i > -1; i--) {
        sourceSelect.remove(selectedIds[i]);
    }

    // Workaround here for a bug in IE:
    // If you have a select element with many values, and you've scrolled to 
    // the bottom and move an option from the top-most element you can now see,
    // IE would not refresh the select element, leaving a hole in the list. 
    // By forcing the select element disabled and back, it seems to refresh the
    // element properly.
    sourceSelect.disabled = true;
    sourceSelect.disabled = false;

    // make sure we don't get an empty list
    if (sourceOptions.length == 0) {
        sourceOptions[0] = new Option (keepSourceLabel, keepSourceLabel);
    }

    // if we moved anything, put the focus on the target list box
    if (selectedIds.length > 0) targetSelect.focus ();
}

function moveAll (sourceSelect, targetSelect, 
                     keepSourceLabel, unmovableSourceValues, 
                     keepTargetLabel) {

    var sourceOptions = sourceSelect.options;
    
    var canMove;
    var option;
    
    // find which ones are selected...
    var selectedIds = new Array ();
    var index = 0;
    for (var i = 0; i < sourceSelect.length; i++) {
       	 option = sourceOptions[i];

         canMove = (option.text != keepSourceLabel);
         if (canMove && unmovableSourceValues != null) {
             // make sure we don't move any options defined as unmovable
             for (var j = 0; j < unmovableSourceValues.length; j++) {
                 if (unmovableSourceValues[j] == option.value) {
                     canMove = false;
                     break;
                 }
             }
         }

         // if this option can be moved we add it to our array of elements to move
         if (canMove) {
             selectedIds[index] = i;
             index++;
         } else {
             // if we can't move this option, then unselect it
             option.selected = false;
         }
    }

    // move them over one by one
    var targetOptions = targetSelect.options;
    if (selectedIds.length > 0) {
        targetSelect.selectedIndex = -1;
        for (var i = 0; i < selectedIds.length; i++) {
            option = new Option (sourceOptions[selectedIds[i]].text, sourceOptions[selectedIds[i]].value);
            
            // replace the target value if its the last one
            if (targetOptions.length == 1 && targetOptions[0].text == keepTargetLabel) {
                targetOptions[0] = option;
//                targetOptions[0].selected = true;
            } else {
                targetOptions[targetOptions.length] = option;
//                targetOptions[targetOptions.length-1].selected = true;
            }
        }
    }

    // notify the Select Elements that their contents have changed
    if (targetSelect["onchange"]) {
        targetSelect.onchange();
    }
    if (sourceSelect["onchange"]) {
        sourceSelect.onchange();
    }

    // remove selected values from the source, starting with the last one selected
    for (var i = selectedIds.length - 1; i > -1; i--) {
        sourceSelect.remove(selectedIds[i]);
    }

    // Workaround here for a bug in IE:
    // If you have a select element with many values, and you've scrolled to 
    // the bottom and move an option from the top-most element you can now see,
    // IE would not refresh the select element, leaving a hole in the list. 
    // By forcing the select element disabled and back, it seems to refresh the
    // element properly.
    sourceSelect.disabled = true;
    sourceSelect.disabled = false;

    // make sure we don't get an empty list
    if (sourceOptions.length == 0) {
        sourceOptions[0] = new Option (keepSourceLabel, keepSourceLabel);
    }

    // if we moved anything, put the focus on the target list box
    if (selectedIds.length > 0) targetSelect.focus ();
}

function saveAllSelected (fromSelectArray, toArray, delim, escape, emptyLabel) {
    var i,j,escapedValue;
    // loop through all the select elements
    for (i = 0; i < fromSelectArray.length; i++) {
        toArray[i].value = ''; // clear out the value to start
        // now loop through all the values in the select element
        for (j = 0; j < fromSelectArray[i].length; j++) {
            // copy over the value as long as it is not the emptyLabel
            if (!(fromSelectArray[i].length == 1 && fromSelectArray[i].options[0].value == emptyLabel)) {
                toArray[i].value += fromSelectArray[i].options[j].value.replace(new RegExp(delim,"g"), escape+delim);
            }

            // add the delimiter (except after the last one)
            if (j + 1 < fromSelectArray[i].length) {
                toArray[i].value += delim;
            }
        }
    }
}