| /** |
| * Canteen v1.0.4 |
| * August 19th, 2015 |
| * |
| * Copyright 2015 Platfora, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| ;(function() { |
| // ================================ Constants ================================ |
| var CONTEXT_2D_ATTRIBUTES = [ |
| 'fillStyle', |
| 'font', |
| 'globalAlpha', |
| 'globalCompositeOperation', |
| 'lineCap', |
| 'lineDashOffset', |
| 'lineJoin', |
| 'lineWidth', |
| 'miterLimit', |
| 'shadowBlur', |
| 'shadowColor', |
| 'shadowOffsetX', |
| 'shadowOffsetY', |
| 'strokeStyle', |
| 'textAlign', |
| 'textBaseline' |
| ]; |
| |
| // ================================ Utils ================================ |
| |
| function each(arr, func) { |
| var len = arr.length, |
| n; |
| |
| for (n=0; n<len; n++) { |
| func(arr[n], n); |
| } |
| } |
| |
| function round(val, decimalPoints) { |
| var power = Math.pow(10, decimalPoints); |
| return Math.round(val * power) / power; |
| } |
| |
| function roundArr(arr, decimalPoints) { |
| var len = arr.length, |
| ret = [], |
| n; |
| |
| for (n=0; n<len; n++) { |
| if (isNumber(arr[n])) { |
| ret.push(round(arr[n], decimalPoints)); |
| } |
| else { |
| ret.push(arr[n]); |
| } |
| } |
| |
| return ret; |
| } |
| |
| function isFunction(func) { |
| return func && {}.toString.call(func) === '[object Function]'; |
| } |
| |
| function isNumber(val) { |
| return typeof val === 'number'; |
| } |
| |
| // ================================ Canteen Class ================================ |
| |
| /** |
| * Canteen Constructor |
| * @constructor |
| */ |
| var Canteen = function(context) { |
| var that = this; |
| |
| this._stack = []; |
| this.context = context; |
| |
| // add observable attributes |
| each(CONTEXT_2D_ATTRIBUTES, function(key, n) { |
| Object.defineProperty(that, key, { |
| get: function() { |
| return that.context[key]; |
| }, |
| set: function(val) { |
| that._pushAttr(key, val); |
| that.context[key] = val; |
| } |
| }); |
| }); |
| }; |
| |
| // Canteen methods |
| Canteen.prototype = { |
| /** |
| * get a stack of operations |
| * @method stack |
| * @param {Object} config |
| * @param {String} [config.loose=false] - strict mode returns method calls with arguments and property names |
| * with values. loose mode only returns method calls and property names |
| * @param {Number} [config.decimalPoints=3] - number of decimal points to round numeric values to. The default is |
| * 3, i.e. 1.23456 will round to 1.234 |
| * @returns {Array} |
| * @public |
| */ |
| stack: function(config) { |
| var config = config || {}, |
| loose = config.loose, |
| decimalPoints = config.decimalPoints === undefined ? 3 : config.decimalPoints, |
| ret = []; |
| |
| if (loose) { |
| each(this._stack, function(el, n) { |
| ret.push(el.method || el.attr); |
| }); |
| } |
| else { |
| each(this._stack, function(el, n) { |
| // if method instruction |
| if (el.method) { |
| ret.push({ |
| method: el.method, |
| arguments: roundArr(el.arguments, decimalPoints) |
| }); |
| } |
| // if attr |
| else if (el.attr) { |
| ret.push({ |
| attr: el.attr, |
| val: isNumber(el.val) ? round(el.val, decimalPoints) : el.val |
| }); |
| } |
| }); |
| } |
| |
| return ret; |
| }, |
| /** |
| * serialize a stack into a string |
| * @method json |
| * @param {Object} config |
| * @param {String} [config.loose=false] - strict mode returns method calls with arguments and property names |
| * with values. loose mode only returns method calls and property names |
| * @param {Number} [config.decimalPoints=3] - number of decimal points to round numeric values to. The default is |
| * 3, i.e. 1.23456 will round to 1.234 |
| * @returns {String} |
| * @public |
| */ |
| json: function(config) { |
| return JSON.stringify(this.stack(config)); |
| }, |
| /** |
| * convert a stack into a small hash string for easy comparisons |
| * @method hash |
| * @param {Object} config |
| * @param {String} [config.loose=false] - strict mode returns method calls with arguments and property names |
| * with values. loose mode only returns method calls and property names |
| * @param {Number} [config.decimalPoints=3] - number of decimal points to round numeric values to. The default is |
| * 3, i.e. 1.23456 will round to 1.234 |
| * @public |
| * @returns {String} |
| */ |
| hash: function(config) { |
| return Canteen.md5(this.json(config)); |
| }, |
| /** |
| * clear the stack |
| * @method clear |
| * @public |
| */ |
| clear: function() { |
| this._stack = []; |
| }, |
| /** |
| * push instruction method onto the stack |
| * @method _pushMethod |
| * @param {String} method |
| * @param {arguments} args |
| * @private |
| */ |
| _pushMethod: function(method, args) { |
| this._stack.push({ |
| method: method, |
| arguments: Array.prototype.slice.call(args, 0) |
| }); |
| |
| this._slice(); |
| }, |
| /** |
| * push instruction attribute onto the stack |
| * @method _pushAttr |
| * @param {String} attr |
| * @param {*} val |
| * @private |
| */ |
| _pushAttr: function(attr, val) { |
| this._stack.push({ |
| attr: attr, |
| val: val |
| }); |
| |
| this._slice(); |
| }, |
| /** |
| * slice the stack if needed. This means making sure that it doesn't exceed |
| * the STACK_SIZE. if it does, then shorten the stack starting from the beginning |
| * @method _slice |
| * @private |
| */ |
| _slice: function() { |
| var stack = this._stack, |
| len = stack.length, |
| exceded = len - Canteen.globals.STACK_SIZE; |
| if (exceded > 0) { |
| this._stack = stack.slice(exceded); |
| } |
| } |
| }; |
| |
| // generate observable methods and add them to the Canteen prototype |
| (function(){ |
| var proto = CanvasRenderingContext2D.prototype, |
| key, val, desc; |
| |
| function addMethod(key, val) { |
| Canteen.prototype[key] = function() { |
| this._pushMethod(key, arguments); |
| return this.context[key].apply(this.context, arguments); |
| }; |
| } |
| |
| for (key in proto) { |
| desc = Object.getOwnPropertyDescriptor(CanvasRenderingContext2D.prototype, key); |
| val = (desc && desc.value ? proto[key] : null); |
| if (isFunction(val)) { |
| addMethod(key, val); |
| } |
| } |
| })(); |
| |
| // ================================ Global Config ================================ |
| /** |
| * global config. You can directly change these values in order to configure Canteen |
| * @static |
| * @example |
| * // change stack size to 3000 |
| * Canteen.globals.STACK_SIZE = 3000; |
| */ |
| Canteen.globals = { |
| STACK_SIZE: 10000 |
| }; |
| |
| // ================================ Initialization ================================ |
| |
| // override the canvas context getContext method in order to automatically instantiate |
| // a Canteen instance and wrap the native context object |
| (function(){ |
| var origGetContext = HTMLCanvasElement.prototype.getContext; |
| |
| HTMLCanvasElement.prototype.getContext = function() { |
| var context = origGetContext.apply(this, arguments); |
| |
| // if the context already has a canteen instance, then return it |
| if (context.canteen) { |
| return context.canteen |
| } |
| // if the context does not have a canteen instance, then instantiate one |
| // and return it |
| else { |
| context.canteen = new Canteen(context); |
| return context.canteen; |
| } |
| } |
| })(); |
| |
| // make the Canteen namespace global so that developers can configure |
| // it via Canteen.globals, or override methods if desired |
| window.Canteen = Canteen; |
| })(); |
| ;/* |
| * JavaScript MD5 1.0.1 |
| * https://github.com/blueimp/JavaScript-MD5 |
| * |
| * Copyright 2011, Sebastian Tschan |
| * https://blueimp.net |
| * |
| * Licensed under the MIT license: |
| * http://www.opensource.org/licenses/MIT |
| * |
| * Based on |
| * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message |
| * Digest Algorithm, as defined in RFC 1321. |
| * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 |
| * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet |
| * Distributed under the BSD License |
| * See http://pajhome.org.uk/crypt/md5 for more info. |
| */ |
| |
| /*jslint bitwise: true */ |
| /*global unescape, define */ |
| (function ($) { |
| 'use strict'; |
| |
| /* |
| * 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), |
| 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)); |
| } |
| |
| /* |
| * 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 MD5 of an array of little-endian words, and a bit length. |
| */ |
| function binl_md5(x, len) { |
| /* append padding */ |
| x[len >> 5] |= 0x80 << (len % 32); |
| x[(((len + 64) >>> 9) << 4) + 14] = len; |
| |
| var i, olda, oldb, oldc, oldd, |
| a = 1732584193, |
| b = -271733879, |
| c = -1732584194, |
| d = 271733878; |
| |
| for (i = 0; i < x.length; i += 16) { |
| olda = a; |
| oldb = b; |
| oldc = c; |
| oldd = d; |
| |
| a = md5_ff(a, b, c, d, x[i], 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], 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], 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], 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 [a, b, c, d]; |
| } |
| |
| /* |
| * Convert an array of little-endian words to a string |
| */ |
| function binl2rstr(input) { |
| var i, |
| output = ''; |
| for (i = 0; i < input.length * 32; i += 8) { |
| output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF); |
| } |
| return output; |
| } |
| |
| /* |
| * Convert a raw string to an array of little-endian words |
| * Characters >255 have their high-byte silently ignored. |
| */ |
| function rstr2binl(input) { |
| var i, |
| output = []; |
| output[(input.length >> 2) - 1] = undefined; |
| for (i = 0; i < output.length; i += 1) { |
| output[i] = 0; |
| } |
| for (i = 0; i < input.length * 8; i += 8) { |
| output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32); |
| } |
| return output; |
| } |
| |
| /* |
| * Calculate the MD5 of a raw string |
| */ |
| function rstr_md5(s) { |
| return binl2rstr(binl_md5(rstr2binl(s), s.length * 8)); |
| } |
| |
| /* |
| * Calculate the HMAC-MD5, of a key and some data (raw strings) |
| */ |
| function rstr_hmac_md5(key, data) { |
| var i, |
| bkey = rstr2binl(key), |
| ipad = [], |
| opad = [], |
| hash; |
| ipad[15] = opad[15] = undefined; |
| if (bkey.length > 16) { |
| bkey = binl_md5(bkey, key.length * 8); |
| } |
| for (i = 0; i < 16; i += 1) { |
| ipad[i] = bkey[i] ^ 0x36363636; |
| opad[i] = bkey[i] ^ 0x5C5C5C5C; |
| } |
| hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); |
| return binl2rstr(binl_md5(opad.concat(hash), 512 + 128)); |
| } |
| |
| /* |
| * Convert a raw string to a hex string |
| */ |
| function rstr2hex(input) { |
| var hex_tab = '0123456789abcdef', |
| output = '', |
| x, |
| i; |
| for (i = 0; i < input.length; i += 1) { |
| x = input.charCodeAt(i); |
| output += hex_tab.charAt((x >>> 4) & 0x0F) + |
| hex_tab.charAt(x & 0x0F); |
| } |
| return output; |
| } |
| |
| /* |
| * Encode a string as utf-8 |
| */ |
| function str2rstr_utf8(input) { |
| return unescape(encodeURIComponent(input)); |
| } |
| |
| /* |
| * Take string arguments and return either raw or hex encoded strings |
| */ |
| function raw_md5(s) { |
| return rstr_md5(str2rstr_utf8(s)); |
| } |
| function hex_md5(s) { |
| return rstr2hex(raw_md5(s)); |
| } |
| function raw_hmac_md5(k, d) { |
| return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)); |
| } |
| function hex_hmac_md5(k, d) { |
| return rstr2hex(raw_hmac_md5(k, d)); |
| } |
| |
| function md5(string, key, raw) { |
| if (!key) { |
| if (!raw) { |
| return hex_md5(string); |
| } |
| return raw_md5(string); |
| } |
| if (!raw) { |
| return hex_hmac_md5(key, string); |
| } |
| return raw_hmac_md5(key, string); |
| } |
| |
| if (typeof define === 'function' && define.amd) { |
| define(function () { |
| return md5; |
| }); |
| } else { |
| $.md5 = md5; |
| } |
| }(Canteen)); |