{"id":351,"date":"2013-12-16T12:48:56","date_gmt":"2013-12-16T12:48:56","guid":{"rendered":"efe937780e95574250dabe07151bdc23"},"modified":"2013-12-16T12:48:56","modified_gmt":"2013-12-16T12:48:56","slug":"","status":"publish","type":"post","link":"https:\/\/www.xiaobo.li\/notes\/archives\/351","title":{"rendered":"js oauth_v1.0"},"content":{"rendered":"<pre class=\"brush:js; toolbar: true; auto-links: true;\">\/* ***** BEGIN LICENSE BLOCK *****\r\n* Version: MPL 1.1\/GPL 2.0\/LGPL 2.1\r\n*\r\n* The contents of this file are subject to the Mozilla Public License Version\r\n* 1.1 (the \"License\"); you may not use this file except in compliance with\r\n* the License. You may obtain a copy of the License at\r\n* http:\/\/www.mozilla.org\/MPL\/\r\n*\r\n* Software distributed under the License is distributed on an \"AS IS\" basis,\r\n* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r\n* for the specific language governing rights and limitations under the\r\n* License.\r\n*\r\n* The Original Code is FireUploader\r\n*\r\n* The Initial Developer of the Original Code is Rahul Jonna.\r\n*\r\n* Portions created by the Initial Developer are Copyright (C) 2007-2009\r\n* the Initial Developer. All Rights Reserved.\r\n*\r\n* Alternatively, the contents of this file may be used under the terms of\r\n* either the GNU General Public License Version 2 or later (the \"GPL\"), or\r\n* the GNU Lesser General Public License Version 2.1 or later (the \"LGPL\"),\r\n* in which case the provisions of the GPL or the LGPL are applicable instead\r\n* of those above. If you wish to allow use of your version of this file only\r\n* under the terms of either the GPL or the LGPL, and not to allow others to\r\n* use your version of this file under the terms of the MPL, indicate your\r\n* decision by deleting the provisions above and replace them with the notice\r\n* and other provisions required by the GPL or the LGPL. If you do not delete\r\n* the provisions above, a recipient may use your version of this file under\r\n* the terms of any one of the MPL, the GPL or the LGPL.\r\n*\r\n* ***** END LICENSE BLOCK ***** *\/\r\n\r\nvar SoundCloud = {};\r\n\r\n(function()\r\n{\r\n    \/**\r\n    * USAGE:\r\n    * \r\n    * @param {Object} loginUrl - The webpage url for login\r\n    * @param {Object} apiUrl - The api end point\r\n    * @param {Object} apiKey\r\n    * @param {Object} secretKey\r\n    * @param {Object} additionalParams - Additional parameters to send if any, like version number etc\r\n    * @param {Object} afterAuthorizeCallback - callback function that is called after authentication\r\n    *\r\n    * var oAuth = new SoundCloud.OAuth(\"http:\/\/api.soundcloud.com\/oauth\/authorize\", \"http:\/\/api.soundcloud.com\/\", \r\n    *\t\"your_api_key\", \"your_api_secret\", {\"version\": \"1.0\"}, function(oauthObj) {});\r\n    * oAuth.startAuthentication(); \r\n    *\t\r\n    * At the end, oauthObj.accessToken and oauthObj.accessTokenSecret will have the access token and token secret respectively\r\n    *\r\n    *\/\r\n    function x_OAuth(loginUrl, apiUrl, apiKey, secretKey, additionalParams, afterAuthorizeCallback)\r\n    {\r\n        this.loginUrl = loginUrl;\r\n        this.apiUrl = apiUrl;\r\n        this.apiKey = apiKey;\r\n        this.secretKey = secretKey;\r\n\r\n        this.requestToken;\r\n        this.accessToken;\r\n\r\n        this.requestTokenSecret;\r\n        this.accessTokenSecret;\r\n\r\n        this.afterAuthorizeCallback = afterAuthorizeCallback;\r\n        this.userName;\r\n\r\n        for (var key in additionalParams)\r\n            this[key] = additionalParams[key];\r\n    }\r\n\r\n    x_OAuth.prototype = {\r\n\r\n        \/\/starts the authentication process\t\r\n        startAuthentication: function()\r\n        {\r\n            this.getRequestToken();\r\n        },\r\n\r\n        getParamString: function(params)\r\n        {\r\n            var arr = [], i = 0;\r\n            for (var key in params)\r\n            {\r\n                arr[i++] = key + \"=\" + params[key];\r\n            }\r\n            return arr.join(\"&amp;\");\r\n        },\r\n\r\n        \/\/encodes the special characters according to the RFC standard\r\n        rfcEncoding: function(str)\r\n        {\r\n            var tmp = encodeURIComponent(str);\r\n            tmp = tmp.replace('!', '%21');\r\n            tmp = tmp.replace('*', '%2A');\r\n            tmp = tmp.replace('(', '%28');\r\n            tmp = tmp.replace(')', '%29');\r\n            tmp = tmp.replace(\"'\", '%27');\r\n            return tmp;\r\n        },\r\n\r\n        \/\/assigns the common parameters for all requests\r\n        getCommonParams: function(params)\r\n        {\r\n            params = params || [];\r\n            params[\"oauth_consumer_key\"] = this.apiKey;\r\n            params[\"oauth_timestamp\"] = Math.ceil((new Date()).getTime() \/ 1000);\r\n            params[\"oauth_nonce\"] = (new Date()).getTime();\r\n            params[\"oauth_version\"] = this.version;\r\n            if (this.format)\r\n                params[\"format\"] = this.format;\r\n            params[\"oauth_signature_method\"] = \"HMAC-SHA1\";\r\n\r\n            return params;\r\n        },\r\n\r\n        getSecretKey: function(tokenType)\r\n        {\r\n            return this.secretKey +\r\n\t\t\t\"&amp;\" +\r\n\t\t\t((tokenType == \"beforeAuthentication\") ? \"\" : ((tokenType == \"request\") ? this.requestTokenSecret : this.accessTokenSecret));\r\n        },\r\n\r\n        \/\/makes the signature using SHA1 algorithm\r\n        getSignature: function(method, url, paramString, tokenType)\r\n        {\r\n            var stringToSign = [this.rfcEncoding(method), this.rfcEncoding(url), this.rfcEncoding(paramString)].join(\"&amp;\");\r\n            return Soundcloud.SHA1.b64_hmac_sha1(this.getSecretKey(tokenType), stringToSign);\r\n        },\r\n\r\n        \/\/gets the request token\r\n        getRequestToken: function()\r\n        {\r\n            var params = this.getCommonParams();\r\n\r\n            var url = this.apiUrl + \"oauth\/request_token\";\r\n            var paramString = this.normalizeParams(params);\r\n            var method = \"POST\";\r\n            var signature = this.getSignature(method, url, paramString, \"beforeAuthentication\");\r\n            paramString += \"&amp;oauth_signature=\" + this.rfcEncoding(signature);\r\n\r\n            Soundcloud.xhttp.doRequest(method, url, paramString, \"\", false, null, this, function(objResponse)\r\n            {\r\n                if (!objResponse.hasErrors)\r\n                {\r\n                    objResponse.responseText = Soundcloud.utils.trimWhitespace(objResponse.responseText) + \"&amp;\";\r\n                    var reg1 = \/oauth_token=(.*?)&amp;\/gi;\r\n                    var reg2 = \/oauth_token_secret=(.*?)&amp;\/gi;\r\n                    var arrToken = reg1.exec(objResponse.responseText);\r\n                    if (arrToken)\r\n                    {\r\n                        this.requestToken = arrToken[1];\r\n                        this.showLoginPage(arrToken[1]);\r\n                    }\r\n                    else\r\n                        throw new Error(\"Failed to get request token\");\r\n\r\n                    var arrTokenSecret = reg2.exec(objResponse.responseText);\r\n                    if (arrTokenSecret)\r\n                        this.requestTokenSecret = arrTokenSecret[1];\r\n                    else\r\n                        throw new Error(\"Failed to get request token\");\r\n                }\r\n                else\r\n                    throw new Error(\"Failed to get request token\");\r\n            });\r\n        },\r\n\r\n        \/\/get access token\r\n        getAccessToken: function(token)\r\n        {\r\n            var params = this.getCommonParams();\r\n            params[\"oauth_token\"] = token;\r\n            var url = this.apiUrl + \"oauth\/access_token\";\r\n            var paramString = this.normalizeParams(params);\r\n            var method = \"POST\";\r\n            var signature = this.getSignature(method, url, paramString, \"request\");\r\n            paramString += \"&amp;oauth_signature=\" + this.rfcEncoding(signature);\r\n\r\n            Soundcloud.xhttp.doRequest(method, url, \"\", paramString, false, null, this, function(objResponse)\r\n            {\r\n                if (!objResponse.hasErrors)\r\n                {\r\n                    var tokenList = objResponse.responseText.split(\"&amp;\");\r\n\r\n                    var reg1 = \/oauth_token=(.*)\/gi;\r\n                    var reg2 = \/oauth_token_secret=(.*)\/gi;\r\n\r\n                    var accessToken, tokenSecret;\r\n                    var arrToken = reg1.exec(tokenList[0]);\r\n                    if (arrToken)\r\n                    {\r\n                        this.accessToken = arrToken[1];\r\n                    }\r\n                    else\r\n                    {\r\n                        throw new Error(\"Failed to get access token. Check if your username and password is valid.\");\r\n                    }\r\n                    var arrTokenSecret = reg2.exec(tokenList[1]);\r\n                    if (arrTokenSecret)\r\n                    {\r\n                        this.accessTokenSecret = arrTokenSecret[1];\r\n                    }\r\n                    else\r\n                    {\r\n                        throw new Error(\"Failed to get access token. Check if your username and password is valid.\");\r\n                    }\r\n                    if (this.afterAuthorizeCallback)\r\n                    {\r\n                        this.afterAuthorizeCallback.call(null, this);\r\n                    }\r\n                }\r\n                else\r\n                    throw new Error(\"Failed to get access token. Check if your username and password is valid.\");\r\n            });\r\n        },\r\n\r\n        \/\/sorts the parameters and creats a GET string to be sent to the server\r\n        normalizeParams: function(params)\r\n        {\r\n            for (var key in params)\r\n                params[key] = this.rfcEncoding(params[key]);\r\n\r\n            return Soundcloud.utils.join(\"&amp;\", \"=\", params, true);\r\n        },\r\n\r\n        \/\/show the login page\r\n        showLoginPage: function(token)\r\n        {\r\n            var doneAuthorizing = false;\r\n            var callbackFunc = function(isDone)\r\n            {\r\n                doneAuthorizing = isDone;\r\n            };\r\n\r\n            var url = this.loginUrl + \"?oauth_token=\" + token;\r\n            window.openDialog(\"chrome:\/\/fireuploader\/content\/loginPanel.xul\", \"Login\/Authorization Panel\", \"chrome,centerscreen,modal,width=350,height=400\", url, callbackFunc);\r\n            if (doneAuthorizing)\r\n            {\r\n                this.getAccessToken(token);\r\n            }\r\n        }\r\n    };\r\n\r\n    this.OAuth = x_OAuth;\r\n\r\n    this.utils = {\r\n        join: function(separator1, separator2, arr, sort)\r\n        {\r\n            var arrKeys = [];\r\n            for (var key in arr)\r\n            {\r\n                arrKeys.push(key);\r\n            }\r\n            if (sort)\r\n                arrKeys.sort();\r\n\r\n            var newArr = [];\r\n            for (var i = 0; i &lt; arrKeys.length; i++)\r\n            {\r\n                if (separator2 != \"\")\r\n                {\r\n                    newArr.push(arrKeys[i] + separator2 + arr[arrKeys[i]]);\r\n                }\r\n                else\r\n                {\r\n                    newArr.push(arrKeys[i]);\r\n                    newArr.push(arr[arrKeys[i]]);\r\n                }\r\n            }\r\n\r\n            return newArr.join(separator1);\r\n        },\r\n\r\n        \/\/ Remove leading and trailing whitespace from a string\r\n        trimWhitespace: function(str)\r\n        {\r\n            return str.replace(\/^\\s*(\\S*(\\s+\\S+)*)\\s*$\/, \"$1\");\r\n        }\r\n    }\r\n\r\n    this.xhttp = {\r\n        \/\/a wrapper to XMLHttpRequest object\r\n\r\n        \/**\r\n        * @param {string} verb - GET, POST, PUT, DELETE\r\n        * @param {string} resLoc - Url of the resource\r\n        * @param {string} getData - Data that's sent in the url\r\n        * @param {string} objData - Data that's sent during POST, PUT\r\n        * @param {bool} isSync - whether to make a syncronous or asynchronous request\r\n        * @param {Object} arrHeaders - array of headers(name, value pairs) that's sent in the request \r\n        * @param {Object} callbackObject - scope of the callback function\r\n        * @param {Object} callbackFunc - callback function that's called after asyncronous response\r\n        *\/\r\n        doRequest: function(verb, resLoc, getData, objData, isSync, arrHeaders, callbackObject, callbackFunc)\r\n        {\r\n            try\r\n            {\r\n                var xmlhttp = new XMLHttpRequest();\r\n                if (getData != \"\")\r\n                    getData = \"?\" + getData;\r\n\r\n                resLoc = encodeURI(resLoc);\r\n                var aUrl = (resLoc.indexOf(\"http\") == -1) ? this.host + resLoc + getData : resLoc + getData;\r\n                xmlhttp.open(verb, aUrl, !isSync);\r\n\r\n                if (verb == \"POST\")\r\n                    xmlhttp.setRequestHeader('Content-Type', 'application\/x-www-form-urlencoded; charset=utf-8');\r\n\r\n                if (arrHeaders instanceof Array)\r\n                {\r\n                    for (var i = 0; i &lt; arrHeaders.length; i++)\r\n                    {\r\n                        xmlhttp.setRequestHeader(arrHeaders[i].name, arrHeaders[i].value);\r\n                    }\r\n                }\r\n\r\n                xmlhttp.send(objData);\r\n\r\n                var domParser = new DOMParser(); \/\/Components.classes[\"@mozilla.org\/xmlextras\/domparser;1\"].createInstance(Components.interfaces.nsIDOMParser);\r\n                if (isSync)\r\n                {\r\n                    if (xmlhttp.status &gt;= 200 &amp;&amp; xmlhttp.status &lt; 300)\r\n                    {\r\n                        try\r\n                        {\r\n                            var xmlDoc1 = domParser.parseFromString(xmlhttp.responseText, \"text\/xml\");\r\n                        }\r\n                        catch (ex)\r\n\t\t\t\t\t\t\t\t{ }\r\n\r\n                        var responseObject = {\r\n                            responseText: xmlhttp.responseText,\r\n                            xmlDoc: xmlDoc1,\r\n                            strHeaders: xmlhttp.getAllResponseHeaders()\r\n                        };\r\n                        callbackFunc.call(callbackObject, responseObject);\r\n                        return responseObject;\r\n                    }\r\n                    else\r\n                    {\r\n\r\n                        try\r\n                        {\r\n                            var xmlDoc1 = domParser.parseFromString(xmlhttp.responseText, \"text\/xml\");\r\n                        }\r\n                        catch (ex2)\r\n                        {\r\n                            alert(ex2);\r\n                        }\r\n                        var errorMessage = \"Error connecting! Try again - \" + xmlhttp.status + \" \" + xmlhttp.statusText;\r\n\r\n                        if (xmlDoc1 != null &amp;&amp; xmlDoc1.getElementsByTagName(\"Message\")[0])\r\n                            errorMessage = xmlDoc1.getElementsByTagName(\"Message\")[0].firstChild.nodeValue;\r\n\r\n                        var responseObject = {\r\n                            responseText: xmlhttp.responseText,\r\n                            xmlDoc: xmlDoc1,\r\n                            strHeaders: xmlhttp.getAllResponseHeaders(),\r\n                            errorMessage: errorMessage,\r\n                            hasErrors: true\r\n                        };\r\n\r\n                        callbackFunc.call(callbackObject, responseObject);\r\n\r\n                        return false;\r\n                    }\r\n                }\r\n                else\r\n                {\r\n                    xmlhttp.onreadystatechange = function()\r\n                    {\r\n                        if (xmlhttp.readyState != 4)\r\n                            return;\r\n                        else\r\n                        {\r\n                            if (xmlhttp.status &gt;= 200 &amp;&amp; xmlhttp.status &lt; 300)\r\n                            {\r\n                                try\r\n                                {\r\n                                    var xmlDoc1 = domParser.parseFromString(xmlhttp.responseText, \"text\/xml\");\r\n                                }\r\n                                catch (ex)\r\n\t\t\t\t\t\t\t\t{ }\r\n                                var responseObject = {\r\n                                    responseText: xmlhttp.responseText,\r\n                                    xmlDoc: xmlDoc1,\r\n                                    strHeaders: xmlhttp.getAllResponseHeaders()\r\n                                };\r\n                                callbackFunc.call(callbackObject, responseObject);\r\n                            }\r\n                            else\r\n                            {\r\n                                try\r\n                                {\r\n                                    var xmlDoc1 = domParser.parseFromString(xmlhttp.responseText, \"text\/xml\");\r\n                                }\r\n                                catch (ex)\r\n\t\t\t\t\t\t\t\t{ }\r\n                                var errorMessage = \"Error connecting! Try again - \" + xmlhttp.status + \" \" + xmlhttp.statusText;\r\n                                if (xmlDoc1 != null &amp;&amp; xmlDoc1.getElementsByTagName(\"Message\")[0])\r\n                                    errorMessage = xmlDoc1.getElementsByTagName(\"Message\")[0].firstChild.nodeValue;\r\n\r\n                                var responseObject = {\r\n                                    responseText: xmlhttp.responseText,\r\n                                    xmlDoc: xmlDoc1,\r\n                                    strHeaders: xmlhttp.getAllResponseHeaders(),\r\n                                    errorMessage: errorMessage,\r\n                                    hasErrors: true\r\n                                };\r\n                                callbackFunc.call(callbackObject, responseObject);\r\n                            }\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            catch (ex)\r\n            {\r\n                alert(ex);\r\n            }\r\n        }\r\n    }\r\n\r\n    this.SHA1 =\r\n    {\r\n        \/*\r\n        * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined\r\n        * in FIPS PUB 180-1\r\n        * Version 2.1a Copyright Paul Johnston 2000 - 2002.\r\n        * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\r\n        * Distributed under the BSD License\r\n        * See http:\/\/pajhome.org.uk\/crypt\/md5 for details.  \r\n        *\/\r\n\r\n        \/*\r\n        * Configurable variables. You may need to tweak these to be compatible with\r\n        * the server-side, but the defaults work in most cases.\r\n        *\/\r\n        hexcase: 0,  \/* hex output format. 0 - lowercase; 1 - uppercase        *\/\r\n        b64pad: \"=\", \/* base-64 pad character. \"=\" for strict RFC compliance   *\/\r\n        chrsz: 8,  \/* bits per input character. 8 - ASCII; 16 - Unicode      *\/\r\n\r\n        \/*\r\n        * These are the functions you'll usually want to call\r\n        * They take string arguments and return either hex or base-64 encoded strings\r\n        *\/\r\n        hex_sha1: function(s) { return this.binb2hex(this.core_sha1(this.str2binb(s), s.length * this.chrsz)); },\r\n        b64_sha1: function(s) { return this.binb2b64(this.core_sha1(this.str2binb(s), s.length * this.chrsz)); },\r\n        str_sha1: function(s) { return this.binb2str(this.core_sha1(this.str2binb(s), s.length * this.chrsz)); },\r\n        hex_hmac_sha1: function(key, data) { return this.binb2hex(this.core_hmac_sha1(key, data)); },\r\n        b64_hmac_sha1: function(key, data) { return this.binb2b64(this.core_hmac_sha1(key, data)); },\r\n        str_hmac_sha1: function(key, data) { return this.binb2str(this.core_hmac_sha1(key, data)); },\r\n\r\n        \/*\r\n        * Perform a simple self-test to see if the VM is working\r\n        *\/\r\n        sha1_vm_test: function()\r\n        {\r\n            return hex_sha1(\"abc\") == \"a9993e364706816aba3e25717850c26c9cd0d89d\";\r\n        },\r\n\r\n        \/*\r\n        * Calculate the SHA-1 of an array of big-endian words, and a bit length\r\n        *\/\r\n        core_sha1: function(x, len)\r\n        {\r\n            \/* append padding *\/\r\n            x[len &gt;&gt; 5] |= 0x80 &lt;&lt; (24 - len % 32);\r\n            x[((len + 64 &gt;&gt; 9) &lt;&lt; 4) + 15] = len;\r\n\r\n            var w = Array(80);\r\n            var a = 1732584193;\r\n            var b = -271733879;\r\n            var c = -1732584194;\r\n            var d = 271733878;\r\n            var e = -1009589776;\r\n\r\n            for (var i = 0; i &lt; x.length; i += 16)\r\n            {\r\n                var olda = a;\r\n                var oldb = b;\r\n                var oldc = c;\r\n                var oldd = d;\r\n                var olde = e;\r\n\r\n                for (var j = 0; j &lt; 80; j++)\r\n                {\r\n                    if (j &lt; 16) w[j] = x[i + j];\r\n                    else w[j] = this.rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);\r\n                    var t = this.safe_add(this.safe_add(this.rol(a, 5), this.sha1_ft(j, b, c, d)),\r\n\t\t\t\t\t\t    this.safe_add(this.safe_add(e, w[j]), this.sha1_kt(j)));\r\n                    e = d;\r\n                    d = c;\r\n                    c = this.rol(b, 30);\r\n                    b = a;\r\n                    a = t;\r\n                }\r\n\r\n                a = this.safe_add(a, olda);\r\n                b = this.safe_add(b, oldb);\r\n                c = this.safe_add(c, oldc);\r\n                d = this.safe_add(d, oldd);\r\n                e = this.safe_add(e, olde);\r\n            }\r\n            return Array(a, b, c, d, e);\r\n        },\r\n\r\n        \/*\r\n        * Perform the appropriate triplet combination function for the current\r\n        * iteration\r\n        *\/\r\n        sha1_ft: function(t, b, c, d)\r\n        {\r\n            if (t &lt; 20) return (b &amp; c) | ((~b) &amp; d);\r\n            if (t &lt; 40) return b ^ c ^ d;\r\n            if (t &lt; 60) return (b &amp; c) | (b &amp; d) | (c &amp; d);\r\n            return b ^ c ^ d;\r\n        },\r\n\r\n        \/*\r\n        * Determine the appropriate additive constant for the current iteration\r\n        *\/\r\n        sha1_kt: function(t)\r\n        {\r\n            return (t &lt; 20) ? 1518500249 : (t &lt; 40) ? 1859775393 :\r\n\t\t\t    (t &lt; 60) ? -1894007588 : -899497514;\r\n        },\r\n\r\n        \/*\r\n        * Calculate the HMAC-SHA1 of a key and some data\r\n        *\/\r\n        core_hmac_sha1: function(key, data)\r\n        {\r\n            var bkey = this.str2binb(key);\r\n            if (bkey.length &gt; 16) bkey = this.core_sha1(bkey, key.length * this.chrsz);\r\n\r\n            var ipad = Array(16), opad = Array(16);\r\n            for (var i = 0; i &lt; 16; i++)\r\n            {\r\n                ipad[i] = bkey[i] ^ 0x36363636;\r\n                opad[i] = bkey[i] ^ 0x5C5C5C5C;\r\n            }\r\n\r\n            var hash = this.core_sha1(ipad.concat(this.str2binb(data)), 512 + data.length * this.chrsz);\r\n            return this.core_sha1(opad.concat(hash), 512 + 160);\r\n        },\r\n\r\n        \/*\r\n        * Add integers, wrapping at 2^32. This uses 16-bit operations internally\r\n        * to work around bugs in some JS interpreters.\r\n        *\/\r\n        safe_add: function(x, y)\r\n        {\r\n            var lsw = (x &amp; 0xFFFF) + (y &amp; 0xFFFF);\r\n            var msw = (x &gt;&gt; 16) + (y &gt;&gt; 16) + (lsw &gt;&gt; 16);\r\n            return (msw &lt;&lt; 16) | (lsw &amp; 0xFFFF);\r\n        },\r\n\r\n        \/*\r\n        * Bitwise rotate a 32-bit number to the left.\r\n        *\/\r\n        rol: function(num, cnt)\r\n        {\r\n            return (num &lt;&lt; cnt) | (num &gt;&gt;&gt; (32 - cnt));\r\n        },\r\n\r\n        \/*\r\n        * Convert an 8-bit or 16-bit string to an array of big-endian words\r\n        * In 8-bit function, characters &gt;255 have their hi-byte silently ignored.\r\n        *\/\r\n        str2binb: function(str)\r\n        {\r\n            var bin = Array();\r\n            var mask = (1 &lt;&lt; this.chrsz) - 1;\r\n            for (var i = 0; i &lt; str.length * this.chrsz; i += this.chrsz)\r\n                bin[i &gt;&gt; 5] |= (str.charCodeAt(i \/ this.chrsz) &amp; mask) &lt;&lt; (32 - this.chrsz - i % 32);\r\n            return bin;\r\n        },\r\n\r\n        \/*\r\n        * Convert an array of big-endian words to a string\r\n        *\/\r\n        binb2str: function(bin)\r\n        {\r\n            var str = \"\";\r\n            var mask = (1 &lt;&lt; this.chrsz) - 1;\r\n            for (var i = 0; i &lt; bin.length * 32; i += this.chrsz)\r\n                str += String.fromCharCode((bin[i &gt;&gt; 5] &gt;&gt;&gt; (32 - this.chrsz - i % 32)) &amp; mask);\r\n            return str;\r\n        },\r\n\r\n        \/*\r\n        * Convert an array of big-endian words to a hex string.\r\n        *\/\r\n        binb2hex: function(binarray)\r\n        {\r\n            var hex_tab = this.hexcase ? \"0123456789ABCDEF\" : \"0123456789abcdef\";\r\n            var str = \"\";\r\n            for (var i = 0; i &lt; binarray.length * 4; i++)\r\n            {\r\n                str += hex_tab.charAt((binarray[i &gt;&gt; 2] &gt;&gt; ((3 - i % 4) * 8 + 4)) &amp; 0xF) +\r\n\t\t\t    hex_tab.charAt((binarray[i &gt;&gt; 2] &gt;&gt; ((3 - i % 4) * 8)) &amp; 0xF);\r\n            }\r\n            return str;\r\n        },\r\n\r\n        \/*\r\n        * Convert an array of big-endian words to a base-64 string\r\n        *\/\r\n        binb2b64: function(binarray)\r\n        {\r\n            var tab = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\/\";\r\n            var str = \"\";\r\n            for (var i = 0; i &lt; binarray.length * 4; i += 3)\r\n            {\r\n                var triplet = (((binarray[i &gt;&gt; 2] &gt;&gt; 8 * (3 - i % 4)) &amp; 0xFF) &lt;&lt; 16)\r\n\t\t\t\t\t    | (((binarray[i + 1 &gt;&gt; 2] &gt;&gt; 8 * (3 - (i + 1) % 4)) &amp; 0xFF) &lt;&lt; 8)\r\n\t\t\t\t\t    | ((binarray[i + 2 &gt;&gt; 2] &gt;&gt; 8 * (3 - (i + 2) % 4)) &amp; 0xFF);\r\n                for (var j = 0; j &lt; 4; j++)\r\n                {\r\n                    if (i * 8 + j * 6 &gt; binarray.length * 32) str += this.b64pad;\r\n                    else str += tab.charAt((triplet &gt;&gt; 6 * (3 - j)) &amp; 0x3F);\r\n                }\r\n            }\r\n            return str;\r\n        }\r\n    }\r\n}).call(SoundCloud);<\/pre>\n","protected":false},"excerpt":{"rendered":"<pre class=\"brush:js; toolbar: true; auto-links: true;\">\/* ***** BEGIN LICENSE BLOCK *****\r\n* Version: MPL 1.1\/GPL 2.0\/LGPL 2.1\r\n*\r\n* The contents of this file are subject to the Mozilla Public License Version\r\n* 1.1 (the \"License\"); you may not use this file except in compliance with\r\n* the License. You may obtain a copy of the License at\r\n* http:\/\/ww...<\/pre>\n<p> <a href=\"https:\/\/www.xiaobo.li\/notes\/archives\/351\">\u7ee7\u7eed\u9605\u8bfb <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[277],"tags":[9,155],"class_list":["post-351","post","type-post","status-publish","format-standard","hentry","category-javascript","tag-js","tag-oauth"],"_links":{"self":[{"href":"https:\/\/www.xiaobo.li\/notes\/wp-json\/wp\/v2\/posts\/351","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.xiaobo.li\/notes\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.xiaobo.li\/notes\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.xiaobo.li\/notes\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.xiaobo.li\/notes\/wp-json\/wp\/v2\/comments?post=351"}],"version-history":[{"count":0,"href":"https:\/\/www.xiaobo.li\/notes\/wp-json\/wp\/v2\/posts\/351\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.xiaobo.li\/notes\/wp-json\/wp\/v2\/media?parent=351"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.xiaobo.li\/notes\/wp-json\/wp\/v2\/categories?post=351"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.xiaobo.li\/notes\/wp-json\/wp\/v2\/tags?post=351"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}