text: var u = require('./util')
  var write = u.write
  var fill = u.zeroFill
  
  module.exports = function (Buffer) {
  
    //prototype class for hash functions
    function Hash (blockSize, finalSize) {
      this._block = new Buffer(blockSize) //new Uint32Array(blockSize/4)
      this._finalSize = finalSize
      this._blockSize = blockSize
      this._len = 0
      this._s = 0
    }
  
    Hash.prototype.init = function () {
      this._s = 0
      this._len = 0
    }
  
    function lengthOf(data, enc) {
      if(enc == null)     return data.byteLength || data.length
      if(enc == 'ascii' || enc == 'binary')  return data.length
      if(enc == 'hex')    return data.length/2
      if(enc == 'base64') return data.length/3
    }
  
    Hash.prototype.update = function (data, enc) {
      var bl = this._blockSize
  
      //I'd rather do this with a streaming encoder, like the opposite of
      //http://nodejs.org/api/string_decoder.html
      var length
        if(!enc && 'string' === typeof data)
          enc = 'utf8'
  
      if(enc) {
        if(enc === 'utf-8')
          enc = 'utf8'
  
        if(enc === 'base64' || enc === 'utf8')
          data = new Buffer(data, enc), enc = null
  
        length = lengthOf(data, enc)
      } else
        length = data.byteLength || data.length
  
      var l = this._len += length
      var s = this._s = (this._s || 0)
      var f = 0
      var buffer = this._block
      while(s < l) {
        var t = Math.min(length, f + bl - s%bl)
        write(buffer, data, enc, s%bl, f, t)
        var ch = (t - f);
        s += ch; f += ch
  
        if(!(s%bl))
          this._update(buffer)
      }
      this._s = s
  
      return this
  
    }
  
    Hash.prototype.digest = function (enc) {
      var bl = this._blockSize
      var fl = this._finalSize
      var len = this._len*8
  
      var x = this._block
  
      var bits = len % (bl*8)
  
      //add end marker, so that appending 0's creats a different hash.
      x[this._len % bl] = 0x80
      fill(this._block, this._len % bl + 1)
  
      if(bits >= fl*8) {
        this._update(this._block)
        u.zeroFill(this._block, 0)
      }
  
      //TODO: handle case where the bit length is > Math.pow(2, 29)
      x.writeInt32BE(len, fl + 4) //big endian
  
      var hash = this._update(this._block) || this._hash()
      if(enc == null) return hash
      return hash.toString(enc)
    }
  
    Hash.prototype._update = function () {
      throw new Error('_update must be implemented by subclass')
    }
  
    return Hash
  }
  