 /****************************************************************************
  * Code from comp.lang.javascript and (c) Michael Winter:
  * http://groups-beta.google.com/group/comp.lang.javascript/msg3f287a2f20de1b10
  ***************************************************************************/
var Hashtable = (function() {
    var prefix = ' $';
    function isNull(object) {return !object && ('object' == typeof object);}
    function isNumber(object) {return 'number' == typeof object;}
    function isUndefined(object) {return 'undefined' == typeof object;}
    function Element(key, value) {
        this.key = key;
        this.value = value;
        this.next = null;
    }
    function Hashtable() {
        var table = {data : []},
            entries = 0;
        this.get = function(key) {var index, tableData = table.data;
            if(!isNull(key) && !isUndefined(key)
             && isNumber(index = table[prefix + key]))
            {
                var node = tableData[index];
                while(node && (node.key !== key)) {node = node.next;}
                if(node) {return node.value;}
            }
        };
        this.put = function(key, value) {var index, prefixedKey, tableData =table.data;
            if(isNull(key) || isUndefined(key) || isUndefined(value)) {return;}
            if(isNumber(index = table[prefixedKey = prefix + key])) {
                var node = tableData[index], previousNode = null;
                while(node && (node.key !== key)) {
                    previousNode = node;
                    node = node.next;
                }
                if(node) {
                    var oldValue = node.value;
                    node.value = value;
                    return oldValue;
                } else {
                    previousNode.next = new Element(key, value);
                }
            }
            else {
                table[prefixedKey] = tableData.length;
                tableData[tableData.length] = new Element(key, value);
            }
            ++entries;
        };
        this.remove = function(key) {var index, prefixedKey, tableData = table.data;
            if(!isNull(key) && !isUndefined(key)
             && isNumber(index = table[prefixedKey = prefix + key]))
            {
                var node = tableData[index], previousNode = null, returnValue;
                while(node && (node.key !== key)) {
                    previousNode = node;
                    node = node.next;
                }
                if(!node) {return;}
                returnValue = node.value;
                if(previousNode) {previousNode.next = node.next;}
                else {tableData[index] = node.next;}
                if(!tableData[index]) {
                    for(var length = tableData.length - 1; index < length; ++index) {
                        tableData[index] = tableData[index + 1];
                        --table[prefix + tableData[index].key];
                    }
                    delete tableData[index];
                    delete table[prefixedKey];
                }
                --entries;
                return returnValue;
            }
        };
    }
    Hashtable.prototype.containsKey = function(key) {
        return !isUndefined(this.get(key));
    };
    return Hashtable;
})();
