浏览代码

'210板驰声测试'

Rorschach 4 年之前
父节点
当前提交
db30c2f0c3
共有 7 个文件被更改,包括 2675 次插入83 次删除
  1. 194 81
      pages/reading/reading.js
  2. 1 1
      pages/reading/reading.wxss
  3. 二进制
      static/image/works_poster.jpg
  4. 2 1
      utils/APIClient.js
  5. 2105 0
      utils/ChivoxAiEngine.js
  6. 1 0
      utils/const.js
  7. 372 0
      utils/sha1.js

+ 194 - 81
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';
@@ -64,7 +67,6 @@ Page({
                 exampleId: res.data.data.userRead.exampleId,
                 summary: res.data.data.userRead.summary,
                 coverImg: res.data.data.userRead.coverImg,
-                shareImg: res.data.data.userRead.shareImg,
             })
             this.getReadInfo(id)
             httpRequestApi.userIntoPage('pages/reading/reading', '朗读页面').success((res) => {
@@ -74,14 +76,13 @@ Page({
     },
     onHide: function () {
         console.log('onhide')
-        if (this.data.audioPlaying) {
-            console.log('返回时状态', this.data.audioPlaying)
-            this.ss.stopPlay();
-        }
         if (this.data.btnImgFlag) {
-            this.ss.stopRecord();
+            this.recorderManager.stop();
         }
-        this.ss.destroyEngine();
+        if (this.innerAudioContext) {
+            this.innerAudioContext.stop();
+        }
+        // this.ss.destroyEngine();
         this.setData({
             recordFlag: 0
         })
@@ -89,14 +90,12 @@ Page({
     },
     onUnload: function () {
         console.log('onUnload')
-        if (this.data.audioPlaying) {
-            console.log('销毁时状态', this.data.audioPlaying)
-            this.ss.stopPlay();
-        }
         if (this.data.btnImgFlag) {
-            this.ss.stopRecord();
+            this.recorderManager.stop();
+        }
+        if (this.innerAudioContext) {
+            this.innerAudioContext.stop();
         }
-        this.ss.destroyEngine();
     },
     onShow: function () {
         this.videoCtx = wx.createVideoContext('myVideo', this);
@@ -114,7 +113,75 @@ 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.seek(0);
+            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 ======');
+                    wx.showLoading({
+                        title: '作品评测中',
+                        mask: true
+                    })
+                    // 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 完成
+                }
+            });
+        });
 
     },
     ssRecorderCallback: function (type, data) {
@@ -159,7 +226,7 @@ Page({
     playingVideoEnd: function () {
         console.log('playingVideoEnd')
 
-        this.ss.stopPlay();;
+        // this.ss.stopPlay();
     },
     /***
      *  recordFlag: 
@@ -168,27 +235,26 @@ Page({
      *      2 录音结束
      ***/
     audioRecord: function () {
+
         console.log('111111111111111recordFlag', this.data.recordFlag)
+        if (this.recorderManager) {
+            this.recorderManager.stop();
+        }
+        if (this.innerAudioContext) {
+            this.innerAudioContext.stop();
+        }
         if (this.data.recordFlag === 0) {
-            // this.recordStart();
-            // this.saveVideo();
-            console.log('2222222222是否有视频', this.videoCtx)
-            if (this.videoCtx) {
-                console.log('3333333333333停止视频停止视频停止视频')
-                this.videoCtx.stop();
-                // this.videoCtx.seek(0);
-            }
-            if (this.data.audioPlaying) {
-                this.ss.stopPlay();
-            }
-            // if (this.recorderManager) {
-            //     this.recorderManager.stop();
-            // }
-            // if (this.innerAudioContext) {
-            //     this.innerAudioContext.stop();
-            // }
-            this.getMicAuth()
-            // this.videoComplete();
+            this.wsEngine = aiengine.createWsEngine({});
+            this.wsEngine.onResult(res => {
+                wx.hideLoading();
+                this.getRecordScore(res)
+            })
+            this.wsEngine.onErrorResult(res => {
+                wx.hideLoading();
+                console.log('驰声createWsEngine失败', res);
+            })
+            this.videoComplete();
+            // this.getMicAuth()
             return;
         }
         // 录音结束后
@@ -219,11 +285,56 @@ 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,
+                result: {
+                    details: {
+                        gop_adjust: 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() {
@@ -231,9 +342,7 @@ Page({
         wx.getSetting({
             success(res) {
                 if (res.authSetting['scope.record']) {
-                    // that.videoComplete();
                     _this.videoComplete();
-
                 } else {
                     _this.getMicSetAuth();
                     return;
@@ -276,18 +385,20 @@ Page({
         this.setData({
             muted: false
         })
-        this.ss.stopRecord();
+        // this.ss.stopRecord();
         console.log('录音结束')
+        this.recorderManager.stop();
         wx.hideLoading()
     },
     // 获取测评结果
     getRecordScore(res) {
-        console.log('测评结果', res)
+        console.log('测评结果', JSON.stringify(res))
         const result = res.result;
         const overall = result.overall; // 总分
         const integrity = result.integrity; //完成度
         const tone = result.tone; // 语调声调
-        const accuracy = result.accuracy; // 发音分
+        // const accuracy = result.accuracy; // 准确度 发音分
+        const accuracy = result.overall; // 准确度 发音分
         const fluency = result.fluency.overall; //流利度 
         let starArray = [];
         let score = overall / 20;
@@ -323,14 +434,25 @@ Page({
     // 播放录音
     audioPlay: function () {
         /* 用了先声智能以后录音播放由先声只能接管 */
+        if (this.innerAudioContext) {
+            this.innerAudioContext.stop();
+            this.videoCtx.stop();
+        }
+        this.innerAudioContext = wx.createInnerAudioContext();
+        this.innerAudioContext.src = this.data.recordSource; // 这里可以是录音的临时路径
         this.setData({
-            videoUrl: this.data.videoUrl
+            videoUrl: this.data.videoUrl,
+            muted: true
         })
-        if (this.data.audioPath) {
+        console.log(this.innerAudioContext.src);
+        this.videoCtx.play();
+        this.innerAudioContext.play();
+
+        /* 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();
 
@@ -351,7 +473,7 @@ Page({
                         audioPath,
                         audioPlaying: true
                     })
-                    this.ss.startPlay(audioPath);
+                    // this.ss.startPlay(audioPath);
                     // this.videoCtx.seek(0);
                     this.videoCtx.stop();
                     console.log('播放器归0')
@@ -359,22 +481,22 @@ Page({
                     console.log('播放器播放')
                 }
             })
-        }
+        } */
     },
 
     videoComplete: function () {
-        // let videoUrl = 'http://efunimgs.ai160.com/ott/test/002tPr2Xlx07oP7B4ro40104120022hP0k010.mp4';
         this.setData({
             recordFlag: 1,
             videoUrl: this.data.originVideo,
             centerBtn: false,
             playBtn: false,
             isVideoListShow: false,
-            muted: true,
+            muted: false,
             ifTextShow: true,
             ifScoreShow: false
 
         }, () => {
+            console.log('播放视频播放视频播放视频')
             this.videoCtx.play();
             this.recordStart();
         })
@@ -385,7 +507,7 @@ Page({
             this.videoCtx.stop();
         }
         if (this.data.audioPlaying) {
-            this.ss.stopPlay();
+            // this.ss.stopPlay();
             this.setData({
                 audioPlaying: false
             })
@@ -394,31 +516,24 @@ Page({
             title: '作品上传中',
             mask: true
         })
-
-        if (this.data.audioPath) {
-            this.shareWorks(this.data.audioPath)
-        } else {
-            const recordSource = this.data.recordSource;
-            wx.uploadFile({
-                url: 'https://reader-api.ai160.com/file/upload',
-                filePath: recordSource,
-                name: '朗读录音',
-                header: {
-                    uid: wx.getStorageSync('uid')
-                },
-                success: (res) => {
-                    const formateRes = JSON.parse(res.data);
-                    let audioPath = formateRes.data;
-                    this.shareWorks(audioPath);
-
-                }
-
-            })
-        }
-
+        const recordSource = this.data.recordSource;
+        wx.uploadFile({
+            url: 'https://reader-api.ai160.com/file/upload',
+            // url: 'https://reader-test.efunbox.cn/file/upload',
+            filePath: recordSource,
+            name: '朗读录音',
+            header: {
+                uid: wx.getStorageSync('uid')
+            },
+            success: (res) => {
+                const formateRes = JSON.parse(res.data);
+                let audioPath = formateRes.data;
+                console.log('音频上传成功')
+                this.shareWorks(audioPath);
+            }
+        })
     },
     shareWorks: function (audio) {
-
         const data = {
             "lessonId": this.data.id,
             "originVideo": this.data.videoUrl,
@@ -429,8 +544,7 @@ Page({
             "productId": this.data.productId,
             "grade": this.data.grade,
             "exampleId": this.data.exampleId,
-            "coverImg": this.data.coverImg,
-            "shareImg": this.data.shareImg,
+            "coverImg": this.data.coverImg
         };
         httpRequestApi.postWork(data).success(res => {
             wx.hideLoading({
@@ -513,7 +627,6 @@ Page({
                 temp.coverImg = item.userRead.coverImg;
                 temp.videoShow = false;
                 temp.grade = item.userRead.grade;
-                temp.shareImg = item.userRead.shareImg;
                 temp.type = item.userRead.type;
 
                 // recommendWorks.push(temp);
@@ -572,7 +685,7 @@ Page({
             return {
                 title: '请欣赏我的课文朗读作品,点赞+评论。',
                 path: `/pages/index/index?readId=${this.data.shareId}`,
-                imageUrl: this.data.shareImg
+                imageUrl: '../../static/index/share_icon.png'
 
             }
         } else {
@@ -591,7 +704,7 @@ Page({
         this.setData({
             shareTitle: e.detail.currentTarget.dataset.title,
             shareId: e.detail.currentTarget.dataset.id,
-            shareImg: e.detail.currentTarget.dataset.shareimg
+            shareImg: e.detail.currentTarget.dataset.img
         })
     },
     onPlay: function (e) {

+ 1 - 1
pages/reading/reading.wxss

@@ -200,7 +200,7 @@ audio {
 
 .readingPage .score_section {
     width: 100%;
-    padding: 0 110rpx;
+    padding: 0 105rpx;
     box-sizing: border-box;
     height: 524rpx;
     background: #fffbf7;

二进制
static/image/works_poster.jpg


+ 2 - 1
utils/APIClient.js

@@ -94,8 +94,9 @@ module.exports = {
   // },
   // 发布作品
   postWork(data) {
-    console.log(data);
+    console.log('上传数据',data);
     let url = getBaseUrl(`wx/userRead`);
+    // let url = `https://reader-test.efunbox.cn/userRead`;
     return request.getInstance().header({
       uid: wx.getStorageSync('uid')
     }).url(url).data(data).method('POST').send();

文件差异内容过多而无法显示
+ 2105 - 0
utils/ChivoxAiEngine.js


+ 1 - 0
utils/const.js

@@ -6,4 +6,5 @@ module.exports = {
   // baseApi: 'https://reader.lingjiao.cn/readerBase/'
   // baseApi: 'https://readertest.lingjiao.cn:442/readerBase/'
   baseApi: 'https://reader-api.ai160.com/'
+  // baseApi: 'https://reader-test.efunbox.cn/'
 }

+ 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;
+        });
+      }
+    }
+  })();