Browse Source

'驰声测试'

Rorschach 4 years ago
parent
commit
3619ae24d4
4 changed files with 3304 additions and 20 deletions
  1. 144 20
      pages/reading/reading.js
  2. 2105 0
      utils/ChivoxAiEngine.js
  3. 683 0
      utils/md5.js
  4. 372 0
      utils/sha1.js

+ 144 - 20
pages/reading/reading.js

@@ -1,4 +1,7 @@
 import httpRequestApi from '../../utils/APIClient';
+const aiengine = require('../../utils/ChivoxAiEngine')
+const sha1 = require('../../utils/sha1');
+
 import {
     formatDate
 } from '../../utils/util';
@@ -75,12 +78,12 @@ Page({
         console.log('onhide')
         if (this.data.audioPlaying) {
             console.log('返回时状态', this.data.audioPlaying)
-            this.ss.stopPlay();
+            // this.ss.stopPlay();
         }
         if (this.data.btnImgFlag) {
-            this.ss.stopRecord();
+            // this.ss.stopRecord();
         }
-        this.ss.destroyEngine();
+        // this.ss.destroyEngine();
         this.setData({
             recordFlag: 0
         })
@@ -90,12 +93,12 @@ Page({
         console.log('onUnload')
         if (this.data.audioPlaying) {
             console.log('销毁时状态', this.data.audioPlaying)
-            this.ss.stopPlay();
+            // this.ss.stopPlay();
         }
         if (this.data.btnImgFlag) {
-            this.ss.stopRecord();
+            // this.ss.stopRecord();
         }
-        this.ss.destroyEngine();
+        // this.ss.destroyEngine();
     },
     onShow: function () {
         this.videoCtx = wx.createVideoContext('myVideo', this);
@@ -113,8 +116,88 @@ Page({
             }
 
         }
-        this.ss = new data.ssEngine(obj);
-
+        // this.ss = new data.ssEngine(obj);
+        this.recorderManager = wx.getRecorderManager();
+        this.recorderManager.onStop((res) => {
+            // wx.showToast({
+            //     title: 'onStop',
+            //     icon: 'fail',
+            //     duration: 500
+            // })
+            this.videoCtx.stop();
+            console.log('recorder stop', res)
+            const recordFile = res.tempFilePath;
+            this.setData({
+                recordFlag: 0,
+                recordSource: recordFile,
+                btnFlag: true,
+                btnImgFlag: false
+            })
+            this.wsEngine.stop({
+                success: () => {
+                  console.log('====== wsEngine stop success ======');
+                  // TODO: add your code here
+                },
+                fail: (res) => {
+                  console.log("====== wsEngine stop fail ======");
+                  console.log(JSON.stringify(res)); //请关注res.errId, res.error
+                  // TODO: add your code here
+                },
+                complete: () => {
+                  // TODO: add your code here
+                //   clearInterval(recordTimeInterval);
+                  console.log("====== wsEngine stop complete ======");
+                }
+              });
+        })
+        this.recorderManager.onStart(() => {
+            // this.saveVideo();
+            this.setData({
+                btnImgFlag: true,
+                btnFlag: false
+            })
+            console.log('recorder start')
+        });
+        //监听已录制完指定帧大小的文件事件。如果设置了 frameSize,则会回调此事件。
+        this.recorderManager.onFrameRecorded((res) => {
+            const {
+                frameBuffer
+            } = res
+            console.log('frameBuffer.byteLength', frameBuffer.byteLength)
+            //TODO 调用feed接口传递音频片给驰声评测引擎
+            this.wsEngine.feed({
+                data: frameBuffer, // frameBuffer为微信录音机回调的音频数据
+                success: () => {
+                    // feed 成功
+                    console.log('feed success.')
+                },
+                fail: (res) => {
+                    // feed 失败, 请关注res.errId, res.error
+                    console.log('feed fail:', JSON.stringify(res))
+                },
+                complete: () => {
+                    // feed 完成
+                }
+            });
+        });
+        this.wsEngine = aiengine.createWsEngine({});
+        this.wsEngine.onResult(res => {
+            console.log('驰声评测结果', res);
+            let overall = res.result.overall;
+            let accuracy = res.result.accuracy;
+            wx.showModal({
+                title: `总分${overall}`,
+                content: `accuracy${accuracy}`,
+                confirmText: '我知道了',
+                showCancel: false,
+                success(res) {
+                  console.log('用户点击确定')
+                }
+              })
+        })
+        this.wsEngine.onErrorResult(res => {
+            console.log('驰声createWsEngine失败', res);
+        })
     },
     ssRecorderCallback: function (type, data) {
         console.log('录音测评监控回调', type)
@@ -158,7 +241,7 @@ Page({
     playingVideoEnd: function () {
         console.log('playingVideoEnd')
 
-        this.ss.stopPlay();;
+        // this.ss.stopPlay();
     },
     /***
      *  recordFlag: 
@@ -178,7 +261,7 @@ Page({
                 // this.videoCtx.seek(0);
             }
             if (this.data.audioPlaying) {
-                this.ss.stopPlay();
+                // this.ss.stopPlay();
             }
             // if (this.recorderManager) {
             //     this.recorderManager.stop();
@@ -218,11 +301,51 @@ Page({
             format: 'mp3',
             frameSize: 50
         }
-        this.ss.startRecord({
-            coreType: 'cn.sent.score', //测评题型    
-            evalTime: 300000, //测评的录音时间,时间到自动停止测评    
-            refText: this.data.readingText, //测评文本  
-            warrantId: 'c11163aa6c834a028da4a4b30955be96', //鉴权id
+        this.recorderManager.start(options);
+        // this.ss.startRecord({
+        //     coreType: 'cn.sent.score', //测评题型    
+        //     evalTime: 300000, //测评的录音时间,时间到自动停止测评    
+        //     refText: this.data.readingText, //测评文本  
+        //     warrantId: 'c11163aa6c834a028da4a4b30955be96', //鉴权id
+        // })
+        // 驰声测评
+        let timeStamp = new Date().getTime()
+        let sig = sha1(`16075689600000da${timeStamp}caa8e60da6042731c230fe431ac9c7fd`)
+        console.log('加密串', sig)
+        // return
+        let app = {
+            applicationId: '16075689600000da',
+            sig, //签名字符串 通过签名算法alg(appkey + timestamp + secretKey)生成
+            alg: 'sha1',
+            timestamp: timeStamp + '',
+            userId: wx.getStorageSync('uid')
+        }
+        console.log('app数据', app)
+        let lessonText = this.data.readingText;
+        console.log('课文课文课文',lessonText)
+        this.wsEngine.start({
+            app,
+            request: {
+                coreType: "cn.pred.raw",
+                refText: lessonText,
+                rank: 100,
+                attachAudioUrl: 1
+            },
+            audio: {
+                audioType: "mp3",
+                channel: 1,
+                sampleBytes: 2,
+                sampleRate: 16000
+            },
+            success: (res) => {
+                // 调用成功
+                console.log('驰声start成功', res)
+            },
+            fail: (res) => {
+                // start失败,请关注res.errId, res.error
+                console.log('驰声start失败', res)
+
+            }
         })
     },
     getMicAuth() {
@@ -275,8 +398,9 @@ Page({
         this.setData({
             muted: false
         })
-        this.ss.stopRecord();
+        // this.ss.stopRecord();
         console.log('录音结束')
+        this.recorderManager.stop();
         wx.hideLoading()
     },
     // 获取测评结果
@@ -327,9 +451,9 @@ Page({
         })
         if (this.data.audioPath) {
             if (this.data.audioPlaying) {
-                this.ss.stopPlay();
+                // this.ss.stopPlay();
             }
-            this.ss.startPlay(this.data.audioPath);
+            // this.ss.startPlay(this.data.audioPath);
             this.videoCtx.stop();
             this.videoCtx.play();
 
@@ -350,7 +474,7 @@ Page({
                         audioPath,
                         audioPlaying: true
                     })
-                    this.ss.startPlay(audioPath);
+                    // this.ss.startPlay(audioPath);
                     // this.videoCtx.seek(0);
                     this.videoCtx.stop();
                     console.log('播放器归0')
@@ -384,7 +508,7 @@ Page({
             this.videoCtx.stop();
         }
         if (this.data.audioPlaying) {
-            this.ss.stopPlay();
+            // this.ss.stopPlay();
             this.setData({
                 audioPlaying: false
             })

File diff suppressed because it is too large
+ 2105 - 0
utils/ChivoxAiEngine.js


+ 683 - 0
utils/md5.js

@@ -0,0 +1,683 @@
+/**
+ * [js-md5]{@link https://github.com/emn178/js-md5}
+ *
+ * @namespace md5
+ * @version 0.7.3
+ * @author Chen, Yi-Cyuan [emn178@gmail.com]
+ * @copyright Chen, Yi-Cyuan 2014-2017
+ * @license MIT
+ */
+(function () {
+    'use strict';
+  
+    var ERROR = 'input is invalid type';
+    var WINDOW = typeof window === 'object';
+    var root = WINDOW ? window : {};
+    if (root.JS_MD5_NO_WINDOW) {
+      WINDOW = false;
+    }
+    var WEB_WORKER = !WINDOW && typeof self === 'object';
+    var NODE_JS = !root.JS_MD5_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
+    if (NODE_JS) {
+      root = global;
+    } else if (WEB_WORKER) {
+      root = self;
+    }
+    var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports;
+    var AMD = typeof define === 'function' && define.amd;
+    var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
+    var HEX_CHARS = '0123456789abcdef'.split('');
+    var EXTRA = [128, 32768, 8388608, -2147483648];
+    var SHIFT = [0, 8, 16, 24];
+    var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64'];
+    var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
+  
+    var blocks = [], buffer8;
+    if (ARRAY_BUFFER) {
+      var buffer = new ArrayBuffer(68);
+      buffer8 = new Uint8Array(buffer);
+      blocks = new Uint32Array(buffer);
+    }
+  
+    if (root.JS_MD5_NO_NODE_JS || !Array.isArray) {
+      Array.isArray = function (obj) {
+        return Object.prototype.toString.call(obj) === '[object Array]';
+      };
+    }
+  
+    if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {
+      ArrayBuffer.isView = function (obj) {
+        return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;
+      };
+    }
+  
+    /**
+     * @method hex
+     * @memberof md5
+     * @description Output hash as hex string
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {String} Hex string
+     * @example
+     * md5.hex('The quick brown fox jumps over the lazy dog');
+     * // equal to
+     * md5('The quick brown fox jumps over the lazy dog');
+     */
+    /**
+     * @method digest
+     * @memberof md5
+     * @description Output hash as bytes array
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {Array} Bytes array
+     * @example
+     * md5.digest('The quick brown fox jumps over the lazy dog');
+     */
+    /**
+     * @method array
+     * @memberof md5
+     * @description Output hash as bytes array
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {Array} Bytes array
+     * @example
+     * md5.array('The quick brown fox jumps over the lazy dog');
+     */
+    /**
+     * @method arrayBuffer
+     * @memberof md5
+     * @description Output hash as ArrayBuffer
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {ArrayBuffer} ArrayBuffer
+     * @example
+     * md5.arrayBuffer('The quick brown fox jumps over the lazy dog');
+     */
+    /**
+     * @method buffer
+     * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
+     * @memberof md5
+     * @description Output hash as ArrayBuffer
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {ArrayBuffer} ArrayBuffer
+     * @example
+     * md5.buffer('The quick brown fox jumps over the lazy dog');
+     */
+    /**
+     * @method base64
+     * @memberof md5
+     * @description Output hash as base64 string
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {String} base64 string
+     * @example
+     * md5.base64('The quick brown fox jumps over the lazy dog');
+     */
+    var createOutputMethod = function (outputType) {
+      return function (message) {
+        return new Md5(true).update(message)[outputType]();
+      };
+    };
+  
+    /**
+     * @method create
+     * @memberof md5
+     * @description Create Md5 object
+     * @returns {Md5} Md5 object.
+     * @example
+     * var hash = md5.create();
+     */
+    /**
+     * @method update
+     * @memberof md5
+     * @description Create and update Md5 object
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {Md5} Md5 object.
+     * @example
+     * var hash = md5.update('The quick brown fox jumps over the lazy dog');
+     * // equal to
+     * var hash = md5.create();
+     * hash.update('The quick brown fox jumps over the lazy dog');
+     */
+    var createMethod = function () {
+      var method = createOutputMethod('hex');
+      if (NODE_JS) {
+        method = nodeWrap(method);
+      }
+      method.create = function () {
+        return new Md5();
+      };
+      method.update = function (message) {
+        return method.create().update(message);
+      };
+      for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
+        var type = OUTPUT_TYPES[i];
+        method[type] = createOutputMethod(type);
+      }
+      return method;
+    };
+  
+    var nodeWrap = function (method) {
+      var crypto = eval("require('crypto')");
+      var Buffer = eval("require('buffer').Buffer");
+      var nodeMethod = function (message) {
+        if (typeof message === 'string') {
+          return crypto.createHash('md5').update(message, 'utf8').digest('hex');
+        } else {
+          if (message === null || message === undefined) {
+            throw ERROR;
+          } else if (message.constructor === ArrayBuffer) {
+            message = new Uint8Array(message);
+          }
+        }
+        if (Array.isArray(message) || ArrayBuffer.isView(message) ||
+          message.constructor === Buffer) {
+          return crypto.createHash('md5').update(new Buffer(message)).digest('hex');
+        } else {
+          return method(message);
+        }
+      };
+      return nodeMethod;
+    };
+  
+    /**
+     * Md5 class
+     * @class Md5
+     * @description This is internal class.
+     * @see {@link md5.create}
+     */
+    function Md5(sharedMemory) {
+      if (sharedMemory) {
+        blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+        blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+        blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+        this.blocks = blocks;
+        this.buffer8 = buffer8;
+      } else {
+        if (ARRAY_BUFFER) {
+          var buffer = new ArrayBuffer(68);
+          this.buffer8 = new Uint8Array(buffer);
+          this.blocks = new Uint32Array(buffer);
+        } else {
+          this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+        }
+      }
+      this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0;
+      this.finalized = this.hashed = false;
+      this.first = true;
+    }
+  
+    /**
+     * @method update
+     * @memberof Md5
+     * @instance
+     * @description Update hash
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {Md5} Md5 object.
+     * @see {@link md5.update}
+     */
+    Md5.prototype.update = function (message) {
+      if (this.finalized) {
+        return;
+      }
+  
+      var notString, type = typeof message;
+      if (type !== 'string') {
+        if (type === 'object') {
+          if (message === null) {
+            throw ERROR;
+          } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {
+            message = new Uint8Array(message);
+          } else if (!Array.isArray(message)) {
+            if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {
+              throw ERROR;
+            }
+          }
+        } else {
+          throw ERROR;
+        }
+        notString = true;
+      }
+      var code, index = 0, i, length = message.length, blocks = this.blocks;
+      var buffer8 = this.buffer8;
+  
+      while (index < length) {
+        if (this.hashed) {
+          this.hashed = false;
+          blocks[0] = blocks[16];
+          blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+          blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+          blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+          blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+        }
+  
+        if (notString) {
+          if (ARRAY_BUFFER) {
+            for (i = this.start; index < length && i < 64; ++index) {
+              buffer8[i++] = message[index];
+            }
+          } else {
+            for (i = this.start; index < length && i < 64; ++index) {
+              blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
+            }
+          }
+        } else {
+          if (ARRAY_BUFFER) {
+            for (i = this.start; index < length && i < 64; ++index) {
+              code = message.charCodeAt(index);
+              if (code < 0x80) {
+                buffer8[i++] = code;
+              } else if (code < 0x800) {
+                buffer8[i++] = 0xc0 | (code >> 6);
+                buffer8[i++] = 0x80 | (code & 0x3f);
+              } else if (code < 0xd800 || code >= 0xe000) {
+                buffer8[i++] = 0xe0 | (code >> 12);
+                buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);
+                buffer8[i++] = 0x80 | (code & 0x3f);
+              } else {
+                code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
+                buffer8[i++] = 0xf0 | (code >> 18);
+                buffer8[i++] = 0x80 | ((code >> 12) & 0x3f);
+                buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);
+                buffer8[i++] = 0x80 | (code & 0x3f);
+              }
+            }
+          } else {
+            for (i = this.start; index < length && i < 64; ++index) {
+              code = message.charCodeAt(index);
+              if (code < 0x80) {
+                blocks[i >> 2] |= code << SHIFT[i++ & 3];
+              } else if (code < 0x800) {
+                blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
+                blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+              } else if (code < 0xd800 || code >= 0xe000) {
+                blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
+                blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
+                blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+              } else {
+                code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
+                blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
+                blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
+                blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
+                blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+              }
+            }
+          }
+        }
+        this.lastByteIndex = i;
+        this.bytes += i - this.start;
+        if (i >= 64) {
+          this.start = i - 64;
+          this.hash();
+          this.hashed = true;
+        } else {
+          this.start = i;
+        }
+      }
+      if (this.bytes > 4294967295) {
+        this.hBytes += this.bytes / 4294967296 << 0;
+        this.bytes = this.bytes % 4294967296;
+      }
+      return this;
+    };
+  
+    Md5.prototype.finalize = function () {
+      if (this.finalized) {
+        return;
+      }
+      this.finalized = true;
+      var blocks = this.blocks, i = this.lastByteIndex;
+      blocks[i >> 2] |= EXTRA[i & 3];
+      if (i >= 56) {
+        if (!this.hashed) {
+          this.hash();
+        }
+        blocks[0] = blocks[16];
+        blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+        blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+        blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+      }
+      blocks[14] = this.bytes << 3;
+      blocks[15] = this.hBytes << 3 | this.bytes >>> 29;
+      this.hash();
+    };
+  
+    Md5.prototype.hash = function () {
+      var a, b, c, d, bc, da, blocks = this.blocks;
+  
+      if (this.first) {
+        a = blocks[0] - 680876937;
+        a = (a << 7 | a >>> 25) - 271733879 << 0;
+        d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708;
+        d = (d << 12 | d >>> 20) + a << 0;
+        c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375;
+        c = (c << 17 | c >>> 15) + d << 0;
+        b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209;
+        b = (b << 22 | b >>> 10) + c << 0;
+      } else {
+        a = this.h0;
+        b = this.h1;
+        c = this.h2;
+        d = this.h3;
+        a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936;
+        a = (a << 7 | a >>> 25) + b << 0;
+        d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586;
+        d = (d << 12 | d >>> 20) + a << 0;
+        c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819;
+        c = (c << 17 | c >>> 15) + d << 0;
+        b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330;
+        b = (b << 22 | b >>> 10) + c << 0;
+      }
+  
+      a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897;
+      a = (a << 7 | a >>> 25) + b << 0;
+      d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426;
+      d = (d << 12 | d >>> 20) + a << 0;
+      c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341;
+      c = (c << 17 | c >>> 15) + d << 0;
+      b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983;
+      b = (b << 22 | b >>> 10) + c << 0;
+      a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416;
+      a = (a << 7 | a >>> 25) + b << 0;
+      d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417;
+      d = (d << 12 | d >>> 20) + a << 0;
+      c += (b ^ (d & (a ^ b))) + blocks[10] - 42063;
+      c = (c << 17 | c >>> 15) + d << 0;
+      b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162;
+      b = (b << 22 | b >>> 10) + c << 0;
+      a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682;
+      a = (a << 7 | a >>> 25) + b << 0;
+      d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101;
+      d = (d << 12 | d >>> 20) + a << 0;
+      c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290;
+      c = (c << 17 | c >>> 15) + d << 0;
+      b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329;
+      b = (b << 22 | b >>> 10) + c << 0;
+      a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510;
+      a = (a << 5 | a >>> 27) + b << 0;
+      d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632;
+      d = (d << 9 | d >>> 23) + a << 0;
+      c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713;
+      c = (c << 14 | c >>> 18) + d << 0;
+      b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302;
+      b = (b << 20 | b >>> 12) + c << 0;
+      a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691;
+      a = (a << 5 | a >>> 27) + b << 0;
+      d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083;
+      d = (d << 9 | d >>> 23) + a << 0;
+      c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335;
+      c = (c << 14 | c >>> 18) + d << 0;
+      b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848;
+      b = (b << 20 | b >>> 12) + c << 0;
+      a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438;
+      a = (a << 5 | a >>> 27) + b << 0;
+      d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690;
+      d = (d << 9 | d >>> 23) + a << 0;
+      c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961;
+      c = (c << 14 | c >>> 18) + d << 0;
+      b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501;
+      b = (b << 20 | b >>> 12) + c << 0;
+      a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467;
+      a = (a << 5 | a >>> 27) + b << 0;
+      d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784;
+      d = (d << 9 | d >>> 23) + a << 0;
+      c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473;
+      c = (c << 14 | c >>> 18) + d << 0;
+      b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734;
+      b = (b << 20 | b >>> 12) + c << 0;
+      bc = b ^ c;
+      a += (bc ^ d) + blocks[5] - 378558;
+      a = (a << 4 | a >>> 28) + b << 0;
+      d += (bc ^ a) + blocks[8] - 2022574463;
+      d = (d << 11 | d >>> 21) + a << 0;
+      da = d ^ a;
+      c += (da ^ b) + blocks[11] + 1839030562;
+      c = (c << 16 | c >>> 16) + d << 0;
+      b += (da ^ c) + blocks[14] - 35309556;
+      b = (b << 23 | b >>> 9) + c << 0;
+      bc = b ^ c;
+      a += (bc ^ d) + blocks[1] - 1530992060;
+      a = (a << 4 | a >>> 28) + b << 0;
+      d += (bc ^ a) + blocks[4] + 1272893353;
+      d = (d << 11 | d >>> 21) + a << 0;
+      da = d ^ a;
+      c += (da ^ b) + blocks[7] - 155497632;
+      c = (c << 16 | c >>> 16) + d << 0;
+      b += (da ^ c) + blocks[10] - 1094730640;
+      b = (b << 23 | b >>> 9) + c << 0;
+      bc = b ^ c;
+      a += (bc ^ d) + blocks[13] + 681279174;
+      a = (a << 4 | a >>> 28) + b << 0;
+      d += (bc ^ a) + blocks[0] - 358537222;
+      d = (d << 11 | d >>> 21) + a << 0;
+      da = d ^ a;
+      c += (da ^ b) + blocks[3] - 722521979;
+      c = (c << 16 | c >>> 16) + d << 0;
+      b += (da ^ c) + blocks[6] + 76029189;
+      b = (b << 23 | b >>> 9) + c << 0;
+      bc = b ^ c;
+      a += (bc ^ d) + blocks[9] - 640364487;
+      a = (a << 4 | a >>> 28) + b << 0;
+      d += (bc ^ a) + blocks[12] - 421815835;
+      d = (d << 11 | d >>> 21) + a << 0;
+      da = d ^ a;
+      c += (da ^ b) + blocks[15] + 530742520;
+      c = (c << 16 | c >>> 16) + d << 0;
+      b += (da ^ c) + blocks[2] - 995338651;
+      b = (b << 23 | b >>> 9) + c << 0;
+      a += (c ^ (b | ~d)) + blocks[0] - 198630844;
+      a = (a << 6 | a >>> 26) + b << 0;
+      d += (b ^ (a | ~c)) + blocks[7] + 1126891415;
+      d = (d << 10 | d >>> 22) + a << 0;
+      c += (a ^ (d | ~b)) + blocks[14] - 1416354905;
+      c = (c << 15 | c >>> 17) + d << 0;
+      b += (d ^ (c | ~a)) + blocks[5] - 57434055;
+      b = (b << 21 | b >>> 11) + c << 0;
+      a += (c ^ (b | ~d)) + blocks[12] + 1700485571;
+      a = (a << 6 | a >>> 26) + b << 0;
+      d += (b ^ (a | ~c)) + blocks[3] - 1894986606;
+      d = (d << 10 | d >>> 22) + a << 0;
+      c += (a ^ (d | ~b)) + blocks[10] - 1051523;
+      c = (c << 15 | c >>> 17) + d << 0;
+      b += (d ^ (c | ~a)) + blocks[1] - 2054922799;
+      b = (b << 21 | b >>> 11) + c << 0;
+      a += (c ^ (b | ~d)) + blocks[8] + 1873313359;
+      a = (a << 6 | a >>> 26) + b << 0;
+      d += (b ^ (a | ~c)) + blocks[15] - 30611744;
+      d = (d << 10 | d >>> 22) + a << 0;
+      c += (a ^ (d | ~b)) + blocks[6] - 1560198380;
+      c = (c << 15 | c >>> 17) + d << 0;
+      b += (d ^ (c | ~a)) + blocks[13] + 1309151649;
+      b = (b << 21 | b >>> 11) + c << 0;
+      a += (c ^ (b | ~d)) + blocks[4] - 145523070;
+      a = (a << 6 | a >>> 26) + b << 0;
+      d += (b ^ (a | ~c)) + blocks[11] - 1120210379;
+      d = (d << 10 | d >>> 22) + a << 0;
+      c += (a ^ (d | ~b)) + blocks[2] + 718787259;
+      c = (c << 15 | c >>> 17) + d << 0;
+      b += (d ^ (c | ~a)) + blocks[9] - 343485551;
+      b = (b << 21 | b >>> 11) + c << 0;
+  
+      if (this.first) {
+        this.h0 = a + 1732584193 << 0;
+        this.h1 = b - 271733879 << 0;
+        this.h2 = c - 1732584194 << 0;
+        this.h3 = d + 271733878 << 0;
+        this.first = false;
+      } else {
+        this.h0 = this.h0 + a << 0;
+        this.h1 = this.h1 + b << 0;
+        this.h2 = this.h2 + c << 0;
+        this.h3 = this.h3 + d << 0;
+      }
+    };
+  
+    /**
+     * @method hex
+     * @memberof Md5
+     * @instance
+     * @description Output hash as hex string
+     * @returns {String} Hex string
+     * @see {@link md5.hex}
+     * @example
+     * hash.hex();
+     */
+    Md5.prototype.hex = function () {
+      this.finalize();
+  
+      var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;
+  
+      return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +
+        HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +
+        HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +
+        HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +
+        HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +
+        HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +
+        HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +
+        HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +
+        HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +
+        HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +
+        HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +
+        HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +
+        HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +
+        HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +
+        HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +
+        HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F];
+    };
+  
+    /**
+     * @method toString
+     * @memberof Md5
+     * @instance
+     * @description Output hash as hex string
+     * @returns {String} Hex string
+     * @see {@link md5.hex}
+     * @example
+     * hash.toString();
+     */
+    Md5.prototype.toString = Md5.prototype.hex;
+  
+    /**
+     * @method digest
+     * @memberof Md5
+     * @instance
+     * @description Output hash as bytes array
+     * @returns {Array} Bytes array
+     * @see {@link md5.digest}
+     * @example
+     * hash.digest();
+     */
+    Md5.prototype.digest = function () {
+      this.finalize();
+  
+      var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;
+      return [
+        h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF,
+        h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF,
+        h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF,
+        h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF
+      ];
+    };
+  
+    /**
+     * @method array
+     * @memberof Md5
+     * @instance
+     * @description Output hash as bytes array
+     * @returns {Array} Bytes array
+     * @see {@link md5.array}
+     * @example
+     * hash.array();
+     */
+    Md5.prototype.array = Md5.prototype.digest;
+  
+    /**
+     * @method arrayBuffer
+     * @memberof Md5
+     * @instance
+     * @description Output hash as ArrayBuffer
+     * @returns {ArrayBuffer} ArrayBuffer
+     * @see {@link md5.arrayBuffer}
+     * @example
+     * hash.arrayBuffer();
+     */
+    Md5.prototype.arrayBuffer = function () {
+      this.finalize();
+  
+      var buffer = new ArrayBuffer(16);
+      var blocks = new Uint32Array(buffer);
+      blocks[0] = this.h0;
+      blocks[1] = this.h1;
+      blocks[2] = this.h2;
+      blocks[3] = this.h3;
+      return buffer;
+    };
+  
+    /**
+     * @method buffer
+     * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
+     * @memberof Md5
+     * @instance
+     * @description Output hash as ArrayBuffer
+     * @returns {ArrayBuffer} ArrayBuffer
+     * @see {@link md5.buffer}
+     * @example
+     * hash.buffer();
+     */
+    Md5.prototype.buffer = Md5.prototype.arrayBuffer;
+  
+    /**
+     * @method base64
+     * @memberof Md5
+     * @instance
+     * @description Output hash as base64 string
+     * @returns {String} base64 string
+     * @see {@link md5.base64}
+     * @example
+     * hash.base64();
+     */
+    Md5.prototype.base64 = function () {
+      var v1, v2, v3, base64Str = '', bytes = this.array();
+      for (var i = 0; i < 15;) {
+        v1 = bytes[i++];
+        v2 = bytes[i++];
+        v3 = bytes[i++];
+        base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +
+          BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] +
+          BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] +
+          BASE64_ENCODE_CHAR[v3 & 63];
+      }
+      v1 = bytes[i];
+      base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +
+        BASE64_ENCODE_CHAR[(v1 << 4) & 63] +
+        '==';
+      return base64Str;
+    };
+  
+    var exports = createMethod();
+  
+    if (COMMON_JS) {
+      module.exports = exports;
+    } else {
+      /**
+       * @method md5
+       * @description Md5 hash function, export to global in browsers.
+       * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+       * @returns {String} md5 hashes
+       * @example
+       * md5(''); // d41d8cd98f00b204e9800998ecf8427e
+       * md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6
+       * md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0
+       *
+       * // It also supports UTF-8 encoding
+       * md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07
+       *
+       * // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer`
+       * md5([]); // d41d8cd98f00b204e9800998ecf8427e
+       * md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e
+       */
+      root.md5 = exports;
+      if (AMD) {
+        define(function () {
+          return exports;
+        });
+      }
+    }
+  })();

