Pārlūkot izejas kodu

万物墙手写识别1000X500适配

shaogen1995 3 gadi atpakaļ
vecāks
revīzija
f8418585e8

+ 244 - 0
万物墙后台/shurufa1000X500/css/index.css

@@ -0,0 +1,244 @@
+*{
+  padding: 0;
+  margin: 0;
+     font-family:"Microsoft YaHei",微软雅黑,"MicrosoftJhengHei",华文细黑,STHeiti,MingLiu;
+     line-height: 1;
+}
+
+::-webkit-scrollbar {
+  width: 0.6rem;
+  height: 1rem;
+  background-color: #71471d;
+
+}
+
+::-webkit-scrollbar-thumb {
+  height: 5rem;
+  background-color: #EA9649;
+  outline: 0.5rem solid #EA9649;
+  outline-offset: -0.5rem;
+}
+
+::-webkit-scrollbar-thumb:hover {
+  height: 5rem;
+  background-color: #EA9649;
+}
+
+li{
+  list-style: none;
+}
+html,body{
+  width: 100%;
+  height: 100%;
+  font-size: 34px;
+}
+
+body{
+  position: relative;
+  color: #EA9649;
+  max-width: 100%;
+  margin: 0 auto;
+}
+
+button,input{
+    border: none;
+    outline: none;
+    background: none;
+    font-size: 1rem;		
+}
+
+
+
+.body{
+  width: 100%;
+  height: 100%;
+}
+
+.bg{
+  width: 100%;
+  top: 0;
+  position: absolute;
+  z-index: -1;
+}
+
+.content{
+  width: 1000px;
+  height: 500px;
+  margin: 0 auto;
+}
+
+.title{
+  text-align: center;
+  padding-top: 6%;
+}
+
+.input{
+  height: 60px;
+  display: flex;
+  width: 100%;
+  font-size: 0;
+  position: relative;
+}
+
+.input input{
+  font-size: 24px;
+  border: #EA9649 5px solid;
+  border-right: none;
+  background: none;
+  color: #EA9649;
+  padding-left: 0.63rem;
+  padding-right: 2.63rem;
+  margin: 0;
+  flex: 30;
+}
+
+.input span{
+  padding: 0 10px;
+  height: 50px;
+  border-top: #EA9649 5px solid;
+  border-bottom: #EA9649 5px solid;
+  flex: 1;
+  text-align: center;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.input span img{
+  vertical-align: middle;
+  display: inline-block;
+  width: 30px;
+  height: 30px;
+  opacity: 0;
+}
+
+.input .button{
+  flex: 3;
+  background: #EA9649;
+  margin: 0;
+  font-size:24px;
+  height: 60px;
+  line-height: 60px;
+  margin: 0 auto;
+  color: #000;
+  min-width: 15%;
+  text-align: center;
+}
+
+.result{
+  display: flex;
+  width: 100%;
+  margin: 10px 0;
+  height: 70px;
+}
+
+.result li{
+  font-size: 20px;
+  list-style: none;
+  display: inline-block;
+  margin-right: 0.38rem;
+  padding: 0.13rem 0.25rem;
+  vertical-align: middle;
+}
+
+.result li:last-of-type{
+  margin-right: 0;
+}
+.result li img{
+  margin-top: 20px;
+  width: 30px;
+  vertical-align: middle;
+}
+
+
+.result .active{
+  background: #EA9649;
+  color: #000;
+}
+
+#canvasWrap {
+  position:relative;
+  margin:0 auto;
+  width:990px;
+  height:340px;
+  border:5px solid #EA9649;
+  font-size: 0;
+}
+
+#clear{
+  opacity: 0;
+}
+
+.cls{
+  text-align: center;
+  width: 100%;
+  position: fixed;
+  left: 50%;
+  transform: translateX(-50%);
+}
+
+.cls img{
+  width: 1.88rem;
+}
+
+.result-page{
+  display: none;
+}
+
+.reload{
+  margin-top: 0.5rem;
+  text-align: right;
+}
+
+#reload{
+  width: 1rem;
+}
+
+.result-page ul {
+  margin-left: 0.63rem;
+  margin-top: 0.5rem;
+  user-select: none;
+}
+
+.result-page ul li{
+  display: flex;
+  align-items: center;
+  margin-top: 0.63rem;
+  font-size: 24px;
+}
+
+.result-page ul li img{
+  width: 150px;
+  height: 150px;
+  object-fit: cover;
+  margin-right: 1.88rem;
+}
+.result-page ul li span{
+  width: 15.63rem;
+  line-height: 1.5;
+}
+
+.no-result{
+  box-sizing: border-box;
+  text-align: center;
+  margin-top: 20px;
+  display: none;
+}
+
+.no-result img{
+  width: 200px;
+  height:auto;
+}
+.no-result p{
+  line-height: 1.5;
+}
+
+.result-page{
+  box-sizing: border-box;
+}
+.reload{
+  padding-right: 30px;
+}
+::-webkit-scrollbar{
+  height: 0 !important;
+}

