docs: function (words) {
      var i, tmp, a, b,
        w = words.slice(0),
        h = this._h,
        k = this._key,
        h0 = h[0], h1 = h[1], h2 = h[2], h3 = h[3],
        h4 = h[4], h5 = h[5], h6 = h[6], h7 = h[7];
  
      /* Rationale for placement of |0 :
       * If a value can overflow is original 32 bits by a factor of more than a few
       * million (2^23 ish), there is a possibility that it might overflow the
       * 53-bit mantissa and lose precision.
       *
       * To avoid this, we clamp back to 32 bits by |'ing with 0 on any value that
       * propagates around the loop, and on the hash state h[].  I don't believe
       * that the clamps on h4 and on h0 are strictly necessary, but it's close
       * (for h4 anyway), and better safe than sorry.
       *
       * The clamps on h[] are necessary for the output to be correct even in the
       * common case and for short inputs.
       */
      for (i=0; i<64; i++) {
        // load up the input word for this round
        if (i<16) {
          tmp = w[i];
        } else {
          a   = w[(i+1 ) & 15];
          b   = w[(i+14) & 15];
          tmp = w[i&15] = ((a>>>7  ^ a>>>18 ^ a>>>3  ^ a<<25 ^ a<<14) +
                           (b>>>17 ^ b>>>19 ^ b>>>10 ^ b<<15 ^ b<<13) +
                           w[i&15] + w[(i+9) & 15]) | 0;
        }
  
        tmp = (tmp + h7 + (h4>>>6 ^ h4>>>11 ^ h4>>>25 ^ h4<<26 ^ h4<<21 ^ h4<<7) +  (h6 ^ h4&(h5^h6)) + k[i]); // | 0;
  
        // shift register
        h7 = h6; h6 = h5; h5 = h4;
        h4 = h3 + tmp | 0;
        h3 = h2; h2 = h1; h1 = h0;
  
        h0 = (tmp +  ((h1&h2) ^ (h3&(h1^h2))) + (h1>>>2 ^ h1>>>13 ^ h1>>>22 ^ h1<<30 ^ h1<<19 ^ h1<<10)) | 0;
      }
  
      h[0] = h[0]+h0 | 0;
      h[1] = h[1]+h1 | 0;
      h[2] = h[2]+h2 | 0;
      h[3] = h[3]+h3 | 0;
      h[4] = h[4]+h4 | 0;
      h[5] = h[5]+h5 | 0;
      h[6] = h[6]+h6 | 0;
      h[7] = h[7]+h7 | 0;
    }