From 063bb3551ba9531d59832401136822d0412e37fc Mon Sep 17 00:00:00 2001 From: David Lee Date: Tue, 4 Feb 2020 10:49:15 +0800 Subject: [PATCH] Deterministic assignment related changes (#49) * added Mojito userID generator * added MD5 lib's license --- LICENSE | 20 ++++ lib/mojito.js | 254 ++++++++++++++++++++++++++++++++++++++++++++++++-- license.txt | 1 + 3 files changed, 268 insertions(+), 7 deletions(-) diff --git a/LICENSE b/LICENSE index f2ca6b6..3dfd454 100644 --- a/LICENSE +++ b/LICENSE @@ -75,3 +75,23 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +====================================================================== + +Copyright (c) 2011 Sebastian Tschan, https://blueimp.net + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/lib/mojito.js b/lib/mojito.js index 3b593b8..73320c2 100644 --- a/lib/mojito.js +++ b/lib/mojito.js @@ -93,7 +93,7 @@ Mojito = (function () } if (simpleRateSet && totalSimpleRate != 1) throw new Error('The sum of all the simple rates must be equal to 1'); - + // Storage adapter definition priority: 1) Test adapter; 2) Global adapter; 3) Default adapter if (!this.options.storageAdapter) { @@ -188,7 +188,7 @@ Mojito = (function () if (inTest === null && isLive) { inTest = (this.options.sampleRate <= 0) ? false : (this.getRandom() <= this.options.sampleRate); - + if (inTest) newToThisTest = true; } @@ -252,7 +252,7 @@ Mojito = (function () this.injectCSS(recipe.css); } // Recipe level js - if (recipe.js) + if (recipe.js) { recipe.js(this); } @@ -264,7 +264,7 @@ Mojito = (function () catch(err) { this.trackRecipeFailureEvent(err); - this.log("Test Object [" + this.options.name + "][" + this.options.id + "] recipe onChosen [" + recipe.name + "][" + recipe.id + "] failed, error: "+err.message||err, 'error'); + this.log("Test Object [" + this.options.name + "][" + this.options.id + "] recipe onChosen [" + recipe.name + "][" + recipe.id + "] failed, error: " + (err.message||err), 'error'); } return success; @@ -903,6 +903,66 @@ Mojito = (function () { this.domWatcher.observe(elements[i], watchOptions); } + }, + /** + * get user id (uuidv4) + */ + getMojitoUserId: function () + { + var cookieName = '_mjo', + expires = 730, + userId = Cookies.get(cookieName); + + if (userId) + { + Cookies.set(cookieName, userId, {expires: expires}); + return userId; + } + + /** + * Fast UUID generator, RFC4122 version 4 compliant. + * @author Jeff Ward (jcward.com). + * @license MIT license + * @link http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 + **/ + var lut = []; + for (var i = 0; i < 256; i++) + { + lut[i] = (i < 16 ? '0' : '') + (i).toString(16); + } + + var randomFn = function () + { + var rand; + try + { + rand = crypto.getRandomValues(new Uint32Array(1))[0]; + } + catch (e) + { + rand = Math.random() * 0xffffffff; + } + + return rand; + }; + + function e7() + { + var d0 = randomFn() | 0; + var d1 = randomFn() | 0; + var d2 = randomFn() | 0; + var d3 = randomFn() | 0; + + return lut[d0 & 0xff] + lut[d0 >> 8 & 0xff] + lut[d0 >> 16 & 0xff] + lut[d0 >> 24 & 0xff] + '-' + + lut[d1 & 0xff] + lut[d1 >> 8 & 0xff] + '-' + lut[d1 >> 16 & 0x0f | 0x40] + lut[d1 >> 24 & 0xff] + '-' + + lut[d2 & 0x3f | 0x80] + lut[d2 >> 8 & 0xff] + '-' + lut[d2 >> 16 & 0xff] + lut[d2 >> 24 & 0xff] + + lut[d3 & 0xff] + lut[d3 >> 8 & 0xff] + lut[d3 >> 16 & 0xff] + lut[d3 >> 24 & 0xff]; + } + + userId = e7(); + Cookies.set(cookieName, userId, {expires: expires}); + + return userId; } }; @@ -1015,9 +1075,8 @@ Mojito = (function () }; // Adapted from https://github.com/requirejs/domReady - var domReadyUtil = (function () + Utils.domReady = (function () { - var readyCalls = [], isPageLoaded = false , scrollIntervalId, testDiv, isTop; @@ -1117,7 +1176,188 @@ Mojito = (function () return domReady; })(); - Utils.domReady = domReadyUtil; + /* + * JavaScript MD5 + * https://github.com/blueimp/JavaScript-MD5 + */ + (function($) { + function safeAdd(x, y) { + var lsw = (x & 0xffff) + (y & 0xffff); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xffff); + } + + function bitRotateLeft(num, cnt) { + return (num << cnt) | (num >>> (32 - cnt)); + } + + function md5cmn(q, a, b, x, s, t) { + return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b); + } + + function md5ff(a, b, c, d, x, s, t) { + return md5cmn((b & c) | (~b & d), a, b, x, s, t); + } + + function md5gg(a, b, c, d, x, s, t) { + return md5cmn((b & d) | (c & ~d), a, b, x, s, t); + } + + function md5hh(a, b, c, d, x, s, t) { + return md5cmn(b ^ c ^ d, a, b, x, s, t); + } + + function md5ii(a, b, c, d, x, s, t) { + return md5cmn(c ^ (b | ~d), a, b, x, s, t); + } + + function binlMD5(x, len) { + /* append padding */ + x[len >> 5] |= 0x80 << len % 32; + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var i; + var olda; + var oldb; + var oldc; + var oldd; + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + + for (i = 0; i < x.length; i += 16) { + olda = a; + oldb = b; + oldc = c; + oldd = d; + + a = md5ff(a, b, c, d, x[i], 7, -680876936); + d = md5ff(d, a, b, c, x[i + 1], 12, -389564586); + c = md5ff(c, d, a, b, x[i + 2], 17, 606105819); + b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330); + a = md5ff(a, b, c, d, x[i + 4], 7, -176418897); + d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426); + c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341); + b = md5ff(b, c, d, a, x[i + 7], 22, -45705983); + a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416); + d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417); + c = md5ff(c, d, a, b, x[i + 10], 17, -42063); + b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162); + a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682); + d = md5ff(d, a, b, c, x[i + 13], 12, -40341101); + c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290); + b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329); + + a = md5gg(a, b, c, d, x[i + 1], 5, -165796510); + d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632); + c = md5gg(c, d, a, b, x[i + 11], 14, 643717713); + b = md5gg(b, c, d, a, x[i], 20, -373897302); + a = md5gg(a, b, c, d, x[i + 5], 5, -701558691); + d = md5gg(d, a, b, c, x[i + 10], 9, 38016083); + c = md5gg(c, d, a, b, x[i + 15], 14, -660478335); + b = md5gg(b, c, d, a, x[i + 4], 20, -405537848); + a = md5gg(a, b, c, d, x[i + 9], 5, 568446438); + d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690); + c = md5gg(c, d, a, b, x[i + 3], 14, -187363961); + b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501); + a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467); + d = md5gg(d, a, b, c, x[i + 2], 9, -51403784); + c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473); + b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734); + + a = md5hh(a, b, c, d, x[i + 5], 4, -378558); + d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463); + c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562); + b = md5hh(b, c, d, a, x[i + 14], 23, -35309556); + a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060); + d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353); + c = md5hh(c, d, a, b, x[i + 7], 16, -155497632); + b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640); + a = md5hh(a, b, c, d, x[i + 13], 4, 681279174); + d = md5hh(d, a, b, c, x[i], 11, -358537222); + c = md5hh(c, d, a, b, x[i + 3], 16, -722521979); + b = md5hh(b, c, d, a, x[i + 6], 23, 76029189); + a = md5hh(a, b, c, d, x[i + 9], 4, -640364487); + d = md5hh(d, a, b, c, x[i + 12], 11, -421815835); + c = md5hh(c, d, a, b, x[i + 15], 16, 530742520); + b = md5hh(b, c, d, a, x[i + 2], 23, -995338651); + + a = md5ii(a, b, c, d, x[i], 6, -198630844); + d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415); + c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905); + b = md5ii(b, c, d, a, x[i + 5], 21, -57434055); + a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571); + d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606); + c = md5ii(c, d, a, b, x[i + 10], 15, -1051523); + b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799); + a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359); + d = md5ii(d, a, b, c, x[i + 15], 10, -30611744); + c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380); + b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649); + a = md5ii(a, b, c, d, x[i + 4], 6, -145523070); + d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379); + c = md5ii(c, d, a, b, x[i + 2], 15, 718787259); + b = md5ii(b, c, d, a, x[i + 9], 21, -343485551); + + a = safeAdd(a, olda); + b = safeAdd(b, oldb); + c = safeAdd(c, oldc); + d = safeAdd(d, oldd); + } + return [a, b, c, d]; + } + + function binl2rstr(input) { + var i; + var output = ''; + var length32 = input.length * 32; + for (i = 0; i < length32; i += 8) { + output += String.fromCharCode((input[i >> 5] >>> i % 32) & 0xff); + } + return output; + } + + function rstr2binl(input) { + var i; + var output = []; + output[(input.length >> 2) - 1] = undefined; + for (i = 0; i < output.length; i += 1) { + output[i] = 0; + } + var length8 = input.length * 8; + for (i = 0; i < length8; i += 8) { + output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << i % 32; + } + return output; + } + + function rstrMD5(s) { + return binl2rstr(binlMD5(rstr2binl(s), s.length * 8)); + } + + function rstr2hex(input) { + var hexTab = '0123456789abcdef'; + var output = ''; + var x; + var i; + for (i = 0; i < input.length; i += 1) { + x = input.charCodeAt(i); + output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f); + } + return output; + } + + function str2rstrUTF8(input) { + return unescape(encodeURIComponent(input)); + } + + function hexMD5(s) { + return rstr2hex(rstrMD5(str2rstrUTF8(s))); + } + + $.md5 = hexMD5; + })(Utils); // General Mojito exclude feature // Mojito.options.excluded can be a boolean value or a function diff --git a/license.txt b/license.txt index c57e100..ff5dbc2 100644 --- a/license.txt +++ b/license.txt @@ -2,4 +2,5 @@ * Copyright (c) 2019, Mint Metrics Pty Ltd All rights reserved. BSD 3-Clause License. https://github.com/mint-metrics/mojito/blob/master/LICENSE * Copyright (c) 2010, James Yu. https://github.com/jamesyu/cohorts/blob/master/LICENSE * Copyright (c) 2005-2017, JS Foundation All rights reserved. https://dojotoolkit.org/license.html + * Copyright (c) 2011 Sebastian Tschan, https://blueimp.net */ \ No newline at end of file