BIN
万物墙后台/shurufa1000X500/images/bg.png


BIN
万物墙后台/shurufa1000X500/images/bodang.png


BIN
万物墙后台/shurufa1000X500/images/close.png


BIN
万物墙后台/shurufa1000X500/images/cls.png


BIN
万物墙后台/shurufa1000X500/images/no-result.png


BIN
万物墙后台/shurufa1000X500/images/reload.png


BIN
万物墙后台/shurufa1000X500/images/二维码按钮.png


BIN
万物墙后台/shurufa1000X500/images/搜索按钮.png


BIN
万物墙后台/shurufa1000X500/images/暂停按钮.png


BIN
万物墙后台/shurufa1000X500/images/点赞按钮(已触发).png


BIN
万物墙后台/shurufa1000X500/images/点赞按钮(未触发).png


+ 246 - 0
万物墙后台/shurufa1000X500/index.html

@@ -0,0 +1,246 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no">
+  <link rel="stylesheet" href="./css/index.css">
+  <title>手写</title>
+  <script type="text/javascript" src="./md5.js"></script>
+  <style>
+    #clear2 {
+      opacity: 0;
+    }
+
+  </style>
+</head>
+
+<body>
+  <div class="body">
+    <!-- <img id="bg" class="bg" src="./images/bg.png" alt=""> -->
+    <div class="content">
+      <!-- <div class="title">搜索页面</div> -->
+      <div class="input">
+        <input id="input" type="text">
+        <span>
+          <img id="clsipt" src="./images/close.png" alt="">
+        </span>
+        <div id="search" class="button">搜索</div>
+      </div>
+
+      <!-- 搜索页面 -->
+      <div class="search-page">
+        <ul class="result">
+          <li>
+            <ul id="ret"></ul>
+          </li>
+          <li><img id="clear2" src="./images/close.png" alt=""></li>
+        </ul>
+        <div id="canvasWrap">
+          <canvas id="cav"></canvas>
+        </div>
+      </div>
+
+      <div class="result-page">
+        <div class="reload">
+          <img id="reload" src="./images/reload.png" alt="">
+        </div>
+        <ul>
+        </ul>
+        <div class="no-result">
+          <img src="./images/no-result.png" alt="">
+          <p>暂时没有结果呢,<br />请试一下其他关键字</p>
+        </div>
+      </div>
+
+      <!-- <div class="cls">
+        <img src="./images/cls.png" alt="">
+      </div> -->
+
+    </div>
+  </div>
+  <script src="./js/jquery.min.js"></script>
+  <!-- <script src="./js/handwritingapi.js"></script> -->
+  <script src="./js/index.js?t=20200921"></script>
+  <script type="text/javascript">
+    var index = 0;
+    var BH = "";
+    var Down = false;
+    let cav = document.getElementById("cav");
+    var ctx = cav.getContext("2d");
+    cav.width = 900;
+    cav.height = 340;
+    var lastX = -1,
+      lastY = -1;
+    var Timer = 0;
+
+
+    // 移动端禁止拉动页面
+    document.body.addEventListener('touchmove', function (e) {
+      e.preventDefault();
+    }, {
+      passive: false
+    });
+
+    // PC
+    cav.addEventListener("mousedown", onStartInput);
+    cav.addEventListener("mousemove", onMoveInput);
+    cav.addEventListener("mouseup", onOverInput);
+
+    // 手机
+    cav.addEventListener("touchstart", onStartInput);
+    cav.addEventListener("touchmove", onMoveInput);
+    cav.addEventListener("touchend", onOverInput);
+    cav.addEventListener("touchcancel", onOverInput);
+
+    function onStartInput(event) {
+      var event = event || window.event;
+
+      Down = true;
+      if (!event.touches) {
+        // pc
+        lastX = parseInt(event.offsetX);
+        lastY = parseInt(event.offsetY);
+      } else {
+        lastX = parseInt(event.touches[0].clientX - cav.offsetLeft);
+        lastY = parseInt(event.touches[0].clientY - cav.offsetTop);
+      }
+      // console.log("down");
+    }
+
+    function onMoveInput(event) {
+      var event = event || window.event;
+      if (Down) {
+        var x, y;
+        if (!event.touches) {
+          // pc
+          x = parseInt(event.offsetX);
+          y = parseInt(event.offsetY);
+        } else {
+          x = parseInt(event.touches[0].clientX - cav.offsetLeft);
+          y = parseInt(event.touches[0].clientY - cav.offsetTop);
+        }
+        BH += `${x},${y},`;
+        renderPoint(lastX, lastY, x, y);
+        lastX = x;
+        lastY = y;
+
+        // console.log("move");
+      }
+    }
+
+    function onOverInput(event) {
+      var event = event || window.event;
+      if (Down) {
+        // 加入一个笔画的结束符
+        Down = false;
+        BH += "-1,0,";
+
+        if (Timer != 0)
+          window.clearInterval(Timer);
+        Timer = self.setInterval("hwRecognition()", 1000);
+
+        // console.log("up");
+      }
+    }
+
+    function hwRecognition() {
+      var lang = 'zh-cn';
+
+      // 识别前要加入-1-1, 结束符
+      sk = BH + "-1,-1";
+      window.clearInterval(Timer);
+      var user = "testUser";
+      var token = hex_md5(hex_md5(sk) + user.toLowerCase() + "728420db91ffc71a4784ce4cef36d63b");
+      var dt = "user=" + user + "&token=" + token + "&sk=" + sk + "&lang=" + lang + "&os=Windows&multi=1&count=10";
+      request(dt);
+    }
+
+    // 输入框的X按钮
+    let inputX = document.querySelector('#clsipt')
+
+    // X按钮
+    let closeBtnDom = document.querySelector('#clear2')
+    closeBtnDom.onclick = (() => {
+      // 删除ul下面的所有子元素
+      ulDom.innerHTML = ''
+      // 清空写字板
+      resetCtx()
+      // 隐藏X按钮
+      closeBtnDom.style.opacity = 0
+    })
+
+
+    function request(data) {
+      let szURL = 'http://handwriting.dwinput.com:4555/temp/';
+      var xhr = new XMLHttpRequest();
+      xhr.open("POST", szURL, true);
+      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+      xhr.onreadystatechange = function () {
+        if (xhr.readyState == 4 && xhr.status == 200) {
+          let temp = xhr.responseText
+          // 笔画太少的时候 直接return
+          if (temp.includes('error')) return
+          temp = temp.split('\t')
+          let ul = document.querySelector('#ret')
+          // 生成的子元素文字
+          let liAll = ''
+          temp.forEach(v => {
+            liAll += `<li>${v}</li>`
+            ulDom.innerHTML = liAll
+          })
+          // 显示X按钮
+          closeBtnDom.style.opacity = 1
+          // document.getElementById("ret").value = xhr.responseText; 
+          //alert("识别结果:" + xhr.responseText);
+        }
+      }
+
+      try {
+        xhr.send(data);
+      } catch (e) {
+        return null;
+      }
+    }
+
+    // 给生成的li文字绑定点击事件
+    let ulDom = document.querySelector('#ret')
+    ulDom.onclick = ((e) => {
+      if (e.target.tagName === 'LI') {
+        // 获取当前点击的li文本
+        let txt = e.target.innerHTML
+        // 加到输入框后面
+        let inputDom = document.querySelector('#input')
+        inputDom.value = inputDom.value + txt
+        // 删除ul下面的所有子元素
+        ulDom.innerHTML = ''
+        // 清空写字板
+        resetCtx()
+        // 隐藏X按钮
+        closeBtnDom.style.opacity = 0
+        // 显示输入框的X按钮
+        inputX.style.opacity = 1
+      }
+    })
+
+    // 画线
+    function renderPoint(x1, y1, x2, y2) {
+      ctx.strokeStyle = '#EA9649';
+      ctx.save();
+      ctx.beginPath();
+      ctx.lineWidth = 5;
+      ctx.moveTo(x1, y1);
+      ctx.lineTo(x2, y2);
+      ctx.stroke();
+      ctx.restore();
+    }
+
+    function resetCtx() {
+      BH = "";
+      ctx.clearRect(0, 0, cav.width, cav.height);
+    }
+
+  </script>
+</body>
+
+</html>