+ 372 - 0
utils/sha1.js

@@ -0,0 +1,372 @@
+  
+/*
+ * [js-sha1]{@link https://github.com/emn178/js-sha1}
+ *
+ * @version 0.6.0
+ * @author Chen, Yi-Cyuan [emn178@gmail.com]
+ * @copyright Chen, Yi-Cyuan 2014-2017
+ * @license MIT
+ */
+/*jslint bitwise: true */
+(function() {
+    'use strict';
+  
+    var root = typeof window === 'object' ? window : {};
+    var NODE_JS = !root.JS_SHA1_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
+    if (NODE_JS) {
+      root = global;
+    }
+    var COMMON_JS = !root.JS_SHA1_NO_COMMON_JS && typeof module === 'object' && module.exports;
+    var AMD = typeof define === 'function' && define.amd;
+    var HEX_CHARS = '0123456789abcdef'.split('');
+    var EXTRA = [-2147483648, 8388608, 32768, 128];
+    var SHIFT = [24, 16, 8, 0];
+    var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer'];
+  
+    var blocks = [];
+  
+    var createOutputMethod = function (outputType) {
+      return function (message) {
+        return new Sha1(true).update(message)[outputType]();
+      };
+    };
+  
+    var createMethod = function () {
+      var method = createOutputMethod('hex');
+      if (NODE_JS) {
+        method = nodeWrap(method);
+      }
+      method.create = function () {
+        return new Sha1();
+      };
+      method.update = function (message) {
+        return method.create().update(message);
+      };
+      for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
+        var type = OUTPUT_TYPES[i];
+        method[type] = createOutputMethod(type);
+      }
+      return method;
+    };
+  
+    var nodeWrap = function (method) {
+      var crypto = eval("require('crypto')");
+      var Buffer = eval("require('buffer').Buffer");
+      var nodeMethod = function (message) {
+        if (typeof message === 'string') {
+          return crypto.createHash('sha1').update(message, 'utf8').digest('hex');
+        } else if (message.constructor === ArrayBuffer) {
+          message = new Uint8Array(message);
+        } else if (message.length === undefined) {
+          return method(message);
+        }
+        return crypto.createHash('sha1').update(new Buffer(message)).digest('hex');
+      };
+      return nodeMethod;
+    };
+  
+    function Sha1(sharedMemory) {
+      if (sharedMemory) {
+        blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+        blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+        blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+        this.blocks = blocks;
+      } else {
+        this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+      }
+  
+      this.h0 = 0x67452301;
+      this.h1 = 0xEFCDAB89;
+      this.h2 = 0x98BADCFE;
+      this.h3 = 0x10325476;
+      this.h4 = 0xC3D2E1F0;
+  
+      this.block = this.start = this.bytes = this.hBytes = 0;
+      this.finalized = this.hashed = false;
+      this.first = true;
+    }
+  
+    Sha1.prototype.update = function (message) {
+      if (this.finalized) {
+        return;
+      }
+      var notString = typeof(message) !== 'string';
+      if (notString && message.constructor === root.ArrayBuffer) {
+        message = new Uint8Array(message);
+      }
+      var code, index = 0, i, length = message.length || 0, blocks = this.blocks;
+  
+      while (index < length) {
+        if (this.hashed) {
+          this.hashed = false;
+          blocks[0] = this.block;
+          blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+          blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+          blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+          blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+        }
+  
+        if(notString) {
+          for (i = this.start; index < length && i < 64; ++index) {
+            blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
+          }
+        } else {
+          for (i = this.start; index < length && i < 64; ++index) {
+            code = message.charCodeAt(index);
+            if (code < 0x80) {
+              blocks[i >> 2] |= code << SHIFT[i++ & 3];
+            } else if (code < 0x800) {
+              blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+            } else if (code < 0xd800 || code >= 0xe000) {
+              blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+            } else {
+              code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
+              blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
+              blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+            }
+          }
+        }
+  
+        this.lastByteIndex = i;
+        this.bytes += i - this.start;
+        if (i >= 64) {
+          this.block = blocks[16];
+          this.start = i - 64;
+          this.hash();
+          this.hashed = true;
+        } else {
+          this.start = i;
+        }
+      }
+      if (this.bytes > 4294967295) {
+        this.hBytes += this.bytes / 4294967296 << 0;
+        this.bytes = this.bytes % 4294967296;
+      }
+      return this;
+    };
+  
+    Sha1.prototype.finalize = function () {
+      if (this.finalized) {
+        return;
+      }
+      this.finalized = true;
+      var blocks = this.blocks, i = this.lastByteIndex;
+      blocks[16] = this.block;
+      blocks[i >> 2] |= EXTRA[i & 3];
+      this.block = blocks[16];
+      if (i >= 56) {
+        if (!this.hashed) {
+          this.hash();
+        }
+        blocks[0] = this.block;
+        blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+        blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+        blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+      }
+      blocks[14] = this.hBytes << 3 | this.bytes >>> 29;
+      blocks[15] = this.bytes << 3;
+      this.hash();
+    };
+  
+    Sha1.prototype.hash = function () {
+      var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4;
+      var f, j, t, blocks = this.blocks;
+  
+      for(j = 16; j < 80; ++j) {
+        t = blocks[j - 3] ^ blocks[j - 8] ^ blocks[j - 14] ^ blocks[j - 16];
+        blocks[j] =  (t << 1) | (t >>> 31);
+      }
+  
+      for(j = 0; j < 20; j += 5) {
+        f = (b & c) | ((~b) & d);
+        t = (a << 5) | (a >>> 27);
+        e = t + f + e + 1518500249 + blocks[j] << 0;
+        b = (b << 30) | (b >>> 2);
+  
+        f = (a & b) | ((~a) & c);
+        t = (e << 5) | (e >>> 27);
+        d = t + f + d + 1518500249 + blocks[j + 1] << 0;
+        a = (a << 30) | (a >>> 2);
+  
+        f = (e & a) | ((~e) & b);
+        t = (d << 5) | (d >>> 27);
+        c = t + f + c + 1518500249 + blocks[j + 2] << 0;
+        e = (e << 30) | (e >>> 2);
+  
+        f = (d & e) | ((~d) & a);
+        t = (c << 5) | (c >>> 27);
+        b = t + f + b + 1518500249 + blocks[j + 3] << 0;
+        d = (d << 30) | (d >>> 2);
+  
+        f = (c & d) | ((~c) & e);
+        t = (b << 5) | (b >>> 27);
+        a = t + f + a + 1518500249 + blocks[j + 4] << 0;
+        c = (c << 30) | (c >>> 2);
+      }
+  
+      for(; j < 40; j += 5) {
+        f = b ^ c ^ d;
+        t = (a << 5) | (a >>> 27);
+        e = t + f + e + 1859775393 + blocks[j] << 0;
+        b = (b << 30) | (b >>> 2);
+  
+        f = a ^ b ^ c;
+        t = (e << 5) | (e >>> 27);
+        d = t + f + d + 1859775393 + blocks[j + 1] << 0;
+        a = (a << 30) | (a >>> 2);
+  
+        f = e ^ a ^ b;
+        t = (d << 5) | (d >>> 27);
+        c = t + f + c + 1859775393 + blocks[j + 2] << 0;
+        e = (e << 30) | (e >>> 2);
+  
+        f = d ^ e ^ a;
+        t = (c << 5) | (c >>> 27);
+        b = t + f + b + 1859775393 + blocks[j + 3] << 0;
+        d = (d << 30) | (d >>> 2);
+  
+        f = c ^ d ^ e;
+        t = (b << 5) | (b >>> 27);
+        a = t + f + a + 1859775393 + blocks[j + 4] << 0;
+        c = (c << 30) | (c >>> 2);
+      }
+  
+      for(; j < 60; j += 5) {
+        f = (b & c) | (b & d) | (c & d);
+        t = (a << 5) | (a >>> 27);
+        e = t + f + e - 1894007588 + blocks[j] << 0;
+        b = (b << 30) | (b >>> 2);
+  
+        f = (a & b) | (a & c) | (b & c);
+        t = (e << 5) | (e >>> 27);
+        d = t + f + d - 1894007588 + blocks[j + 1] << 0;
+        a = (a << 30) | (a >>> 2);
+  
+        f = (e & a) | (e & b) | (a & b);
+        t = (d << 5) | (d >>> 27);
+        c = t + f + c - 1894007588 + blocks[j + 2] << 0;
+        e = (e << 30) | (e >>> 2);
+  
+        f = (d & e) | (d & a) | (e & a);
+        t = (c << 5) | (c >>> 27);
+        b = t + f + b - 1894007588 + blocks[j + 3] << 0;
+        d = (d << 30) | (d >>> 2);
+  
+        f = (c & d) | (c & e) | (d & e);
+        t = (b << 5) | (b >>> 27);
+        a = t + f + a - 1894007588 + blocks[j + 4] << 0;
+        c = (c << 30) | (c >>> 2);
+      }
+  
+      for(; j < 80; j += 5) {
+        f = b ^ c ^ d;
+        t = (a << 5) | (a >>> 27);
+        e = t + f + e - 899497514 + blocks[j] << 0;
+        b = (b << 30) | (b >>> 2);
+  
+        f = a ^ b ^ c;
+        t = (e << 5) | (e >>> 27);
+        d = t + f + d - 899497514 + blocks[j + 1] << 0;
+        a = (a << 30) | (a >>> 2);
+  
+        f = e ^ a ^ b;
+        t = (d << 5) | (d >>> 27);
+        c = t + f + c - 899497514 + blocks[j + 2] << 0;
+        e = (e << 30) | (e >>> 2);
+  
+        f = d ^ e ^ a;
+        t = (c << 5) | (c >>> 27);
+        b = t + f + b - 899497514 + blocks[j + 3] << 0;
+        d = (d << 30) | (d >>> 2);
+  
+        f = c ^ d ^ e;
+        t = (b << 5) | (b >>> 27);
+        a = t + f + a - 899497514 + blocks[j + 4] << 0;
+        c = (c << 30) | (c >>> 2);
+      }
+  
+      this.h0 = this.h0 + a << 0;
+      this.h1 = this.h1 + b << 0;
+      this.h2 = this.h2 + c << 0;
+      this.h3 = this.h3 + d << 0;
+      this.h4 = this.h4 + e << 0;
+    };
+  
+    Sha1.prototype.hex = function () {
+      this.finalize();
+  
+      var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4;
+  
+      return HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +
+             HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +
+             HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +
+             HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +
+             HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +
+             HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +
+             HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +
+             HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +
+             HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +
+             HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +
+             HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +
+             HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +
+             HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F] +
+             HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +
+             HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +
+             HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +
+             HEX_CHARS[(h4 >> 28) & 0x0F] + HEX_CHARS[(h4 >> 24) & 0x0F] +
+             HEX_CHARS[(h4 >> 20) & 0x0F] + HEX_CHARS[(h4 >> 16) & 0x0F] +
+             HEX_CHARS[(h4 >> 12) & 0x0F] + HEX_CHARS[(h4 >> 8) & 0x0F] +
+             HEX_CHARS[(h4 >> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F];
+    };
+  
+    Sha1.prototype.toString = Sha1.prototype.hex;
+  
+    Sha1.prototype.digest = function () {
+      this.finalize();
+  
+      var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4;
+  
+      return [
+        (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, h0 & 0xFF,
+        (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, h1 & 0xFF,
+        (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, h2 & 0xFF,
+        (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, h3 & 0xFF,
+        (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, h4 & 0xFF
+      ];
+    };
+  
+    Sha1.prototype.array = Sha1.prototype.digest;
+  
+    Sha1.prototype.arrayBuffer = function () {
+      this.finalize();
+  
+      var buffer = new ArrayBuffer(20);
+      var dataView = new DataView(buffer);
+      dataView.setUint32(0, this.h0);
+      dataView.setUint32(4, this.h1);
+      dataView.setUint32(8, this.h2);
+      dataView.setUint32(12, this.h3);
+      dataView.setUint32(16, this.h4);
+      return buffer;
+    };
+  
+    var exports = createMethod();
+  
+    if (COMMON_JS) {
+      module.exports = exports;
+    } else {
+      root.sha1 = exports;
+      if (AMD) {
+        define(function () {
+          return exports;
+        });
+      }
+    }
+  })();