function HashTable(a, b) {
  this._storage = [];
  this._limit = 8; 
  this._size = 0;  
}
HashTable.prototype.insert = function(key, value) {
  const index = hash(key, this._limit);
  const oldSize = this._size;
  
  if (!this._storage[index]) {
    this._storage[index] = [[key, value]];
    this._size++;
  } else {
    let hasKey = false;
    const bucket = this._storage[index];
    for (let i = 0; i < bucket.length; i++) {
      const [entryKey, entryValue] = bucket[i];
      if (entryKey === key) {
        hasKey = true;
        bucket[i][1] = value;
      }
    }
    
    if (!hasKey) {
      bucket.push([key, value]);
      this._size++;
    }
  }
  
  if (this._size !== oldSize && this._size > this._limit * 0.75) {
    this._resize(this._limit * 2);    
  }
};
HashTable.prototype.remove = function(key) {
  const index = hash(key, this._limit);
  const bucket = this._storage[index];
  let entryIndex = -1;
  
  
  if (!bucket) return false;
  
  for (let i = 0; i < bucket.length; i++) {
    const [entryKey, entryValue] = bucket[i];
    if (entryKey === key) {
      entryIndex = i;
    }
  }
  
  bucket.splice(entryIndex, 1);
  this._size--;
  if (this._size < 0.25 * this._limit) {
    this._resize(Math.floor(this._limit / 2));
  }
};
HashTable.prototype.retrieve = function(key) {
  const index = hash(key, this._limit);
  
  if (!this._storage[index]) return undefined;
  
  const bucket = this._storage[index];
  let result;
  
  bucket.forEach((entry) => {
    [entryKey, entryValue] = entry;
    if (entryKey === key) {
      result = entryValue; 
    }
  });
  
  return result;
  
};
HashTable.prototype._resize = function(newLimit) {
  const oldStorage = this._storage;
  
  newLimit = Math.max(newLimit, 8); 
  if (newLimit === this._limit) return;
  
  this._limit = newLimit;
  this._size = 0;
  this._storage = [];
  
  oldStorage.forEach(bucket => {
    if (!bucket) return;
    for (let i = 0; i < bucket.length; i++) {
      const [key, value] = bucket[i];
      this.insert(key, value);
    }
  });
};
function hash(string, max) {
  let ret, i;
  for(ret = 0, i = 0, len = string.length; i < len; i++) {
    ret = (31 * ret + string.charCodeAt(i)) << 0;
  }
  return ret % max; 
}