+ 147 - 0
万物墙后台/shurufa1000X500/js/index.js

@@ -0,0 +1,147 @@
+$(function () {
+  // let base = 'http://project.4dage.com:8017'
+  let base = '/'
+
+  var stopClick = false
+
+  function getQueryString (value) {
+    var reg = new RegExp('(^|&)' + value + '=([^&]*)(&|$)', 'i')
+    var r = window.location.search.substr(1).match(reg)
+    if (r != null) return unescape(r[2]); return null
+  }
+  $('#canvas').attr('width', $('#canvasWrap').width())
+  $('#canvas').attr('height', $('#canvasWrap').height())
+
+  // init()
+
+  $('#clear').click(function () {
+    $('#clear').css('opacity', 0)
+    $('#result').html('')
+  })
+
+  $('#clsipt').click(function () {
+    $('#input').val('')
+    $('#clsipt').css('opacity', 0)
+    $('.search-page').show()
+    $('.result-page').hide()
+  })
+
+  $('#input').on('input propertychange', function () {
+    var count = $(this).val().length
+    $('#clsipt').css('opacity', count ? 1 : 0)
+  })
+
+  $('#search').click(function () {
+    search()
+  })
+
+  $('#reload').click(function () {
+    location.reload()
+  })
+
+  let startY = ''
+  let lastY = ''
+
+  let mMove = function (event) {
+    event.stopPropagation()
+    event.preventDefault()
+    let deltaY = event.clientY - startY
+    stopClick = true
+
+    if (lastY == deltaY) {
+      return
+    }
+    let de = document.documentElement.scrollTop || document.body.scrollTop
+    dic = lastY > deltaY ? 1 : -1
+    let to = de + dic * 15
+    window.scrollTo(0, to)
+    // lastY>deltaY?window.scrollTo(deltaY):'下'
+    lastY = deltaY
+  }
+
+  $('.body').mousedown(function (e) {
+    startY = e.clientY
+    stopClick = false
+    $('.body').mousemove(mMove)
+  })
+
+  $('.body').mouseup(function (e) {
+    $('.body').off('mousemove', mMove)
+  })
+  function callbackfunc (ret) {
+    let html = ''
+
+    ret.cand.forEach(item => {
+      html += `<li>${item}</li>`
+    })
+    $('#clear').css('opacity', 1)
+    $('#result').html(html)
+    $('#result').undelegate()
+    $('#result').delegate('li', 'click', function (e) {
+      e.stopPropagation()
+      e.preventDefault()
+      let target = e.target
+      $('#input').val($('#input').val() + $(target).text())
+      $('#clsipt').css('opacity', 1)
+      $('#clear').click()
+    })
+  }
+
+  function search () {
+    let data = {
+      id: getQueryString('id') || '',
+      name: $('#input').val()
+    }
+    $.ajax({
+      url: base + 'api/searchCollection',
+      // url: 'http://project.4dage.com:8018/' + 'api/searchCollection',
+      type: 'POST',
+      data: JSON.stringify(data),
+      dataType: 'json',
+      contentType: 'application/json;charset=utf-8',
+      success: function (data) {
+        if (data.code != 0) {
+          return alert(data.msg)
+        }
+        $('.search-page').hide()
+
+        if (data.data.length <= 0) {
+          $('.result-page').fadeIn()
+          $('.result-page ul').hide()
+          $('.no-result').fadeIn()
+        } else {
+          $('.no-result').hide()
+          $('.result-page').fadeIn()
+          $('.result-page ul').fadeIn()
+
+          let html = ``
+          data.data.forEach(item => {
+            html += `<li data-id="${item.id}">
+                      <img src="${item.pic}" data-id="${item.id}" alt="">
+                      <span data-id="${item.id}">${item.name}</span>
+                    </li>`
+          })
+          $('.result-page ul').html(html)
+          let arr = Array.from(document.querySelectorAll('.result-page ul li'))
+          arr.forEach(function (dom) {
+            dom.addEventListener('mouseup', function (e) {
+              let id = e.target.dataset.id
+              setTimeout(function () {
+                (window.resultCallback && !stopClick) && window.resultCallback(parseInt(id))
+              })
+            })
+          })
+        }
+      }
+    })
+  }
+
+  // function init () {
+  //   QQShuru.HWPanel({
+  //     canvasId: '#canvas',
+  //     lineColor: '#EA9649',
+  //     clearBtnId: '#clear',
+  //     callback: callbackfunc
+  //   })
+  // }
+})

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 4 - 0
万物墙后台/shurufa1000X500/js/jquery.min.js


