docs: function(options) {
        /**
         * Private config properties. You may need to tweak these to be compatible with
         * the server-side, but the defaults work in most cases.
         * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
         */
        var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
          b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
          utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
  
        // public methods
        this.hex = function(s) {
          return rstr2hex(rstr(s, utf8), hexcase);
        };
        this.b64 = function(s) {
          return rstr2b64(rstr(s, utf8), b64pad);
        };
        this.any = function(s, e) {
          return rstr2any(rstr(s, utf8), e);
        };
        this.raw = function(s) {
          return rstr(s, utf8);
        };
        this.hex_hmac = function(k, d) {
          return rstr2hex(rstr_hmac(k, d));
        };
        this.b64_hmac = function(k, d) {
          return rstr2b64(rstr_hmac(k, d), b64pad);
        };
        this.any_hmac = function(k, d, e) {
          return rstr2any(rstr_hmac(k, d), e);
        };
        /**
         * Perform a simple self-test to see if the VM is working
         * @return {String} Hexadecimal hash sample
         * @public
         */
        this.vm_test = function() {
          return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
        };
        /**
         * @description Enable/disable uppercase hexadecimal returned string
         * @param {boolean}
         * @return {Object} this
         * @public
         */
        this.setUpperCase = function(a) {
          if (typeof a === 'boolean') {
            hexcase = a;
          }
          return this;
        };
        /**
         * @description Defines a base64 pad string
         * @param {string} Pad
         * @return {Object} this
         * @public
         */
        this.setPad = function(a) {
          b64pad = a || b64pad;
          return this;
        };
        /**
         * @description Defines a base64 pad string
         * @param {boolean}
         * @return {Object} this
         * @public
         */
        this.setUTF8 = function(a) {
          if (typeof a === 'boolean') {
            utf8 = a;
          }
          return this;
        };
  
        // private methods
  
        /**
         * Calculate the SHA-512 of a raw string
         */
  
        function rstr(s) {
          s = (utf8) ? utf8Encode(s) : s;
          return binb2rstr(binb(rstr2binb(s), s.length * 8));
        }
  
        /**
         * Calculate the HMAC-SHA1 of a key and some data (raw strings)
         */
  
        function rstr_hmac(key, data) {
          var bkey, ipad, opad, i, hash;
          key = (utf8) ? utf8Encode(key) : key;
          data = (utf8) ? utf8Encode(data) : data;
          bkey = rstr2binb(key);
  
          if (bkey.length > 16) {
            bkey = binb(bkey, key.length * 8);
          }
          ipad = Array(16), opad = Array(16);
          for (i = 0; i < 16; i += 1) {
            ipad[i] = bkey[i] ^ 0x36363636;
            opad[i] = bkey[i] ^ 0x5C5C5C5C;
          }
          hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
          return binb2rstr(binb(opad.concat(hash), 512 + 160));
        }
  
        /**
         * Calculate the SHA-1 of an array of big-endian words, and a bit length
         */
  
        function binb(x, len) {
          var i, j, t, olda, oldb, oldc, oldd, olde,
            w = Array(80),
            a = 1732584193,
            b = -271733879,
            c = -1732584194,
            d = 271733878,
            e = -1009589776;
  
          /* append padding */
          x[len >> 5] |= 0x80 << (24 - len % 32);
          x[((len + 64 >> 9) << 4) + 15] = len;
  
          for (i = 0; i < x.length; i += 16) {
            olda = a;
            oldb = b;
            oldc = c;
            oldd = d;
            olde = e;
  
            for (j = 0; j < 80; j += 1) {
              if (j < 16) {
                w[j] = x[i + j];
              } else {
                w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
              }
              t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
                safe_add(safe_add(e, w[j]), sha1_kt(j)));
              e = d;
              d = c;
              c = bit_rol(b, 30);
              b = a;
              a = t;
            }
  
            a = safe_add(a, olda);
            b = safe_add(b, oldb);
            c = safe_add(c, oldc);
            d = safe_add(d, oldd);
            e = safe_add(e, olde);
          }
          return Array(a, b, c, d, e);
        }
  
        /**
         * Perform the appropriate triplet combination function for the current
         * iteration
         */
  
        function sha1_ft(t, b, c, d) {
          if (t < 20) {
            return (b & c) | ((~b) & d);
          }
          if (t < 40) {
            return b ^ c ^ d;
          }
          if (t < 60) {
            return (b & c) | (b & d) | (c & d);
          }
          return b ^ c ^ d;
        }
  
        /**
         * Determine the appropriate additive constant for the current iteration
         */
  
        function sha1_kt(t) {
          return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
            (t < 60) ? -1894007588 : -899497514;
        }
      }