docs: function (ki, key, value, index, literal) {
  		// ki is the key information from _find_key
  		var i, value_hash, vhash_val, info,
  			key_index = ki.i, // where the key is in the hash array
  			hash_values = ki.hv, // the hash array
  			hash = ki.h; // the hash value
  
  		if (key_index >= 0) { // The key was already in this map
  			// get the information
  			info = hash_values[key_index];
  
  			if (this._vhash) { // If we're hashing values, the new value has to get re-hashed
  				var old_value = info.value.get(),
  					old_value_hash = this._valuehash(old_value),
  					old_vhash_val = this._vhash[old_value_hash];
  				value_hash = this._valuehash(value);
  
  				if (old_vhash_val) { // This should probably always be true, unless something went wrong...
  					var len = old_vhash_val.length;
  					for (i = 0; i < len; i += 1) {
  						if (old_vhash_val[i] === info) { // wohoo, found it
  							old_vhash_val.splice(i, 1);
  							if (old_vhash_val.length === 0) {
  								delete this._vhash[old_value_hash]; // don't keep the old hash array
  							}
  							break;
  						}
  					}
  				}
  
  				// Put the new value has in
  				vhash_val = this._vhash[value_hash]; // hash array
  				if (vhash_val) {
  					vhash_val.push(info); // add onto the hash array
  				} else {
  					this._vhash[value_hash] = [info]; // create a new hash array
  				}
  			}
  
  			info.value.set(value); // set the value constraint to the new value
  
  			if (isPositiveInteger(index)) { // But they also specified an index...
  				var old_index = info.index.get();
  				if(old_index !== index) { // great...now we have to move it too
  					// take out the old value
  					this._ordered_values.splice(old_index, 1);
  					// and re-add it
  					this._ordered_values.splice(index, 0, info);
  
  					// Properly iterate regardless of whether moving higher or lower
  					var low = Math.min(old_index, index);
  					var high = Math.max(old_index, index);
  					// update the indicies of every thing between that might have been affected
  					for (i = low; i <= high; i += 1) {
  						_set_index(this._ordered_values[i], i);
  					}
  					this.$keys.invalidate(); // Keys are now invalid
  				}
  			}
  		} else {
  			// They didn't specify an index or at least they specified it wrong...
  			if (!isPositiveInteger(index)) {
  				index = this._ordered_values.length; // just set it to the 
  			}
  			// Check to see if there was an unsubstantiated item
  			var unsubstantiated_index = ki.ui;
  
  			if (unsubstantiated_index >= 0) { // Found it! Now let's remove it from the list of unsubstantiated items
  				var unsubstantiated_hash_values = ki.uhv,
  					unsubstantiated_info = unsubstantiated_hash_values[unsubstantiated_index];
  
  				unsubstantiated_hash_values.splice(unsubstantiated_index, 1);
  				if (unsubstantiated_hash_values.length === 0) {
  					delete this._unsubstantiated_values[hash];
  				}
  
  				info = unsubstantiated_info; // re-use the same object to keep dependencies
  			} else {
  				// Nothing in unsubstantiated; just create it from scratch
  				info = {
  					key: new Constraint(key, {literal: true}),
  					value: new Constraint(value, {literal: literal === undefined ? this._default_literal_values : !!literal}),
  					index: new Constraint(index, {literal: true})
  				};
  			}
  
  			if(hash_values) { // There was already a hash array
  				hash_values.push(info);
  			} else { // Have to create the hash array
  				hash_values = this._khash[hash] = [info];
  			}
  
  			//If we're hashing values...
  			if (this._vhash) {
  				value_hash = this._valuehash(value);
  				vhash_val = this._vhash[value_hash];
  				// Add the item to the value hash
  				if (vhash_val) {
  					vhash_val.push(info);
  				} else {
  					this._vhash[value_hash] = [info];
  				}
  			}
  
  			//  insert into values
  			this._ordered_values.splice(index, 0, info);
  
  			if (unsubstantiated_index >= 0) {
  				info.value.set(value); // but update its value and index
  				info.index.set(index);
  			}
  
  			// Push the index of every item that I spliced before up
  			for (i = index + 1; i < this._ordered_values.length; i += 1) {
  				_set_index(this._ordered_values[i], i);
  			}
  			// Now, size and keys are invalid
  			this.$size.invalidate();
  			this.$keys.invalidate();
  		}
  		this.$values.invalidate();
  		this.$entries.invalidate();
  	}