+ 256 - 0
万物墙后台/shurufa1000X500/md5.js

@@ -0,0 +1,256 @@
+/*
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
+var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
+var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
+function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
+function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
+function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
+function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
+function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function md5_vm_test()
+{
+  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
+}
+
+/*
+ * Calculate the MD5 of an array of little-endian words, and a bit length
+ */
+function core_md5(x, len)
+{
+  /* append padding */
+  x[len >> 5] |= 0x80 << ((len) % 32);
+  x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+  var a =  1732584193;
+  var b = -271733879;
+  var c = -1732584194;
+  var d =  271733878;
+
+  for(var i = 0; i < x.length; i += 16)
+  {
+    var olda = a;
+    var oldb = b;
+    var oldc = c;
+    var oldd = d;
+
+    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
+    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
+    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
+    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
+    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
+    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
+    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
+    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
+    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
+    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
+    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
+    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
+    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
+    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
+
+    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
+    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
+    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
+    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
+    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
+    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
+    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
+    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
+    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
+    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
+    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
+    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
+    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
+    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
+    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
+
+    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
+    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
+    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
+    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
+    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
+    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
+    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
+    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
+    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
+    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
+    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
+    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
+    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
+    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
+    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
+
+    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
+    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
+    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
+    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
+    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
+    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
+    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
+    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
+    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
+    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
+    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
+    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
+    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
+    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
+    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+
+    a = safe_add(a, olda);
+    b = safe_add(b, oldb);
+    c = safe_add(c, oldc);
+    d = safe_add(d, oldd);
+  }
+  return Array(a, b, c, d);
+
+}
+
+/*
+ * These functions implement the four basic operations the algorithm uses.
+ */
+function md5_cmn(q, a, b, x, s, t)
+{
+  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
+}
+function md5_ff(a, b, c, d, x, s, t)
+{
+  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
+}
+function md5_gg(a, b, c, d, x, s, t)
+{
+  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
+}
+function md5_hh(a, b, c, d, x, s, t)
+{
+  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
+}
+function md5_ii(a, b, c, d, x, s, t)
+{
+  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
+}
+
+/*
+ * Calculate the HMAC-MD5, of a key and some data
+ */
+function core_hmac_md5(key, data)
+{
+  var bkey = str2binl(key);
+  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
+
+  var ipad = Array(16), opad = Array(16);
+  for(var i = 0; i < 16; i++)
+  {
+    ipad[i] = bkey[i] ^ 0x36363636;
+    opad[i] = bkey[i] ^ 0x5C5C5C5C;
+  }
+
+  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
+  return core_md5(opad.concat(hash), 512 + 128);
+}
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+  return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+  return (num << cnt) | (num >>> (32 - cnt));
+}
+
+/*
+ * Convert a string to an array of little-endian words
+ * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
+ */
+function str2binl(str)
+{
+  var bin = Array();
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < str.length * chrsz; i += chrsz)
+    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
+  return bin;
+}
+
+/*
+ * Convert an array of little-endian words to a string
+ */
+function binl2str(bin)
+{
+  var str = "";
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < bin.length * 32; i += chrsz)
+    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
+  return str;
+}
+
+/*
+ * Convert an array of little-endian words to a hex string.
+ */
+function binl2hex(binarray)
+{
+  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i++)
+  {
+    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
+           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
+  }
+  return str;
+}
+
+/*
+ * Convert an array of little-endian words to a base-64 string
+ */
+function binl2b64(binarray)
+{
+  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i += 3)
+  {
+    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
+                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
+                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
+    for(var j = 0; j < 4; j++)
+    {
+      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
+      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
+    }
+  }
+  return str;
+}