| /** | |
| * 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)); |