#include <StringConstants.au3> ; to declare the Constants of StringRegExp
#include <Array.au3> ; UDF needed for _ArrayDisplay and _ArrayConcatenate
Local $sRegex = "function\s+(?<functionName>\w+)\s*\((?<functionArguments>(?:[^()]+)*)?\s*\)\s*(?<functionBody>{(?:[^{}]+|(?-1))*+})"
Local $sString = "/*" & @CRLF & _
" html2canvas 0.5.0-alpha1 <http://html2canvas.hertzen.com>" & @CRLF & _
" Copyright (c) 2015 Niklas von Hertzen" & @CRLF & _
"" & @CRLF & _
" Released under MIT License" & @CRLF & _
"*/" & @CRLF & _
"" & @CRLF & _
"(function(window, document, exports, global, define, undefined){" & @CRLF & _
"" & @CRLF & _
"/*!" & @CRLF & _
" * @overview es6-promise - a tiny implementation of Promises/A+." & @CRLF & _
" * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)" & @CRLF & _
" * @license Licensed under MIT license" & @CRLF & _
" * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE" & @CRLF & _
" * @version 2.0.1" & @CRLF & _
" */" & @CRLF & _
"" & @CRLF & _
"(function(){function r(a,b){n[l]=a;n[l+1]=b;l+=2;2===l&&A()}function s(a){return"function"===typeof a}function F(){return function(){process.nextTick(t)}}function G(){var a=0,b=new B(t),c=document.createTextNode("");b.observe(c,{characterData:!0});return function(){c.data=a=++a%2}}function H(){var a=new MessageChannel;a.port1.onmessage=t;return function(){a.port2.postMessage(0)}}function I(){return function(){setTimeout(t,1)}}function t(){for(var a=0;a<l;a+=2)(0,n[a])(n[a+1]),n[a]=void 0,n[a+1]=void 0;" & @CRLF & _
"l=0}function p(){}function J(a,b,c,d){try{a.call(b,c,d)}catch(e){return e}}function K(a,b,c){r(function(a){var e=!1,f=J(c,b,function(c){e||(e=!0,b!==c?q(a,c):m(a,c))},function(b){e||(e=!0,g(a,b))});!e&&f&&(e=!0,g(a,f))},a)}function L(a,b){1===b.a?m(a,b.b):2===a.a?g(a,b.b):u(b,void 0,function(b){q(a,b)},function(b){g(a,b)})}function q(a,b){if(a===b)g(a,new TypeError("You cannot resolve a promise with itself"));else if("function"===typeof b||"object"===typeof b&&null!==b)if(b.constructor===a.constructor)L(a," & @CRLF & _
"b);else{var c;try{c=b.then}catch(d){v.error=d,c=v}c===v?g(a,v.error):void 0===c?m(a,b):s(c)?K(a,b,c):m(a,b)}else m(a,b)}function M(a){a.f&&a.f(a.b);x(a)}function m(a,b){void 0===a.a&&(a.b=b,a.a=1,0!==a.e.length&&r(x,a))}function g(a,b){void 0===a.a&&(a.a=2,a.b=b,r(M,a))}function u(a,b,c,d){var e=a.e,f=e.length;a.f=null;e[f]=b;e[f+1]=c;e[f+2]=d;0===f&&a.a&&r(x,a)}function x(a){var b=a.e,c=a.a;if(0!==b.length){for(var d,e,f=a.b,g=0;g<b.length;g+=3)d=b[g],e=b[g+c],d?C(c,d,e,f):e(f);a.e.length=0}}function D(){this.error=" & @CRLF & _
"null}function C(a,b,c,d){var e=s(c),f,k,h,l;if(e){try{f=c(d)}catch(n){y.error=n,f=y}f===y?(l=!0,k=f.error,f=null):h=!0;if(b===f){g(b,new TypeError("A promises callback cannot return that same promise."));return}}else f=d,h=!0;void 0===b.a&&(e&&h?q(b,f):l?g(b,k):1===a?m(b,f):2===a&&g(b,f))}function N(a,b){try{b(function(b){q(a,b)},function(b){g(a,b)})}catch(c){g(a,c)}}function k(a,b,c,d){this.n=a;this.c=new a(p,d);this.i=c;this.o(b)?(this.m=b,this.d=this.length=b.length,this.l(),0===this.length?m(this.c," & @CRLF & _
"this.b):(this.length=this.length||0,this.k(),0===this.d&&m(this.c,this.b))):g(this.c,this.p())}function h(a){O++;this.b=this.a=void 0;this.e=[];if(p!==a){if(!s(a))throw new TypeError("You must pass a resolver function as the first argument to the promise constructor");if(!(this instanceof h))throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");N(this,a)}}var E=Array.isArray?Array.isArray:function(a){return"[object Array]"===" & @CRLF & _
"Object.prototype.toString.call(a)},l=0,w="undefined"!==typeof window?window:{},B=w.MutationObserver||w.WebKitMutationObserver,w="undefined"!==typeof Uint8ClampedArray&&"undefined"!==typeof importScripts&&"undefined"!==typeof MessageChannel,n=Array(1E3),A;A="undefined"!==typeof process&&"[object process]"==={}.toString.call(process)?F():B?G():w?H():I();var v=new D,y=new D;k.prototype.o=function(a){return E(a)};k.prototype.p=function(){return Error("Array Methods must be provided an Array")};k.prototype.l=" & @CRLF & _
"function(){this.b=Array(this.length)};k.prototype.k=function(){for(var a=this.length,b=this.c,c=this.m,d=0;void 0===b.a&&d<a;d++)this.j(c[d],d)};k.prototype.j=function(a,b){var c=this.n;"object"===typeof a&&null!==a?a.constructor===c&&void 0!==a.a?(a.f=null,this.g(a.a,b,a.b)):this.q(c.resolve(a),b):(this.d--,this.b[b]=this.h(a))};k.prototype.g=function(a,b,c){var d=this.c;void 0===d.a&&(this.d--,this.i&&2===a?g(d,c):this.b[b]=this.h(c));0===this.d&&m(d,this.b)};k.prototype.h=function(a){return a};" & @CRLF & _
"k.prototype.q=function(a,b){var c=this;u(a,void 0,function(a){c.g(1,b,a)},function(a){c.g(2,b,a)})};var O=0;h.all=function(a,b){return(new k(this,a,!0,b)).c};h.race=function(a,b){function c(a){q(e,a)}function d(a){g(e,a)}var e=new this(p,b);if(!E(a))return (g(e,new TypeError("You must pass an array to race.")), e);for(var f=a.length,h=0;void 0===e.a&&h<f;h++)u(this.resolve(a[h]),void 0,c,d);return e};h.resolve=function(a,b){if(a&&"object"===typeof a&&a.constructor===this)return a;var c=new this(p,b);" & @CRLF & _
"q(c,a);return c};h.reject=function(a,b){var c=new this(p,b);g(c,a);return c};h.prototype={constructor:h,then:function(a,b){var c=this.a;if(1===c&&!a||2===c&&!b)return this;var d=new this.constructor(p),e=this.b;if(c){var f=arguments[c-1];r(function(){C(c,d,f,e)})}else u(this,d,a,b);return d},"catch":function(a){return this.then(null,a)}};var z={Promise:h,polyfill:function(){var a;a="undefined"!==typeof global?global:"undefined"!==typeof window&&window.document?window:self;"Promise"in a&&"resolve"in" & @CRLF & _
"a.Promise&&"reject"in a.Promise&&"all"in a.Promise&&"race"in a.Promise&&function(){var b;new a.Promise(function(a){b=a});return s(b)}()||(a.Promise=h)}};"function"===typeof define&&define.amd?define(function(){return z}):"undefined"!==typeof module&&module.exports?module.exports=z:"undefined"!==typeof this&&(this.ES6Promise=z);}).call(window);" & @CRLF & _
"if (window) {" & @CRLF & _
" window.ES6Promise.polyfill();" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"" & @CRLF & _
"if (typeof(document) === "undefined" || typeof(Object.create) !== "function" || typeof(document.createElement("canvas").getContext) !== "function") {" & @CRLF & _
" (window || module.exports).html2canvas = function() {" & @CRLF & _
" return Promise.reject("No canvas support");" & @CRLF & _
" };" & @CRLF & _
" return;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"/*! https://mths.be/punycode v1.3.1 by @mathias */" & @CRLF & _
";(function(root) {" & @CRLF & _
"" & @CRLF & _
" /** Detect free variables */" & @CRLF & _
" var freeExports = typeof exports == 'object' && exports &&" & @CRLF & _
" !exports.nodeType && exports;" & @CRLF & _
" var freeModule = typeof module == 'object' && module &&" & @CRLF & _
" !module.nodeType && module;" & @CRLF & _
" var freeGlobal = typeof global == 'object' && global;" & @CRLF & _
" if (" & @CRLF & _
" freeGlobal.global === freeGlobal ||" & @CRLF & _
" freeGlobal.window === freeGlobal ||" & @CRLF & _
" freeGlobal.self === freeGlobal" & @CRLF & _
" ) {" & @CRLF & _
" root = freeGlobal;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * The `punycode` object." & @CRLF & _
" * @name punycode" & @CRLF & _
" * @type Object" & @CRLF & _
" */" & @CRLF & _
" var punycode," & @CRLF & _
"" & @CRLF & _
" /** Highest positive signed 32-bit float value */" & @CRLF & _
" maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1" & @CRLF & _
"" & @CRLF & _
" /** Bootstring parameters */" & @CRLF & _
" base = 36," & @CRLF & _
" tMin = 1," & @CRLF & _
" tMax = 26," & @CRLF & _
" skew = 38," & @CRLF & _
" damp = 700," & @CRLF & _
" initialBias = 72," & @CRLF & _
" initialN = 128, // 0x80" & @CRLF & _
" delimiter = '-', // '\x2D'" & @CRLF & _
"" & @CRLF & _
" /** Regular expressions */" & @CRLF & _
" regexPunycode = /^xn--/," & @CRLF & _
" regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars" & @CRLF & _
" regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators" & @CRLF & _
"" & @CRLF & _
" /** Error messages */" & @CRLF & _
" errors = {" & @CRLF & _
" 'overflow': 'Overflow: input needs wider integers to process'," & @CRLF & _
" 'not-basic': 'Illegal input >= 0x80 (not a basic code point)'," & @CRLF & _
" 'invalid-input': 'Invalid input'" & @CRLF & _
" }," & @CRLF & _
"" & @CRLF & _
" /** Convenience shortcuts */" & @CRLF & _
" baseMinusTMin = base - tMin," & @CRLF & _
" floor = Math.floor," & @CRLF & _
" stringFromCharCode = String.fromCharCode," & @CRLF & _
"" & @CRLF & _
" /** Temporary variable */" & @CRLF & _
" key;" & @CRLF & _
"" & @CRLF & _
" /*--------------------------------------------------------------------------*/" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * A generic error utility function." & @CRLF & _
" * @private" & @CRLF & _
" * @param {String} type The error type." & @CRLF & _
" * @returns {Error} Throws a `RangeError` with the applicable error message." & @CRLF & _
" */" & @CRLF & _
" function error(type) {" & @CRLF & _
" throw RangeError(errors[type]);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * A generic `Array#map` utility function." & @CRLF & _
" * @private" & @CRLF & _
" * @param {Array} array The array to iterate over." & @CRLF & _
" * @param {Function} callback The function that gets called for every array" & @CRLF & _
" * item." & @CRLF & _
" * @returns {Array} A new array of values returned by the callback function." & @CRLF & _
" */" & @CRLF & _
" function map(array, fn) {" & @CRLF & _
" var length = array.length;" & @CRLF & _
" var result = [];" & @CRLF & _
" while (length--) {" & @CRLF & _
" result[length] = fn(array[length]);" & @CRLF & _
" }" & @CRLF & _
" return result;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * A simple `Array#map`-like wrapper to work with domain name strings or email" & @CRLF & _
" * addresses." & @CRLF & _
" * @private" & @CRLF & _
" * @param {String} domain The domain name or email address." & @CRLF & _
" * @param {Function} callback The function that gets called for every" & @CRLF & _
" * character." & @CRLF & _
" * @returns {Array} A new string of characters returned by the callback" & @CRLF & _
" * function." & @CRLF & _
" */" & @CRLF & _
" function mapDomain(string, fn) {" & @CRLF & _
" var parts = string.split('@');" & @CRLF & _
" var result = '';" & @CRLF & _
" if (parts.length > 1) {" & @CRLF & _
" // In email addresses, only the domain name should be punycoded. Leave" & @CRLF & _
" // the local part (i.e. everything up to `@`) intact." & @CRLF & _
" result = parts[0] + '@';" & @CRLF & _
" string = parts[1];" & @CRLF & _
" }" & @CRLF & _
" var labels = string.split(regexSeparators);" & @CRLF & _
" var encoded = map(labels, fn).join('.');" & @CRLF & _
" return result + encoded;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * Creates an array containing the numeric code points of each Unicode" & @CRLF & _
" * character in the string. While JavaScript uses UCS-2 internally," & @CRLF & _
" * this function will convert a pair of surrogate halves (each of which" & @CRLF & _
" * UCS-2 exposes as separate characters) into a single code point," & @CRLF & _
" * matching UTF-16." & @CRLF & _
" * @see `punycode.ucs2.encode`" & @CRLF & _
" * @see <https://mathiasbynens.be/notes/javascript-encoding>" & @CRLF & _
" * @memberOf punycode.ucs2" & @CRLF & _
" * @name decode" & @CRLF & _
" * @param {String} string The Unicode input string (UCS-2)." & @CRLF & _
" * @returns {Array} The new array of code points." & @CRLF & _
" */" & @CRLF & _
" function ucs2decode(string) {" & @CRLF & _
" var output = []," & @CRLF & _
" counter = 0," & @CRLF & _
" length = string.length," & @CRLF & _
" value," & @CRLF & _
" extra;" & @CRLF & _
" while (counter < length) {" & @CRLF & _
" value = string.charCodeAt(counter++);" & @CRLF & _
" if (value >= 0xD800 && value <= 0xDBFF && counter < length) {" & @CRLF & _
" // high surrogate, and there is a next character" & @CRLF & _
" extra = string.charCodeAt(counter++);" & @CRLF & _
" if ((extra & 0xFC00) == 0xDC00) { // low surrogate" & @CRLF & _
" output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);" & @CRLF & _
" } else {" & @CRLF & _
" // unmatched surrogate; only append this code unit, in case the next" & @CRLF & _
" // code unit is the high surrogate of a surrogate pair" & @CRLF & _
" output.push(value);" & @CRLF & _
" counter--;" & @CRLF & _
" }" & @CRLF & _
" } else {" & @CRLF & _
" output.push(value);" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
" return output;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * Creates a string based on an array of numeric code points." & @CRLF & _
" * @see `punycode.ucs2.decode`" & @CRLF & _
" * @memberOf punycode.ucs2" & @CRLF & _
" * @name encode" & @CRLF & _
" * @param {Array} codePoints The array of numeric code points." & @CRLF & _
" * @returns {String} The new Unicode string (UCS-2)." & @CRLF & _
" */" & @CRLF & _
" function ucs2encode(array) {" & @CRLF & _
" return map(array, function(value) {" & @CRLF & _
" var output = '';" & @CRLF & _
" if (value > 0xFFFF) {" & @CRLF & _
" value -= 0x10000;" & @CRLF & _
" output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);" & @CRLF & _
" value = 0xDC00 | value & 0x3FF;" & @CRLF & _
" }" & @CRLF & _
" output += stringFromCharCode(value);" & @CRLF & _
" return output;" & @CRLF & _
" }).join('');" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * Converts a basic code point into a digit/integer." & @CRLF & _
" * @see `digitToBasic()`" & @CRLF & _
" * @private" & @CRLF & _
" * @param {Number} codePoint The basic numeric code point value." & @CRLF & _
" * @returns {Number} The numeric value of a basic code point (for use in" & @CRLF & _
" * representing integers) in the range `0` to `base - 1`, or `base` if" & @CRLF & _
" * the code point does not represent a value." & @CRLF & _
" */" & @CRLF & _
" function basicToDigit(codePoint) {" & @CRLF & _
" if (codePoint - 48 < 10) {" & @CRLF & _
" return codePoint - 22;" & @CRLF & _
" }" & @CRLF & _
" if (codePoint - 65 < 26) {" & @CRLF & _
" return codePoint - 65;" & @CRLF & _
" }" & @CRLF & _
" if (codePoint - 97 < 26) {" & @CRLF & _
" return codePoint - 97;" & @CRLF & _
" }" & @CRLF & _
" return base;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * Converts a digit/integer into a basic code point." & @CRLF & _
" * @see `basicToDigit()`" & @CRLF & _
" * @private" & @CRLF & _
" * @param {Number} digit The numeric value of a basic code point." & @CRLF & _
" * @returns {Number} The basic code point whose value (when used for" & @CRLF & _
" * representing integers) is `digit`, which needs to be in the range" & @CRLF & _
" * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is" & @CRLF & _
" * used; else, the lowercase form is used. The behavior is undefined" & @CRLF & _
" * if `flag` is non-zero and `digit` has no uppercase form." & @CRLF & _
" */" & @CRLF & _
" function digitToBasic(digit, flag) {" & @CRLF & _
" // 0..25 map to ASCII a..z or A..Z" & @CRLF & _
" // 26..35 map to ASCII 0..9" & @CRLF & _
" return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * Bias adaptation function as per section 3.4 of RFC 3492." & @CRLF & _
" * http://tools.ietf.org/html/rfc3492#section-3.4" & @CRLF & _
" * @private" & @CRLF & _
" */" & @CRLF & _
" function adapt(delta, numPoints, firstTime) {" & @CRLF & _
" var k = 0;" & @CRLF & _
" delta = firstTime ? floor(delta / damp) : delta >> 1;" & @CRLF & _
" delta += floor(delta / numPoints);" & @CRLF & _
" for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {" & @CRLF & _
" delta = floor(delta / baseMinusTMin);" & @CRLF & _
" }" & @CRLF & _
" return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * Converts a Punycode string of ASCII-only symbols to a string of Unicode" & @CRLF & _
" * symbols." & @CRLF & _
" * @memberOf punycode" & @CRLF & _
" * @param {String} input The Punycode string of ASCII-only symbols." & @CRLF & _
" * @returns {String} The resulting string of Unicode symbols." & @CRLF & _
" */" & @CRLF & _
" function decode(input) {" & @CRLF & _
" // Don't use UCS-2" & @CRLF & _
" var output = []," & @CRLF & _
" inputLength = input.length," & @CRLF & _
" out," & @CRLF & _
" i = 0," & @CRLF & _
" n = initialN," & @CRLF & _
" bias = initialBias," & @CRLF & _
" basic," & @CRLF & _
" j," & @CRLF & _
" index," & @CRLF & _
" oldi," & @CRLF & _
" w," & @CRLF & _
" k," & @CRLF & _
" digit," & @CRLF & _
" t," & @CRLF & _
" /** Cached calculation results */" & @CRLF & _
" baseMinusT;" & @CRLF & _
"" & @CRLF & _
" // Handle the basic code points: let `basic` be the number of input code" & @CRLF & _
" // points before the last delimiter, or `0` if there is none, then copy" & @CRLF & _
" // the first basic code points to the output." & @CRLF & _
"" & @CRLF & _
" basic = input.lastIndexOf(delimiter);" & @CRLF & _
" if (basic < 0) {" & @CRLF & _
" basic = 0;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" for (j = 0; j < basic; ++j) {" & @CRLF & _
" // if it's not a basic code point" & @CRLF & _
" if (input.charCodeAt(j) >= 0x80) {" & @CRLF & _
" error('not-basic');" & @CRLF & _
" }" & @CRLF & _
" output.push(input.charCodeAt(j));" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" // Main decoding loop: start just after the last delimiter if any basic code" & @CRLF & _
" // points were copied; start at the beginning otherwise." & @CRLF & _
"" & @CRLF & _
" for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {" & @CRLF & _
"" & @CRLF & _
" // `index` is the index of the next character to be consumed." & @CRLF & _
" // Decode a generalized variable-length integer into `delta`," & @CRLF & _
" // which gets added to `i`. The overflow checking is easier" & @CRLF & _
" // if we increase `i` as we go, then subtract off its starting" & @CRLF & _
" // value at the end to obtain `delta`." & @CRLF & _
" for (oldi = i, w = 1, k = base; /* no condition */; k += base) {" & @CRLF & _
"" & @CRLF & _
" if (index >= inputLength) {" & @CRLF & _
" error('invalid-input');" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" digit = basicToDigit(input.charCodeAt(index++));" & @CRLF & _
"" & @CRLF & _
" if (digit >= base || digit > floor((maxInt - i) / w)) {" & @CRLF & _
" error('overflow');" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" i += digit * w;" & @CRLF & _
" t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);" & @CRLF & _
"" & @CRLF & _
" if (digit < t) {" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" baseMinusT = base - t;" & @CRLF & _
" if (w > floor(maxInt / baseMinusT)) {" & @CRLF & _
" error('overflow');" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" w *= baseMinusT;" & @CRLF & _
"" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" out = output.length + 1;" & @CRLF & _
" bias = adapt(i - oldi, out, oldi == 0);" & @CRLF & _
"" & @CRLF & _
" // `i` was supposed to wrap around from `out` to `0`," & @CRLF & _
" // incrementing `n` each time, so we'll fix that now:" & @CRLF & _
" if (floor(i / out) > maxInt - n) {" & @CRLF & _
" error('overflow');" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" n += floor(i / out);" & @CRLF & _
" i %= out;" & @CRLF & _
"" & @CRLF & _
" // Insert `n` at position `i` of the output" & @CRLF & _
" output.splice(i++, 0, n);" & @CRLF & _
"" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return ucs2encode(output);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * Converts a string of Unicode symbols (e.g. a domain name label) to a" & @CRLF & _
" * Punycode string of ASCII-only symbols." & @CRLF & _
" * @memberOf punycode" & @CRLF & _
" * @param {String} input The string of Unicode symbols." & @CRLF & _
" * @returns {String} The resulting Punycode string of ASCII-only symbols." & @CRLF & _
" */" & @CRLF & _
" function encode(input) {" & @CRLF & _
" var n," & @CRLF & _
" delta," & @CRLF & _
" handledCPCount," & @CRLF & _
" basicLength," & @CRLF & _
" bias," & @CRLF & _
" j," & @CRLF & _
" m," & @CRLF & _
" q," & @CRLF & _
" k," & @CRLF & _
" t," & @CRLF & _
" currentValue," & @CRLF & _
" output = []," & @CRLF & _
" /** `inputLength` will hold the number of code points in `input`. */" & @CRLF & _
" inputLength," & @CRLF & _
" /** Cached calculation results */" & @CRLF & _
" handledCPCountPlusOne," & @CRLF & _
" baseMinusT," & @CRLF & _
" qMinusT;" & @CRLF & _
"" & @CRLF & _
" // Convert the input in UCS-2 to Unicode" & @CRLF & _
" input = ucs2decode(input);" & @CRLF & _
"" & @CRLF & _
" // Cache the length" & @CRLF & _
" inputLength = input.length;" & @CRLF & _
"" & @CRLF & _
" // Initialize the state" & @CRLF & _
" n = initialN;" & @CRLF & _
" delta = 0;" & @CRLF & _
" bias = initialBias;" & @CRLF & _
"" & @CRLF & _
" // Handle the basic code points" & @CRLF & _
" for (j = 0; j < inputLength; ++j) {" & @CRLF & _
" currentValue = input[j];" & @CRLF & _
" if (currentValue < 0x80) {" & @CRLF & _
" output.push(stringFromCharCode(currentValue));" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" handledCPCount = basicLength = output.length;" & @CRLF & _
"" & @CRLF & _
" // `handledCPCount` is the number of code points that have been handled;" & @CRLF & _
" // `basicLength` is the number of basic code points." & @CRLF & _
"" & @CRLF & _
" // Finish the basic string - if it is not empty - with a delimiter" & @CRLF & _
" if (basicLength) {" & @CRLF & _
" output.push(delimiter);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" // Main encoding loop:" & @CRLF & _
" while (handledCPCount < inputLength) {" & @CRLF & _
"" & @CRLF & _
" // All non-basic code points < n have been handled already. Find the next" & @CRLF & _
" // larger one:" & @CRLF & _
" for (m = maxInt, j = 0; j < inputLength; ++j) {" & @CRLF & _
" currentValue = input[j];" & @CRLF & _
" if (currentValue >= n && currentValue < m) {" & @CRLF & _
" m = currentValue;" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>," & @CRLF & _
" // but guard against overflow" & @CRLF & _
" handledCPCountPlusOne = handledCPCount + 1;" & @CRLF & _
" if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {" & @CRLF & _
" error('overflow');" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" delta += (m - n) * handledCPCountPlusOne;" & @CRLF & _
" n = m;" & @CRLF & _
"" & @CRLF & _
" for (j = 0; j < inputLength; ++j) {" & @CRLF & _
" currentValue = input[j];" & @CRLF & _
"" & @CRLF & _
" if (currentValue < n && ++delta > maxInt) {" & @CRLF & _
" error('overflow');" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (currentValue == n) {" & @CRLF & _
" // Represent delta as a generalized variable-length integer" & @CRLF & _
" for (q = delta, k = base; /* no condition */; k += base) {" & @CRLF & _
" t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);" & @CRLF & _
" if (q < t) {" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
" qMinusT = q - t;" & @CRLF & _
" baseMinusT = base - t;" & @CRLF & _
" output.push(" & @CRLF & _
" stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))" & @CRLF & _
" );" & @CRLF & _
" q = floor(qMinusT / baseMinusT);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" output.push(stringFromCharCode(digitToBasic(q, 0)));" & @CRLF & _
" bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);" & @CRLF & _
" delta = 0;" & @CRLF & _
" ++handledCPCount;" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" ++delta;" & @CRLF & _
" ++n;" & @CRLF & _
"" & @CRLF & _
" }" & @CRLF & _
" return output.join('');" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * Converts a Punycode string representing a domain name or an email address" & @CRLF & _
" * to Unicode. Only the Punycoded parts of the input will be converted, i.e." & @CRLF & _
" * it doesn't matter if you call it on a string that has already been" & @CRLF & _
" * converted to Unicode." & @CRLF & _
" * @memberOf punycode" & @CRLF & _
" * @param {String} input The Punycoded domain name or email address to" & @CRLF & _
" * convert to Unicode." & @CRLF & _
" * @returns {String} The Unicode representation of the given Punycode" & @CRLF & _
" * string." & @CRLF & _
" */" & @CRLF & _
" function toUnicode(input) {" & @CRLF & _
" return mapDomain(input, function(string) {" & @CRLF & _
" return regexPunycode.test(string)" & @CRLF & _
" ? decode(string.slice(4).toLowerCase())" & @CRLF & _
" : string;" & @CRLF & _
" });" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /**" & @CRLF & _
" * Converts a Unicode string representing a domain name or an email address to" & @CRLF & _
" * Punycode. Only the non-ASCII parts of the domain name will be converted," & @CRLF & _
" * i.e. it doesn't matter if you call it with a domain that's already in" & @CRLF & _
" * ASCII." & @CRLF & _
" * @memberOf punycode" & @CRLF & _
" * @param {String} input The domain name or email address to convert, as a" & @CRLF & _
" * Unicode string." & @CRLF & _
" * @returns {String} The Punycode representation of the given domain name or" & @CRLF & _
" * email address." & @CRLF & _
" */" & @CRLF & _
" function toASCII(input) {" & @CRLF & _
" return mapDomain(input, function(string) {" & @CRLF & _
" return regexNonASCII.test(string)" & @CRLF & _
" ? 'xn--' + encode(string)" & @CRLF & _
" : string;" & @CRLF & _
" });" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" /*--------------------------------------------------------------------------*/" & @CRLF & _
"" & @CRLF & _
" /** Define the public API */" & @CRLF & _
" punycode = {" & @CRLF & _
" /**" & @CRLF & _
" * A string representing the current Punycode.js version number." & @CRLF & _
" * @memberOf punycode" & @CRLF & _
" * @type String" & @CRLF & _
" */" & @CRLF & _
" 'version': '1.3.1'," & @CRLF & _
" /**" & @CRLF & _
" * An object of methods to convert from JavaScript's internal character" & @CRLF & _
" * representation (UCS-2) to Unicode code points, and back." & @CRLF & _
" * @see <https://mathiasbynens.be/notes/javascript-encoding>" & @CRLF & _
" * @memberOf punycode" & @CRLF & _
" * @type Object" & @CRLF & _
" */" & @CRLF & _
" 'ucs2': {" & @CRLF & _
" 'decode': ucs2decode," & @CRLF & _
" 'encode': ucs2encode" & @CRLF & _
" }," & @CRLF & _
" 'decode': decode," & @CRLF & _
" 'encode': encode," & @CRLF & _
" 'toASCII': toASCII," & @CRLF & _
" 'toUnicode': toUnicode" & @CRLF & _
" };" & @CRLF & _
"" & @CRLF & _
" /** Expose `punycode` */" & @CRLF & _
" // Some AMD build optimizers, like r.js, check for specific condition patterns" & @CRLF & _
" // like the following:" & @CRLF & _
" if (" & @CRLF & _
" typeof define == 'function' &&" & @CRLF & _
" typeof define.amd == 'object' &&" & @CRLF & _
" define.amd" & @CRLF & _
" ) {" & @CRLF & _
" define('punycode', function() {" & @CRLF & _
" return punycode;" & @CRLF & _
" });" & @CRLF & _
" } else if (freeExports && freeModule) {" & @CRLF & _
" if (module.exports == freeExports) { // in Node.js or RingoJS v0.8.0+" & @CRLF & _
" freeModule.exports = punycode;" & @CRLF & _
" } else { // in Narwhal or RingoJS v0.7.0-" & @CRLF & _
" for (key in punycode) {" & @CRLF & _
" punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
" } else { // in Rhino or a web browser" & @CRLF & _
" root.punycode = punycode;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
"}(this));" & @CRLF & _
"" & @CRLF & _
"var html2canvasNodeAttribute = "data-html2canvas-node";" & @CRLF & _
"var html2canvasCanvasCloneAttribute = "data-html2canvas-canvas-clone";" & @CRLF & _
"var html2canvasCanvasCloneIndex = 0;" & @CRLF & _
"var html2canvasCloneIndex = 0;" & @CRLF & _
"" & @CRLF & _
"window.html2canvas = function(nodeList, options) {" & @CRLF & _
" var index = html2canvasCloneIndex++;" & @CRLF & _
" options = options || {};" & @CRLF & _
" if (options.logging) {" & @CRLF & _
" window.html2canvas.logging = true;" & @CRLF & _
" window.html2canvas.start = Date.now();" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" options.async = typeof(options.async) === "undefined" ? true : options.async;" & @CRLF & _
" options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint;" & @CRLF & _
" options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer;" & @CRLF & _
" options.javascriptEnabled = typeof(options.javascriptEnabled) === "undefined" ? false : options.javascriptEnabled;" & @CRLF & _
" options.imageTimeout = typeof(options.imageTimeout) === "undefined" ? 10000 : options.imageTimeout;" & @CRLF & _
" options.renderer = typeof(options.renderer) === "function" ? options.renderer : CanvasRenderer;" & @CRLF & _
" options.strict = !!options.strict;" & @CRLF & _
"" & @CRLF & _
" if (typeof(nodeList) === "string") {" & @CRLF & _
" if (typeof(options.proxy) !== "string") {" & @CRLF & _
" return Promise.reject("Proxy must be used when rendering url");" & @CRLF & _
" }" & @CRLF & _
" var width = options.width != null ? options.width : window.innerWidth;" & @CRLF & _
" var height = options.height != null ? options.height : window.innerHeight;" & @CRLF & _
" return loadUrlDocument(absoluteUrl(nodeList), options.proxy, document, width, height, options).then(function(container) {" & @CRLF & _
" return renderWindow(container.contentWindow.document.documentElement, container, options, width, height);" & @CRLF & _
" });" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0];" & @CRLF & _
" node.setAttribute(html2canvasNodeAttribute + index, index);" & @CRLF & _
" return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {" & @CRLF & _
" if (typeof(options.onrendered) === "function") {" & @CRLF & _
" log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas");" & @CRLF & _
" options.onrendered(canvas);" & @CRLF & _
" }" & @CRLF & _
" return canvas;" & @CRLF & _
" });" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"window.html2canvas.punycode = this.punycode;" & @CRLF & _
"window.html2canvas.proxy = {};" & @CRLF & _
"" & @CRLF & _
"function renderDocument(document, options, windowWidth, windowHeight, html2canvasIndex) {" & @CRLF & _
" return createWindowClone(document, document, windowWidth, windowHeight, options, document.defaultView.pageXOffset, document.defaultView.pageYOffset).then(function(container) {" & @CRLF & _
" log("Document cloned");" & @CRLF & _
" var attributeName = html2canvasNodeAttribute + html2canvasIndex;" & @CRLF & _
" var selector = "[" + attributeName + "='" + html2canvasIndex + "']";" & @CRLF & _
" document.querySelector(selector).removeAttribute(attributeName);" & @CRLF & _
" var clonedWindow = container.contentWindow;" & @CRLF & _
" var node = clonedWindow.document.querySelector(selector);" & @CRLF & _
" var oncloneHandler = (typeof(options.onclone) === "function") ? Promise.resolve(options.onclone(clonedWindow.document)) : Promise.resolve(true);" & @CRLF & _
" return oncloneHandler.then(function() {" & @CRLF & _
" return renderWindow(node, container, options, windowWidth, windowHeight);" & @CRLF & _
" });" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function renderWindow(node, container, options, windowWidth, windowHeight) {" & @CRLF & _
" var clonedWindow = container.contentWindow;" & @CRLF & _
" var support = new Support(clonedWindow.document);" & @CRLF & _
" var imageLoader = new ImageLoader(options, support);" & @CRLF & _
" var bounds = getBounds(node);" & @CRLF & _
" var width = options.type === "view" ? windowWidth : documentWidth(clonedWindow.document);" & @CRLF & _
" var height = options.type === "view" ? windowHeight : documentHeight(clonedWindow.document);" & @CRLF & _
" var renderer = new options.renderer(width, height, imageLoader, options, document);" & @CRLF & _
" var parser = new NodeParser(node, renderer, support, imageLoader, options);" & @CRLF & _
" return parser.ready.then(function() {" & @CRLF & _
" log("Finished rendering");" & @CRLF & _
" var canvas;" & @CRLF & _
"" & @CRLF & _
" if (options.type === "view") {" & @CRLF & _
" canvas = crop(renderer.canvas, {width: renderer.canvas.width, height: renderer.canvas.height, top: 0, left: 0, x: 0, y: 0});" & @CRLF & _
" } else if (node === clonedWindow.document.body || node === clonedWindow.document.documentElement || options.canvas != null) {" & @CRLF & _
" canvas = renderer.canvas;" & @CRLF & _
" } else {" & @CRLF & _
" canvas = crop(renderer.canvas, {width: options.width != null ? options.width : bounds.width, height: options.height != null ? options.height : bounds.height, top: bounds.top, left: bounds.left, x: clonedWindow.pageXOffset, y: clonedWindow.pageYOffset});" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" cleanupContainer(container, options);" & @CRLF & _
" return canvas;" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function cleanupContainer(container, options) {" & @CRLF & _
" if (options.removeContainer) {" & @CRLF & _
" container.parentNode.removeChild(container);" & @CRLF & _
" log("Cleaned up container");" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function crop(canvas, bounds) {" & @CRLF & _
" var croppedCanvas = document.createElement("canvas");" & @CRLF & _
" var x1 = Math.min(canvas.width - 1, Math.max(0, bounds.left));" & @CRLF & _
" var x2 = Math.min(canvas.width, Math.max(1, bounds.left + bounds.width));" & @CRLF & _
" var y1 = Math.min(canvas.height - 1, Math.max(0, bounds.top));" & @CRLF & _
" var y2 = Math.min(canvas.height, Math.max(1, bounds.top + bounds.height));" & @CRLF & _
" croppedCanvas.width = bounds.width;" & @CRLF & _
" croppedCanvas.height = bounds.height;" & @CRLF & _
" log("Cropping canvas at:", "left:", bounds.left, "top:", bounds.top, "width:", (x2-x1), "height:", (y2-y1));" & @CRLF & _
" log("Resulting crop with width", bounds.width, "and height", bounds.height, " with x", x1, "and y", y1);" & @CRLF & _
" croppedCanvas.getContext("2d").drawImage(canvas, x1, y1, x2-x1, y2-y1, bounds.x, bounds.y, x2-x1, y2-y1);" & @CRLF & _
" return croppedCanvas;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function documentWidth (doc) {" & @CRLF & _
" return Math.max(" & @CRLF & _
" Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth)," & @CRLF & _
" Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth)," & @CRLF & _
" Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)" & @CRLF & _
" );" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function documentHeight (doc) {" & @CRLF & _
" return Math.max(" & @CRLF & _
" Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight)," & @CRLF & _
" Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight)," & @CRLF & _
" Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)" & @CRLF & _
" );" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function smallImage() {" & @CRLF & _
" return "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isIE9() {" & @CRLF & _
" return document.documentMode && document.documentMode <= 9;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"// https://github.com/niklasvh/html2canvas/issues/503" & @CRLF & _
"function cloneNodeIE9(node, javascriptEnabled) {" & @CRLF & _
" var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);" & @CRLF & _
"" & @CRLF & _
" var child = node.firstChild;" & @CRLF & _
" while(child) {" & @CRLF & _
" if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {" & @CRLF & _
" clone.appendChild(cloneNodeIE9(child, javascriptEnabled));" & @CRLF & _
" }" & @CRLF & _
" child = child.nextSibling;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return clone;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function createWindowClone(ownerDocument, containerDocument, width, height, options, x ,y) {" & @CRLF & _
" labelCanvasElements(ownerDocument);" & @CRLF & _
" var documentElement = isIE9() ? cloneNodeIE9(ownerDocument.documentElement, options.javascriptEnabled) : ownerDocument.documentElement.cloneNode(true);" & @CRLF & _
" var container = containerDocument.createElement("iframe");" & @CRLF & _
"" & @CRLF & _
" container.className = "html2canvas-container";" & @CRLF & _
" container.style.visibility = "hidden";" & @CRLF & _
" container.style.position = "fixed";" & @CRLF & _
" container.style.left = "-10000px";" & @CRLF & _
" container.style.top = "0px";" & @CRLF & _
" container.style.border = "0";" & @CRLF & _
" container.width = width;" & @CRLF & _
" container.height = height;" & @CRLF & _
" container.scrolling = "no"; // ios won't scroll without it" & @CRLF & _
" containerDocument.body.appendChild(container);" & @CRLF & _
"" & @CRLF & _
" return new Promise(function(resolve) {" & @CRLF & _
" var documentClone = container.contentWindow.document;" & @CRLF & _
"" & @CRLF & _
" cloneNodeValues(ownerDocument.documentElement, documentElement, "textarea");" & @CRLF & _
" cloneNodeValues(ownerDocument.documentElement, documentElement, "select");" & @CRLF & _
"" & @CRLF & _
" /* Chrome doesn't detect relative background-images assigned in inline <style> sheets when fetched through getComputedStyle" & @CRLF & _
" if window url is about:blank, we can assign the url to current by writing onto the document" & @CRLF & _
" */" & @CRLF & _
" container.contentWindow.onload = container.onload = function() {" & @CRLF & _
" var interval = setInterval(function() {" & @CRLF & _
" if (documentClone.body.childNodes.length > 0) {" & @CRLF & _
" cloneCanvasContents(ownerDocument, documentClone);" & @CRLF & _
" clearInterval(interval);" & @CRLF & _
" if (options.type === "view") {" & @CRLF & _
" container.contentWindow.scrollTo(x, y);" & @CRLF & _
" }" & @CRLF & _
" resolve(container);" & @CRLF & _
" }" & @CRLF & _
" }, 50);" & @CRLF & _
" };" & @CRLF & _
"" & @CRLF & _
" documentClone.open();" & @CRLF & _
" documentClone.write("<!DOCTYPE html><html></html>");" & @CRLF & _
" // Chrome scrolls the parent document for some reason after the write to the cloned window???" & @CRLF & _
" restoreOwnerScroll(ownerDocument, x, y);" & @CRLF & _
" documentClone.replaceChild(options.javascriptEnabled === true ? documentClone.adoptNode(documentElement) : removeScriptNodes(documentClone.adoptNode(documentElement)), documentClone.documentElement);" & @CRLF & _
" documentClone.close();" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function cloneNodeValues(document, clone, nodeName) {" & @CRLF & _
" var originalNodes = document.getElementsByTagName(nodeName);" & @CRLF & _
" var clonedNodes = clone.getElementsByTagName(nodeName);" & @CRLF & _
" var count = originalNodes.length;" & @CRLF & _
" for (var i = 0; i < count; i++) {" & @CRLF & _
" clonedNodes[i].value = originalNodes[i].value;" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function restoreOwnerScroll(ownerDocument, x, y) {" & @CRLF & _
" if (ownerDocument.defaultView && (x !== ownerDocument.defaultView.pageXOffset || y !== ownerDocument.defaultView.pageYOffset)) {" & @CRLF & _
" ownerDocument.defaultView.scrollTo(x, y);" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function loadUrlDocument(src, proxy, document, width, height, options) {" & @CRLF & _
" return new Proxy(src, proxy, window.document).then(documentFromHTML(src)).then(function(doc) {" & @CRLF & _
" return createWindowClone(doc, document, width, height, options, 0, 0);" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function documentFromHTML(src) {" & @CRLF & _
" return function(html) {" & @CRLF & _
" var parser = new DOMParser(), doc;" & @CRLF & _
" try {" & @CRLF & _
" doc = parser.parseFromString(html, "text/html");" & @CRLF & _
" } catch(e) {" & @CRLF & _
" log("DOMParser not supported, falling back to createHTMLDocument");" & @CRLF & _
" doc = document.implementation.createHTMLDocument("");" & @CRLF & _
" try {" & @CRLF & _
" doc.open();" & @CRLF & _
" doc.write(html);" & @CRLF & _
" doc.close();" & @CRLF & _
" } catch(ee) {" & @CRLF & _
" log("createHTMLDocument write not supported, falling back to document.body.innerHTML");" & @CRLF & _
" doc.body.innerHTML = html; // ie9 doesnt support writing to documentElement" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" var b = doc.querySelector("base");" & @CRLF & _
" if (!b || !b.href.host) {" & @CRLF & _
" var base = doc.createElement("base");" & @CRLF & _
" base.href = src;" & @CRLF & _
" doc.head.insertBefore(base, doc.head.firstChild);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return doc;" & @CRLF & _
" };" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"" & @CRLF & _
"function labelCanvasElements(ownerDocument) {" & @CRLF & _
" [].slice.call(ownerDocument.querySelectorAll("canvas"), 0).forEach(function(canvas) {" & @CRLF & _
" canvas.setAttribute(html2canvasCanvasCloneAttribute, "canvas-" + html2canvasCanvasCloneIndex++);" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function cloneCanvasContents(ownerDocument, documentClone) {" & @CRLF & _
" [].slice.call(ownerDocument.querySelectorAll("[" + html2canvasCanvasCloneAttribute + "]"), 0).forEach(function(canvas) {" & @CRLF & _
" try {" & @CRLF & _
" var clonedCanvas = documentClone.querySelector('[' + html2canvasCanvasCloneAttribute + '="' + canvas.getAttribute(html2canvasCanvasCloneAttribute) + '"]');" & @CRLF & _
" if (clonedCanvas) {" & @CRLF & _
" clonedCanvas.width = canvas.width;" & @CRLF & _
" clonedCanvas.height = canvas.height;" & @CRLF & _
" clonedCanvas.getContext("2d").putImageData(canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height), 0, 0);" & @CRLF & _
" }" & @CRLF & _
" } catch(e) {" & @CRLF & _
" log("Unable to copy canvas content from", canvas, e);" & @CRLF & _
" }" & @CRLF & _
" canvas.removeAttribute(html2canvasCanvasCloneAttribute);" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function removeScriptNodes(parent) {" & @CRLF & _
" [].slice.call(parent.childNodes, 0).filter(isElementNode).forEach(function(node) {" & @CRLF & _
" if (node.tagName === "SCRIPT") {" & @CRLF & _
" parent.removeChild(node);" & @CRLF & _
" } else {" & @CRLF & _
" removeScriptNodes(node);" & @CRLF & _
" }" & @CRLF & _
" });" & @CRLF & _
" return parent;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isElementNode(node) {" & @CRLF & _
" return node.nodeType === Node.ELEMENT_NODE;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function absoluteUrl(url) {" & @CRLF & _
" var link = document.createElement("a");" & @CRLF & _
" link.href = url;" & @CRLF & _
" link.href = link.href;" & @CRLF & _
" return link;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"// http://dev.w3.org/csswg/css-color/" & @CRLF & _
"" & @CRLF & _
"function Color(value) {" & @CRLF & _
" this.r = 0;" & @CRLF & _
" this.g = 0;" & @CRLF & _
" this.b = 0;" & @CRLF & _
" this.a = null;" & @CRLF & _
" var result = this.fromArray(value) ||" & @CRLF & _
" this.namedColor(value) ||" & @CRLF & _
" this.rgb(value) ||" & @CRLF & _
" this.rgba(value) ||" & @CRLF & _
" this.hex6(value) ||" & @CRLF & _
" this.hex3(value);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"Color.prototype.darken = function(amount) {" & @CRLF & _
" var a = 1 - amount;" & @CRLF & _
" return new Color([" & @CRLF & _
" Math.round(this.r * a)," & @CRLF & _
" Math.round(this.g * a)," & @CRLF & _
" Math.round(this.b * a)," & @CRLF & _
" this.a" & @CRLF & _
" ]);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Color.prototype.isTransparent = function() {" & @CRLF & _
" return this.a === 0;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Color.prototype.isBlack = function() {" & @CRLF & _
" return this.r === 0 && this.g === 0 && this.b === 0;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Color.prototype.fromArray = function(array) {" & @CRLF & _
" if (Array.isArray(array)) {" & @CRLF & _
" this.r = Math.min(array[0], 255);" & @CRLF & _
" this.g = Math.min(array[1], 255);" & @CRLF & _
" this.b = Math.min(array[2], 255);" & @CRLF & _
" if (array.length > 3) {" & @CRLF & _
" this.a = array[3];" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return (Array.isArray(array));" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"var _hex3 = /^#([a-f0-9]{3})$/i;" & @CRLF & _
"" & @CRLF & _
"Color.prototype.hex3 = function(value) {" & @CRLF & _
" var match = null;" & @CRLF & _
" if ((match = value.match(_hex3)) !== null) {" & @CRLF & _
" this.r = parseInt(match[1][0] + match[1][0], 16);" & @CRLF & _
" this.g = parseInt(match[1][1] + match[1][1], 16);" & @CRLF & _
" this.b = parseInt(match[1][2] + match[1][2], 16);" & @CRLF & _
" }" & @CRLF & _
" return match !== null;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"var _hex6 = /^#([a-f0-9]{6})$/i;" & @CRLF & _
"" & @CRLF & _
"Color.prototype.hex6 = function(value) {" & @CRLF & _
" var match = null;" & @CRLF & _
" if ((match = value.match(_hex6)) !== null) {" & @CRLF & _
" this.r = parseInt(match[1].substring(0, 2), 16);" & @CRLF & _
" this.g = parseInt(match[1].substring(2, 4), 16);" & @CRLF & _
" this.b = parseInt(match[1].substring(4, 6), 16);" & @CRLF & _
" }" & @CRLF & _
" return match !== null;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"" & @CRLF & _
"var _rgb = /^rgb\((\d{1,3}) *, *(\d{1,3}) *, *(\d{1,3})\)$/;" & @CRLF & _
"" & @CRLF & _
"Color.prototype.rgb = function(value) {" & @CRLF & _
" var match = null;" & @CRLF & _
" if ((match = value.match(_rgb)) !== null) {" & @CRLF & _
" this.r = Number(match[1]);" & @CRLF & _
" this.g = Number(match[2]);" & @CRLF & _
" this.b = Number(match[3]);" & @CRLF & _
" }" & @CRLF & _
" return match !== null;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"var _rgba = /^rgba\((\d{1,3}) *, *(\d{1,3}) *, *(\d{1,3}) *, *(\d+\.?\d*)\)$/;" & @CRLF & _
"" & @CRLF & _
"Color.prototype.rgba = function(value) {" & @CRLF & _
" var match = null;" & @CRLF & _
" if ((match = value.match(_rgba)) !== null) {" & @CRLF & _
" this.r = Number(match[1]);" & @CRLF & _
" this.g = Number(match[2]);" & @CRLF & _
" this.b = Number(match[3]);" & @CRLF & _
" this.a = Number(match[4]);" & @CRLF & _
" }" & @CRLF & _
" return match !== null;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Color.prototype.toString = function() {" & @CRLF & _
" return this.a !== null && this.a !== 1 ?" & @CRLF & _
" "rgba(" + [this.r, this.g, this.b, this.a].join(",") + ")" :" & @CRLF & _
" "rgb(" + [this.r, this.g, this.b].join(",") + ")";" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Color.prototype.namedColor = function(value) {" & @CRLF & _
" var color = colors[value.toLowerCase()];" & @CRLF & _
" if (color) {" & @CRLF & _
" this.r = color[0];" & @CRLF & _
" this.g = color[1];" & @CRLF & _
" this.b = color[2];" & @CRLF & _
" } else if (value.toLowerCase() === "transparent") {" & @CRLF & _
" this.r = this.g = this.b = this.a = 0;" & @CRLF & _
" return true;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return !!color;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Color.prototype.isColor = true;" & @CRLF & _
"" & @CRLF & _
"// JSON.stringify([].slice.call($$('.named-color-table tr'), 1).map(function(row) { return [row.childNodes[3].textContent, row.childNodes[5].textContent.trim().split(",").map(Number)] }).reduce(function(data, row) {data[row[0]] = row[1]; return data}, {}))" & @CRLF & _
"var colors = {" & @CRLF & _
" "aliceblue": [240, 248, 255]," & @CRLF & _
" "antiquewhite": [250, 235, 215]," & @CRLF & _
" "aqua": [0, 255, 255]," & @CRLF & _
" "aquamarine": [127, 255, 212]," & @CRLF & _
" "azure": [240, 255, 255]," & @CRLF & _
" "beige": [245, 245, 220]," & @CRLF & _
" "bisque": [255, 228, 196]," & @CRLF & _
" "black": [0, 0, 0]," & @CRLF & _
" "blanchedalmond": [255, 235, 205]," & @CRLF & _
" "blue": [0, 0, 255]," & @CRLF & _
" "blueviolet": [138, 43, 226]," & @CRLF & _
" "brown": [165, 42, 42]," & @CRLF & _
" "burlywood": [222, 184, 135]," & @CRLF & _
" "cadetblue": [95, 158, 160]," & @CRLF & _
" "chartreuse": [127, 255, 0]," & @CRLF & _
" "chocolate": [210, 105, 30]," & @CRLF & _
" "coral": [255, 127, 80]," & @CRLF & _
" "cornflowerblue": [100, 149, 237]," & @CRLF & _
" "cornsilk": [255, 248, 220]," & @CRLF & _
" "crimson": [220, 20, 60]," & @CRLF & _
" "cyan": [0, 255, 255]," & @CRLF & _
" "darkblue": [0, 0, 139]," & @CRLF & _
" "darkcyan": [0, 139, 139]," & @CRLF & _
" "darkgoldenrod": [184, 134, 11]," & @CRLF & _
" "darkgray": [169, 169, 169]," & @CRLF & _
" "darkgreen": [0, 100, 0]," & @CRLF & _
" "darkgrey": [169, 169, 169]," & @CRLF & _
" "darkkhaki": [189, 183, 107]," & @CRLF & _
" "darkmagenta": [139, 0, 139]," & @CRLF & _
" "darkolivegreen": [85, 107, 47]," & @CRLF & _
" "darkorange": [255, 140, 0]," & @CRLF & _
" "darkorchid": [153, 50, 204]," & @CRLF & _
" "darkred": [139, 0, 0]," & @CRLF & _
" "darksalmon": [233, 150, 122]," & @CRLF & _
" "darkseagreen": [143, 188, 143]," & @CRLF & _
" "darkslateblue": [72, 61, 139]," & @CRLF & _
" "darkslategray": [47, 79, 79]," & @CRLF & _
" "darkslategrey": [47, 79, 79]," & @CRLF & _
" "darkturquoise": [0, 206, 209]," & @CRLF & _
" "darkviolet": [148, 0, 211]," & @CRLF & _
" "deeppink": [255, 20, 147]," & @CRLF & _
" "deepskyblue": [0, 191, 255]," & @CRLF & _
" "dimgray": [105, 105, 105]," & @CRLF & _
" "dimgrey": [105, 105, 105]," & @CRLF & _
" "dodgerblue": [30, 144, 255]," & @CRLF & _
" "firebrick": [178, 34, 34]," & @CRLF & _
" "floralwhite": [255, 250, 240]," & @CRLF & _
" "forestgreen": [34, 139, 34]," & @CRLF & _
" "fuchsia": [255, 0, 255]," & @CRLF & _
" "gainsboro": [220, 220, 220]," & @CRLF & _
" "ghostwhite": [248, 248, 255]," & @CRLF & _
" "gold": [255, 215, 0]," & @CRLF & _
" "goldenrod": [218, 165, 32]," & @CRLF & _
" "gray": [128, 128, 128]," & @CRLF & _
" "green": [0, 128, 0]," & @CRLF & _
" "greenyellow": [173, 255, 47]," & @CRLF & _
" "grey": [128, 128, 128]," & @CRLF & _
" "honeydew": [240, 255, 240]," & @CRLF & _
" "hotpink": [255, 105, 180]," & @CRLF & _
" "indianred": [205, 92, 92]," & @CRLF & _
" "indigo": [75, 0, 130]," & @CRLF & _
" "ivory": [255, 255, 240]," & @CRLF & _
" "khaki": [240, 230, 140]," & @CRLF & _
" "lavender": [230, 230, 250]," & @CRLF & _
" "lavenderblush": [255, 240, 245]," & @CRLF & _
" "lawngreen": [124, 252, 0]," & @CRLF & _
" "lemonchiffon": [255, 250, 205]," & @CRLF & _
" "lightblue": [173, 216, 230]," & @CRLF & _
" "lightcoral": [240, 128, 128]," & @CRLF & _
" "lightcyan": [224, 255, 255]," & @CRLF & _
" "lightgoldenrodyellow": [250, 250, 210]," & @CRLF & _
" "lightgray": [211, 211, 211]," & @CRLF & _
" "lightgreen": [144, 238, 144]," & @CRLF & _
" "lightgrey": [211, 211, 211]," & @CRLF & _
" "lightpink": [255, 182, 193]," & @CRLF & _
" "lightsalmon": [255, 160, 122]," & @CRLF & _
" "lightseagreen": [32, 178, 170]," & @CRLF & _
" "lightskyblue": [135, 206, 250]," & @CRLF & _
" "lightslategray": [119, 136, 153]," & @CRLF & _
" "lightslategrey": [119, 136, 153]," & @CRLF & _
" "lightsteelblue": [176, 196, 222]," & @CRLF & _
" "lightyellow": [255, 255, 224]," & @CRLF & _
" "lime": [0, 255, 0]," & @CRLF & _
" "limegreen": [50, 205, 50]," & @CRLF & _
" "linen": [250, 240, 230]," & @CRLF & _
" "magenta": [255, 0, 255]," & @CRLF & _
" "maroon": [128, 0, 0]," & @CRLF & _
" "mediumaquamarine": [102, 205, 170]," & @CRLF & _
" "mediumblue": [0, 0, 205]," & @CRLF & _
" "mediumorchid": [186, 85, 211]," & @CRLF & _
" "mediumpurple": [147, 112, 219]," & @CRLF & _
" "mediumseagreen": [60, 179, 113]," & @CRLF & _
" "mediumslateblue": [123, 104, 238]," & @CRLF & _
" "mediumspringgreen": [0, 250, 154]," & @CRLF & _
" "mediumturquoise": [72, 209, 204]," & @CRLF & _
" "mediumvioletred": [199, 21, 133]," & @CRLF & _
" "midnightblue": [25, 25, 112]," & @CRLF & _
" "mintcream": [245, 255, 250]," & @CRLF & _
" "mistyrose": [255, 228, 225]," & @CRLF & _
" "moccasin": [255, 228, 181]," & @CRLF & _
" "navajowhite": [255, 222, 173]," & @CRLF & _
" "navy": [0, 0, 128]," & @CRLF & _
" "oldlace": [253, 245, 230]," & @CRLF & _
" "olive": [128, 128, 0]," & @CRLF & _
" "olivedrab": [107, 142, 35]," & @CRLF & _
" "orange": [255, 165, 0]," & @CRLF & _
" "orangered": [255, 69, 0]," & @CRLF & _
" "orchid": [218, 112, 214]," & @CRLF & _
" "palegoldenrod": [238, 232, 170]," & @CRLF & _
" "palegreen": [152, 251, 152]," & @CRLF & _
" "paleturquoise": [175, 238, 238]," & @CRLF & _
" "palevioletred": [219, 112, 147]," & @CRLF & _
" "papayawhip": [255, 239, 213]," & @CRLF & _
" "peachpuff": [255, 218, 185]," & @CRLF & _
" "peru": [205, 133, 63]," & @CRLF & _
" "pink": [255, 192, 203]," & @CRLF & _
" "plum": [221, 160, 221]," & @CRLF & _
" "powderblue": [176, 224, 230]," & @CRLF & _
" "purple": [128, 0, 128]," & @CRLF & _
" "rebeccapurple": [102, 51, 153]," & @CRLF & _
" "red": [255, 0, 0]," & @CRLF & _
" "rosybrown": [188, 143, 143]," & @CRLF & _
" "royalblue": [65, 105, 225]," & @CRLF & _
" "saddlebrown": [139, 69, 19]," & @CRLF & _
" "salmon": [250, 128, 114]," & @CRLF & _
" "sandybrown": [244, 164, 96]," & @CRLF & _
" "seagreen": [46, 139, 87]," & @CRLF & _
" "seashell": [255, 245, 238]," & @CRLF & _
" "sienna": [160, 82, 45]," & @CRLF & _
" "silver": [192, 192, 192]," & @CRLF & _
" "skyblue": [135, 206, 235]," & @CRLF & _
" "slateblue": [106, 90, 205]," & @CRLF & _
" "slategray": [112, 128, 144]," & @CRLF & _
" "slategrey": [112, 128, 144]," & @CRLF & _
" "snow": [255, 250, 250]," & @CRLF & _
" "springgreen": [0, 255, 127]," & @CRLF & _
" "steelblue": [70, 130, 180]," & @CRLF & _
" "tan": [210, 180, 140]," & @CRLF & _
" "teal": [0, 128, 128]," & @CRLF & _
" "thistle": [216, 191, 216]," & @CRLF & _
" "tomato": [255, 99, 71]," & @CRLF & _
" "turquoise": [64, 224, 208]," & @CRLF & _
" "violet": [238, 130, 238]," & @CRLF & _
" "wheat": [245, 222, 179]," & @CRLF & _
" "white": [255, 255, 255]," & @CRLF & _
" "whitesmoke": [245, 245, 245]," & @CRLF & _
" "yellow": [255, 255, 0]," & @CRLF & _
" "yellowgreen": [154, 205, 50]" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"" & @CRLF & _
"function DummyImageContainer(src) {" & @CRLF & _
" this.src = src;" & @CRLF & _
" log("DummyImageContainer for", src);" & @CRLF & _
" if (!this.promise || !this.image) {" & @CRLF & _
" log("Initiating DummyImageContainer");" & @CRLF & _
" DummyImageContainer.prototype.image = new Image();" & @CRLF & _
" var image = this.image;" & @CRLF & _
" DummyImageContainer.prototype.promise = new Promise(function(resolve, reject) {" & @CRLF & _
" image.onload = resolve;" & @CRLF & _
" image.onerror = reject;" & @CRLF & _
" image.src = smallImage();" & @CRLF & _
" if (image.complete === true) {" & @CRLF & _
" resolve(image);" & @CRLF & _
" }" & @CRLF & _
" });" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function Font(family, size) {" & @CRLF & _
" var container = document.createElement('div')," & @CRLF & _
" img = document.createElement('img')," & @CRLF & _
" span = document.createElement('span')," & @CRLF & _
" sampleText = 'Hidden Text'," & @CRLF & _
" baseline," & @CRLF & _
" middle;" & @CRLF & _
"" & @CRLF & _
" container.style.visibility = "hidden";" & @CRLF & _
" container.style.fontFamily = family;" & @CRLF & _
" container.style.fontSize = size;" & @CRLF & _
" container.style.margin = 0;" & @CRLF & _
" container.style.padding = 0;" & @CRLF & _
"" & @CRLF & _
" document.body.appendChild(container);" & @CRLF & _
"" & @CRLF & _
" img.src = smallImage();" & @CRLF & _
" img.width = 1;" & @CRLF & _
" img.height = 1;" & @CRLF & _
"" & @CRLF & _
" img.style.margin = 0;" & @CRLF & _
" img.style.padding = 0;" & @CRLF & _
" img.style.verticalAlign = "baseline";" & @CRLF & _
"" & @CRLF & _
" span.style.fontFamily = family;" & @CRLF & _
" span.style.fontSize = size;" & @CRLF & _
" span.style.margin = 0;" & @CRLF & _
" span.style.padding = 0;" & @CRLF & _
"" & @CRLF & _
" span.appendChild(document.createTextNode(sampleText));" & @CRLF & _
" container.appendChild(span);" & @CRLF & _
" container.appendChild(img);" & @CRLF & _
" baseline = (img.offsetTop - span.offsetTop) + 1;" & @CRLF & _
"" & @CRLF & _
" container.removeChild(span);" & @CRLF & _
" container.appendChild(document.createTextNode(sampleText));" & @CRLF & _
"" & @CRLF & _
" container.style.lineHeight = "normal";" & @CRLF & _
" img.style.verticalAlign = "super";" & @CRLF & _
"" & @CRLF & _
" middle = (img.offsetTop-container.offsetTop) + 1;" & @CRLF & _
"" & @CRLF & _
" document.body.removeChild(container);" & @CRLF & _
"" & @CRLF & _
" this.baseline = baseline;" & @CRLF & _
" this.lineWidth = 1;" & @CRLF & _
" this.middle = middle;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function FontMetrics() {" & @CRLF & _
" this.data = {};" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"FontMetrics.prototype.getMetrics = function(family, size) {" & @CRLF & _
" if (this.data[family + "-" + size] === undefined) {" & @CRLF & _
" this.data[family + "-" + size] = new Font(family, size);" & @CRLF & _
" }" & @CRLF & _
" return this.data[family + "-" + size];" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function FrameContainer(container, sameOrigin, options) {" & @CRLF & _
" this.image = null;" & @CRLF & _
" this.src = container;" & @CRLF & _
" var self = this;" & @CRLF & _
" var bounds = getBounds(container);" & @CRLF & _
" this.promise = (!sameOrigin ? this.proxyLoad(options.proxy, bounds, options) : new Promise(function(resolve) {" & @CRLF & _
" if (container.contentWindow.document.URL === "about:blank" || container.contentWindow.document.documentElement == null) {" & @CRLF & _
" container.contentWindow.onload = container.onload = function() {" & @CRLF & _
" resolve(container);" & @CRLF & _
" };" & @CRLF & _
" } else {" & @CRLF & _
" resolve(container);" & @CRLF & _
" }" & @CRLF & _
" })).then(function(container) {" & @CRLF & _
" return html2canvas(container.contentWindow.document.documentElement, {type: 'view', width: container.width, height: container.height, proxy: options.proxy, javascriptEnabled: options.javascriptEnabled, removeContainer: options.removeContainer, allowTaint: options.allowTaint, imageTimeout: options.imageTimeout / 2});" & @CRLF & _
" }).then(function(canvas) {" & @CRLF & _
" return self.image = canvas;" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"FrameContainer.prototype.proxyLoad = function(proxy, bounds, options) {" & @CRLF & _
" var container = this.src;" & @CRLF & _
" return loadUrlDocument(container.src, proxy, container.ownerDocument, bounds.width, bounds.height, options);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function GradientContainer(imageData) {" & @CRLF & _
" this.src = imageData.value;" & @CRLF & _
" this.colorStops = [];" & @CRLF & _
" this.type = null;" & @CRLF & _
" this.x0 = 0.5;" & @CRLF & _
" this.y0 = 0.5;" & @CRLF & _
" this.x1 = 0.5;" & @CRLF & _
" this.y1 = 0.5;" & @CRLF & _
" this.promise = Promise.resolve(true);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"GradientContainer.prototype.TYPES = {" & @CRLF & _
" LINEAR: 1," & @CRLF & _
" RADIAL: 2" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function ImageContainer(src, cors) {" & @CRLF & _
" this.src = src;" & @CRLF & _
" this.image = new Image();" & @CRLF & _
" var self = this;" & @CRLF & _
" this.tainted = null;" & @CRLF & _
" this.promise = new Promise(function(resolve, reject) {" & @CRLF & _
" self.image.onload = resolve;" & @CRLF & _
" self.image.onerror = reject;" & @CRLF & _
" if (cors) {" & @CRLF & _
" self.image.crossOrigin = "anonymous";" & @CRLF & _
" }" & @CRLF & _
" self.image.src = src;" & @CRLF & _
" if (self.image.complete === true) {" & @CRLF & _
" resolve(self.image);" & @CRLF & _
" }" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function ImageLoader(options, support) {" & @CRLF & _
" this.link = null;" & @CRLF & _
" this.options = options;" & @CRLF & _
" this.support = support;" & @CRLF & _
" this.origin = this.getOrigin(window.location.href);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.findImages = function(nodes) {" & @CRLF & _
" var images = [];" & @CRLF & _
" nodes.reduce(function(imageNodes, container) {" & @CRLF & _
" switch(container.node.nodeName) {" & @CRLF & _
" case "IMG":" & @CRLF & _
" return imageNodes.concat([{" & @CRLF & _
" args: [container.node.src]," & @CRLF & _
" method: "url"" & @CRLF & _
" }]);" & @CRLF & _
" case "svg":" & @CRLF & _
" case "IFRAME":" & @CRLF & _
" return imageNodes.concat([{" & @CRLF & _
" args: [container.node]," & @CRLF & _
" method: container.node.nodeName" & @CRLF & _
" }]);" & @CRLF & _
" }" & @CRLF & _
" return imageNodes;" & @CRLF & _
" }, []).forEach(this.addImage(images, this.loadImage), this);" & @CRLF & _
" return images;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.findBackgroundImage = function(images, container) {" & @CRLF & _
" container.parseBackgroundImages().filter(this.hasImageBackground).forEach(this.addImage(images, this.loadImage), this);" & @CRLF & _
" return images;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.addImage = function(images, callback) {" & @CRLF & _
" return function(newImage) {" & @CRLF & _
" newImage.args.forEach(function(image) {" & @CRLF & _
" if (!this.imageExists(images, image)) {" & @CRLF & _
" images.splice(0, 0, callback.call(this, newImage));" & @CRLF & _
" log('Added image #' + (images.length), typeof(image) === "string" ? image.substring(0, 100) : image);" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
" };" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.hasImageBackground = function(imageData) {" & @CRLF & _
" return imageData.method !== "none";" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.loadImage = function(imageData) {" & @CRLF & _
" if (imageData.method === "url") {" & @CRLF & _
" var src = imageData.args[0];" & @CRLF & _
" if (this.isSVG(src) && !this.support.svg && !this.options.allowTaint) {" & @CRLF & _
" return new SVGContainer(src);" & @CRLF & _
" } else if (src.match(/data:image\/.*;base64,/i)) {" & @CRLF & _
" return new ImageContainer(src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''), false);" & @CRLF & _
" } else if (this.isSameOrigin(src) || this.options.allowTaint === true || this.isSVG(src)) {" & @CRLF & _
" return new ImageContainer(src, false);" & @CRLF & _
" } else if (this.support.cors && !this.options.allowTaint && this.options.useCORS) {" & @CRLF & _
" return new ImageContainer(src, true);" & @CRLF & _
" } else if (this.options.proxy) {" & @CRLF & _
" return new ProxyImageContainer(src, this.options.proxy);" & @CRLF & _
" } else {" & @CRLF & _
" return new DummyImageContainer(src);" & @CRLF & _
" }" & @CRLF & _
" } else if (imageData.method === "linear-gradient") {" & @CRLF & _
" return new LinearGradientContainer(imageData);" & @CRLF & _
" } else if (imageData.method === "gradient") {" & @CRLF & _
" return new WebkitGradientContainer(imageData);" & @CRLF & _
" } else if (imageData.method === "svg") {" & @CRLF & _
" return new SVGNodeContainer(imageData.args[0], this.support.svg);" & @CRLF & _
" } else if (imageData.method === "IFRAME") {" & @CRLF & _
" return new FrameContainer(imageData.args[0], this.isSameOrigin(imageData.args[0].src), this.options);" & @CRLF & _
" } else {" & @CRLF & _
" return new DummyImageContainer(imageData);" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.isSVG = function(src) {" & @CRLF & _
" return src.substring(src.length - 3).toLowerCase() === "svg" || SVGContainer.prototype.isInline(src);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.imageExists = function(images, src) {" & @CRLF & _
" return images.some(function(image) {" & @CRLF & _
" return image.src === src;" & @CRLF & _
" });" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.isSameOrigin = function(url) {" & @CRLF & _
" return (this.getOrigin(url) === this.origin);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.getOrigin = function(url) {" & @CRLF & _
" var link = this.link || (this.link = document.createElement("a"));" & @CRLF & _
" link.href = url;" & @CRLF & _
" link.href = link.href; // IE9, LOL! - http://jsfiddle.net/niklasvh/2e48b/" & @CRLF & _
" return link.protocol + link.hostname + link.port;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.getPromise = function(container) {" & @CRLF & _
" return this.timeout(container, this.options.imageTimeout)['catch'](function() {" & @CRLF & _
" var dummy = new DummyImageContainer(container.src);" & @CRLF & _
" return dummy.promise.then(function(image) {" & @CRLF & _
" container.image = image;" & @CRLF & _
" });" & @CRLF & _
" });" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.get = function(src) {" & @CRLF & _
" var found = null;" & @CRLF & _
" return this.images.some(function(img) {" & @CRLF & _
" return (found = img).src === src;" & @CRLF & _
" }) ? found : null;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.fetch = function(nodes) {" & @CRLF & _
" this.images = nodes.reduce(bind(this.findBackgroundImage, this), this.findImages(nodes));" & @CRLF & _
" this.images.forEach(function(image, index) {" & @CRLF & _
" image.promise.then(function() {" & @CRLF & _
" log("Succesfully loaded image #"+ (index+1), image);" & @CRLF & _
" }, function(e) {" & @CRLF & _
" log("Failed loading image #"+ (index+1), image, e);" & @CRLF & _
" });" & @CRLF & _
" });" & @CRLF & _
" this.ready = Promise.all(this.images.map(this.getPromise, this));" & @CRLF & _
" log("Finished searching images");" & @CRLF & _
" return this;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"ImageLoader.prototype.timeout = function(container, timeout) {" & @CRLF & _
" var timer;" & @CRLF & _
" var promise = Promise.race([container.promise, new Promise(function(res, reject) {" & @CRLF & _
" timer = setTimeout(function() {" & @CRLF & _
" log("Timed out loading image", container);" & @CRLF & _
" reject(container);" & @CRLF & _
" }, timeout);" & @CRLF & _
" })]).then(function(container) {" & @CRLF & _
" clearTimeout(timer);" & @CRLF & _
" return container;" & @CRLF & _
" });" & @CRLF & _
" promise['catch'](function() {" & @CRLF & _
" clearTimeout(timer);" & @CRLF & _
" });" & @CRLF & _
" return promise;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function LinearGradientContainer(imageData) {" & @CRLF & _
" GradientContainer.apply(this, arguments);" & @CRLF & _
" this.type = this.TYPES.LINEAR;" & @CRLF & _
"" & @CRLF & _
" var hasDirection = imageData.args[0].match(this.stepRegExp) === null;" & @CRLF & _
"" & @CRLF & _
" if (hasDirection) {" & @CRLF & _
" imageData.args[0].split(" ").reverse().forEach(function(position) {" & @CRLF & _
" switch(position) {" & @CRLF & _
" case "left":" & @CRLF & _
" this.x0 = 0;" & @CRLF & _
" this.x1 = 1;" & @CRLF & _
" break;" & @CRLF & _
" case "top":" & @CRLF & _
" this.y0 = 0;" & @CRLF & _
" this.y1 = 1;" & @CRLF & _
" break;" & @CRLF & _
" case "right":" & @CRLF & _
" this.x0 = 1;" & @CRLF & _
" this.x1 = 0;" & @CRLF & _
" break;" & @CRLF & _
" case "bottom":" & @CRLF & _
" this.y0 = 1;" & @CRLF & _
" this.y1 = 0;" & @CRLF & _
" break;" & @CRLF & _
" case "to":" & @CRLF & _
" var y0 = this.y0;" & @CRLF & _
" var x0 = this.x0;" & @CRLF & _
" this.y0 = this.y1;" & @CRLF & _
" this.x0 = this.x1;" & @CRLF & _
" this.x1 = x0;" & @CRLF & _
" this.y1 = y0;" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
" } else {" & @CRLF & _
" this.y0 = 0;" & @CRLF & _
" this.y1 = 1;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" this.colorStops = imageData.args.slice(hasDirection ? 1 : 0).map(function(colorStop) {" & @CRLF & _
" var colorStopMatch = colorStop.match(this.stepRegExp);" & @CRLF & _
" return {" & @CRLF & _
" color: new Color(colorStopMatch[1])," & @CRLF & _
" stop: colorStopMatch[3] === "%" ? colorStopMatch[2] / 100 : null" & @CRLF & _
" };" & @CRLF & _
" }, this);" & @CRLF & _
"" & @CRLF & _
" if (this.colorStops[0].stop === null) {" & @CRLF & _
" this.colorStops[0].stop = 0;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (this.colorStops[this.colorStops.length - 1].stop === null) {" & @CRLF & _
" this.colorStops[this.colorStops.length - 1].stop = 1;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" this.colorStops.forEach(function(colorStop, index) {" & @CRLF & _
" if (colorStop.stop === null) {" & @CRLF & _
" this.colorStops.slice(index).some(function(find, count) {" & @CRLF & _
" if (find.stop !== null) {" & @CRLF & _
" colorStop.stop = ((find.stop - this.colorStops[index - 1].stop) / (count + 1)) + this.colorStops[index - 1].stop;" & @CRLF & _
" return true;" & @CRLF & _
" } else {" & @CRLF & _
" return false;" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"LinearGradientContainer.prototype = Object.create(GradientContainer.prototype);" & @CRLF & _
"" & @CRLF & _
"LinearGradientContainer.prototype.stepRegExp = /((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/;" & @CRLF & _
"" & @CRLF & _
"function log() {" & @CRLF & _
" if (window.html2canvas.logging && window.console && window.console.log) {" & @CRLF & _
" Function.prototype.bind.call(window.console.log, (window.console)).apply(window.console, [(Date.now() - window.html2canvas.start) + "ms", "html2canvas:"].concat([].slice.call(arguments, 0)));" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function NodeContainer(node, parent) {" & @CRLF & _
" this.node = node;" & @CRLF & _
" this.parent = parent;" & @CRLF & _
" this.stack = null;" & @CRLF & _
" this.bounds = null;" & @CRLF & _
" this.borders = null;" & @CRLF & _
" this.clip = [];" & @CRLF & _
" this.backgroundClip = [];" & @CRLF & _
" this.offsetBounds = null;" & @CRLF & _
" this.visible = null;" & @CRLF & _
" this.computedStyles = null;" & @CRLF & _
" this.colors = {};" & @CRLF & _
" this.styles = {};" & @CRLF & _
" this.backgroundImages = null;" & @CRLF & _
" this.transformData = null;" & @CRLF & _
" this.transformMatrix = null;" & @CRLF & _
" this.isPseudoElement = false;" & @CRLF & _
" this.opacity = null;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.cloneTo = function(stack) {" & @CRLF & _
" stack.visible = this.visible;" & @CRLF & _
" stack.borders = this.borders;" & @CRLF & _
" stack.bounds = this.bounds;" & @CRLF & _
" stack.clip = this.clip;" & @CRLF & _
" stack.backgroundClip = this.backgroundClip;" & @CRLF & _
" stack.computedStyles = this.computedStyles;" & @CRLF & _
" stack.styles = this.styles;" & @CRLF & _
" stack.backgroundImages = this.backgroundImages;" & @CRLF & _
" stack.opacity = this.opacity;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.getOpacity = function() {" & @CRLF & _
" return this.opacity === null ? (this.opacity = this.cssFloat('opacity')) : this.opacity;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.assignStack = function(stack) {" & @CRLF & _
" this.stack = stack;" & @CRLF & _
" stack.children.push(this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.isElementVisible = function() {" & @CRLF & _
" return this.node.nodeType === Node.TEXT_NODE ? this.parent.visible : (" & @CRLF & _
" this.css('display') !== "none" &&" & @CRLF & _
" this.css('visibility') !== "hidden" &&" & @CRLF & _
" !this.node.hasAttribute("data-html2canvas-ignore") &&" & @CRLF & _
" (this.node.nodeName !== "INPUT" || this.node.getAttribute("type") !== "hidden")" & @CRLF & _
" );" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.css = function(attribute) {" & @CRLF & _
" if (!this.computedStyles) {" & @CRLF & _
" this.computedStyles = this.isPseudoElement ? this.parent.computedStyle(this.before ? ":before" : ":after") : this.computedStyle(null);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return this.styles[attribute] || (this.styles[attribute] = this.computedStyles[attribute]);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.prefixedCss = function(attribute) {" & @CRLF & _
" var prefixes = ["webkit", "moz", "ms", "o"];" & @CRLF & _
" var value = this.css(attribute);" & @CRLF & _
" if (value === undefined) {" & @CRLF & _
" prefixes.some(function(prefix) {" & @CRLF & _
" value = this.css(prefix + attribute.substr(0, 1).toUpperCase() + attribute.substr(1));" & @CRLF & _
" return value !== undefined;" & @CRLF & _
" }, this);" & @CRLF & _
" }" & @CRLF & _
" return value === undefined ? null : value;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.computedStyle = function(type) {" & @CRLF & _
" return this.node.ownerDocument.defaultView.getComputedStyle(this.node, type);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.cssInt = function(attribute) {" & @CRLF & _
" var value = parseInt(this.css(attribute), 10);" & @CRLF & _
" return (isNaN(value)) ? 0 : value; // borders in old IE are throwing 'medium' for demo.html" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.color = function(attribute) {" & @CRLF & _
" return this.colors[attribute] || (this.colors[attribute] = new Color(this.css(attribute)));" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.cssFloat = function(attribute) {" & @CRLF & _
" var value = parseFloat(this.css(attribute));" & @CRLF & _
" return (isNaN(value)) ? 0 : value;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.fontWeight = function() {" & @CRLF & _
" var weight = this.css("fontWeight");" & @CRLF & _
" switch(parseInt(weight, 10)){" & @CRLF & _
" case 401:" & @CRLF & _
" weight = "bold";" & @CRLF & _
" break;" & @CRLF & _
" case 400:" & @CRLF & _
" weight = "normal";" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
" return weight;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.parseClip = function() {" & @CRLF & _
" var matches = this.css('clip').match(this.CLIP);" & @CRLF & _
" if (matches) {" & @CRLF & _
" return {" & @CRLF & _
" top: parseInt(matches[1], 10)," & @CRLF & _
" right: parseInt(matches[2], 10)," & @CRLF & _
" bottom: parseInt(matches[3], 10)," & @CRLF & _
" left: parseInt(matches[4], 10)" & @CRLF & _
" };" & @CRLF & _
" }" & @CRLF & _
" return null;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.parseBackgroundImages = function() {" & @CRLF & _
" return this.backgroundImages || (this.backgroundImages = parseBackgrounds(this.css("backgroundImage")));" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.cssList = function(property, index) {" & @CRLF & _
" var value = (this.css(property) || '').split(',');" & @CRLF & _
" value = value[index || 0] || value[0] || 'auto';" & @CRLF & _
" value = value.trim().split(' ');" & @CRLF & _
" if (value.length === 1) {" & @CRLF & _
" value = [value[0], value[0]];" & @CRLF & _
" }" & @CRLF & _
" return value;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.parseBackgroundSize = function(bounds, image, index) {" & @CRLF & _
" var size = this.cssList("backgroundSize", index);" & @CRLF & _
" var width, height;" & @CRLF & _
"" & @CRLF & _
" if (isPercentage(size[0])) {" & @CRLF & _
" width = bounds.width * parseFloat(size[0]) / 100;" & @CRLF & _
" } else if (/contain|cover/.test(size[0])) {" & @CRLF & _
" var targetRatio = bounds.width / bounds.height, currentRatio = image.width / image.height;" & @CRLF & _
" return (targetRatio < currentRatio ^ size[0] === 'contain') ? {width: bounds.height * currentRatio, height: bounds.height} : {width: bounds.width, height: bounds.width / currentRatio};" & @CRLF & _
" } else {" & @CRLF & _
" width = parseInt(size[0], 10);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (size[0] === 'auto' && size[1] === 'auto') {" & @CRLF & _
" height = image.height;" & @CRLF & _
" } else if (size[1] === 'auto') {" & @CRLF & _
" height = width / image.width * image.height;" & @CRLF & _
" } else if (isPercentage(size[1])) {" & @CRLF & _
" height = bounds.height * parseFloat(size[1]) / 100;" & @CRLF & _
" } else {" & @CRLF & _
" height = parseInt(size[1], 10);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (size[0] === 'auto') {" & @CRLF & _
" width = height / image.height * image.width;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return {width: width, height: height};" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.parseBackgroundPosition = function(bounds, image, index, backgroundSize) {" & @CRLF & _
" var position = this.cssList('backgroundPosition', index);" & @CRLF & _
" var left, top;" & @CRLF & _
"" & @CRLF & _
" if (isPercentage(position[0])){" & @CRLF & _
" left = (bounds.width - (backgroundSize || image).width) * (parseFloat(position[0]) / 100);" & @CRLF & _
" } else {" & @CRLF & _
" left = parseInt(position[0], 10);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (position[1] === 'auto') {" & @CRLF & _
" top = left / image.width * image.height;" & @CRLF & _
" } else if (isPercentage(position[1])){" & @CRLF & _
" top = (bounds.height - (backgroundSize || image).height) * parseFloat(position[1]) / 100;" & @CRLF & _
" } else {" & @CRLF & _
" top = parseInt(position[1], 10);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (position[0] === 'auto') {" & @CRLF & _
" left = top / image.height * image.width;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return {left: left, top: top};" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.parseBackgroundRepeat = function(index) {" & @CRLF & _
" return this.cssList("backgroundRepeat", index)[0];" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.parseTextShadows = function() {" & @CRLF & _
" var textShadow = this.css("textShadow");" & @CRLF & _
" var results = [];" & @CRLF & _
"" & @CRLF & _
" if (textShadow && textShadow !== 'none') {" & @CRLF & _
" var shadows = textShadow.match(this.TEXT_SHADOW_PROPERTY);" & @CRLF & _
" for (var i = 0; shadows && (i < shadows.length); i++) {" & @CRLF & _
" var s = shadows[i].match(this.TEXT_SHADOW_VALUES);" & @CRLF & _
" results.push({" & @CRLF & _
" color: new Color(s[0])," & @CRLF & _
" offsetX: s[1] ? parseFloat(s[1].replace('px', '')) : 0," & @CRLF & _
" offsetY: s[2] ? parseFloat(s[2].replace('px', '')) : 0," & @CRLF & _
" blur: s[3] ? s[3].replace('px', '') : 0" & @CRLF & _
" });" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
" return results;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.parseTransform = function() {" & @CRLF & _
" if (!this.transformData) {" & @CRLF & _
" if (this.hasTransform()) {" & @CRLF & _
" var offset = this.parseBounds();" & @CRLF & _
" var origin = this.prefixedCss("transformOrigin").split(" ").map(removePx).map(asFloat);" & @CRLF & _
" origin[0] += offset.left;" & @CRLF & _
" origin[1] += offset.top;" & @CRLF & _
" this.transformData = {" & @CRLF & _
" origin: origin," & @CRLF & _
" matrix: this.parseTransformMatrix()" & @CRLF & _
" };" & @CRLF & _
" } else {" & @CRLF & _
" this.transformData = {" & @CRLF & _
" origin: [0, 0]," & @CRLF & _
" matrix: [1, 0, 0, 1, 0, 0]" & @CRLF & _
" };" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
" return this.transformData;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.parseTransformMatrix = function() {" & @CRLF & _
" if (!this.transformMatrix) {" & @CRLF & _
" var transform = this.prefixedCss("transform");" & @CRLF & _
" var matrix = transform ? parseMatrix(transform.match(this.MATRIX_PROPERTY)) : null;" & @CRLF & _
" this.transformMatrix = matrix ? matrix : [1, 0, 0, 1, 0, 0];" & @CRLF & _
" }" & @CRLF & _
" return this.transformMatrix;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.parseBounds = function() {" & @CRLF & _
" return this.bounds || (this.bounds = this.hasTransform() ? offsetBounds(this.node) : getBounds(this.node));" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.hasTransform = function() {" & @CRLF & _
" return this.parseTransformMatrix().join(",") !== "1,0,0,1,0,0" || (this.parent && this.parent.hasTransform());" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.getValue = function() {" & @CRLF & _
" var value = this.node.value || "";" & @CRLF & _
" if (this.node.tagName === "SELECT") {" & @CRLF & _
" value = selectionValue(this.node);" & @CRLF & _
" } else if (this.node.type === "password") {" & @CRLF & _
" value = Array(value.length + 1).join('\u2022'); // jshint ignore:line" & @CRLF & _
" }" & @CRLF & _
" return value.length === 0 ? (this.node.placeholder || "") : value;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeContainer.prototype.MATRIX_PROPERTY = /(matrix)\((.+)\)/;" & @CRLF & _
"NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g;" & @CRLF & _
"NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;" & @CRLF & _
"NodeContainer.prototype.CLIP = /^rect\((\d+)px,? (\d+)px,? (\d+)px,? (\d+)px\)$/;" & @CRLF & _
"" & @CRLF & _
"function selectionValue(node) {" & @CRLF & _
" var option = node.options[node.selectedIndex || 0];" & @CRLF & _
" return option ? (option.text || "") : "";" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function parseMatrix(match) {" & @CRLF & _
" if (match && match[1] === "matrix") {" & @CRLF & _
" return match[2].split(",").map(function(s) {" & @CRLF & _
" return parseFloat(s.trim());" & @CRLF & _
" });" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isPercentage(value) {" & @CRLF & _
" return value.toString().indexOf("%") !== -1;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function parseBackgrounds(backgroundImage) {" & @CRLF & _
" var whitespace = ' \r\n\t'," & @CRLF & _
" method, definition, prefix, prefix_i, block, results = []," & @CRLF & _
" mode = 0, numParen = 0, quote, args;" & @CRLF & _
" var appendResult = function() {" & @CRLF & _
" if(method) {" & @CRLF & _
" if (definition.substr(0, 1) === '"') {" & @CRLF & _
" definition = definition.substr(1, definition.length - 2);" & @CRLF & _
" }" & @CRLF & _
" if (definition) {" & @CRLF & _
" args.push(definition);" & @CRLF & _
" }" & @CRLF & _
" if (method.substr(0, 1) === '-' && (prefix_i = method.indexOf('-', 1 ) + 1) > 0) {" & @CRLF & _
" prefix = method.substr(0, prefix_i);" & @CRLF & _
" method = method.substr(prefix_i);" & @CRLF & _
" }" & @CRLF & _
" results.push({" & @CRLF & _
" prefix: prefix," & @CRLF & _
" method: method.toLowerCase()," & @CRLF & _
" value: block," & @CRLF & _
" args: args," & @CRLF & _
" image: null" & @CRLF & _
" });" & @CRLF & _
" }" & @CRLF & _
" args = [];" & @CRLF & _
" method = prefix = definition = block = '';" & @CRLF & _
" };" & @CRLF & _
" args = [];" & @CRLF & _
" method = prefix = definition = block = '';" & @CRLF & _
" backgroundImage.split("").forEach(function(c) {" & @CRLF & _
" if (mode === 0 && whitespace.indexOf(c) > -1) {" & @CRLF & _
" return;" & @CRLF & _
" }" & @CRLF & _
" switch(c) {" & @CRLF & _
" case '"':" & @CRLF & _
" if(!quote) {" & @CRLF & _
" quote = c;" & @CRLF & _
" } else if(quote === c) {" & @CRLF & _
" quote = null;" & @CRLF & _
" }" & @CRLF & _
" break;" & @CRLF & _
" case '(':" & @CRLF & _
" if(quote) {" & @CRLF & _
" break;" & @CRLF & _
" } else if(mode === 0) {" & @CRLF & _
" mode = 1;" & @CRLF & _
" block += c;" & @CRLF & _
" return;" & @CRLF & _
" } else {" & @CRLF & _
" numParen++;" & @CRLF & _
" }" & @CRLF & _
" break;" & @CRLF & _
" case ')':" & @CRLF & _
" if (quote) {" & @CRLF & _
" break;" & @CRLF & _
" } else if(mode === 1) {" & @CRLF & _
" if(numParen === 0) {" & @CRLF & _
" mode = 0;" & @CRLF & _
" block += c;" & @CRLF & _
" appendResult();" & @CRLF & _
" return;" & @CRLF & _
" } else {" & @CRLF & _
" numParen--;" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
" break;" & @CRLF & _
"" & @CRLF & _
" case ',':" & @CRLF & _
" if (quote) {" & @CRLF & _
" break;" & @CRLF & _
" } else if(mode === 0) {" & @CRLF & _
" appendResult();" & @CRLF & _
" return;" & @CRLF & _
" } else if (mode === 1) {" & @CRLF & _
" if (numParen === 0 && !method.match(/^url$/i)) {" & @CRLF & _
" args.push(definition);" & @CRLF & _
" definition = '';" & @CRLF & _
" block += c;" & @CRLF & _
" return;" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" block += c;" & @CRLF & _
" if (mode === 0) {" & @CRLF & _
" method += c;" & @CRLF & _
" } else {" & @CRLF & _
" definition += c;" & @CRLF & _
" }" & @CRLF & _
" });" & @CRLF & _
"" & @CRLF & _
" appendResult();" & @CRLF & _
" return results;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function removePx(str) {" & @CRLF & _
" return str.replace("px", "");" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function asFloat(str) {" & @CRLF & _
" return parseFloat(str);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getBounds(node) {" & @CRLF & _
" if (node.getBoundingClientRect) {" & @CRLF & _
" var clientRect = node.getBoundingClientRect();" & @CRLF & _
" var width = node.offsetWidth == null ? clientRect.width : node.offsetWidth;" & @CRLF & _
" return {" & @CRLF & _
" top: clientRect.top," & @CRLF & _
" bottom: clientRect.bottom || (clientRect.top + clientRect.height)," & @CRLF & _
" right: clientRect.left + width," & @CRLF & _
" left: clientRect.left," & @CRLF & _
" width: width," & @CRLF & _
" height: node.offsetHeight == null ? clientRect.height : node.offsetHeight" & @CRLF & _
" };" & @CRLF & _
" }" & @CRLF & _
" return {};" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function offsetBounds(node) {" & @CRLF & _
" var parent = node.offsetParent ? offsetBounds(node.offsetParent) : {top: 0, left: 0};" & @CRLF & _
"" & @CRLF & _
" return {" & @CRLF & _
" top: node.offsetTop + parent.top," & @CRLF & _
" bottom: node.offsetTop + node.offsetHeight + parent.top," & @CRLF & _
" right: node.offsetLeft + parent.left + node.offsetWidth," & @CRLF & _
" left: node.offsetLeft + parent.left," & @CRLF & _
" width: node.offsetWidth," & @CRLF & _
" height: node.offsetHeight" & @CRLF & _
" };" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function NodeParser(element, renderer, support, imageLoader, options) {" & @CRLF & _
" log("Starting NodeParser");" & @CRLF & _
" this.renderer = renderer;" & @CRLF & _
" this.options = options;" & @CRLF & _
" this.range = null;" & @CRLF & _
" this.support = support;" & @CRLF & _
" this.renderQueue = [];" & @CRLF & _
" this.stack = new StackingContext(true, 1, element.ownerDocument, null);" & @CRLF & _
" var parent = new NodeContainer(element, null);" & @CRLF & _
" if (options.background) {" & @CRLF & _
" renderer.rectangle(0, 0, renderer.width, renderer.height, new Color(options.background));" & @CRLF & _
" }" & @CRLF & _
" if (element === element.ownerDocument.documentElement) {" & @CRLF & _
" // http://www.w3.org/TR/css3-background/#special-backgrounds" & @CRLF & _
" var canvasBackground = new NodeContainer(parent.color('backgroundColor').isTransparent() ? element.ownerDocument.body : element.ownerDocument.documentElement, null);" & @CRLF & _
" renderer.rectangle(0, 0, renderer.width, renderer.height, canvasBackground.color('backgroundColor'));" & @CRLF & _
" }" & @CRLF & _
" parent.visibile = parent.isElementVisible();" & @CRLF & _
" this.createPseudoHideStyles(element.ownerDocument);" & @CRLF & _
" this.disableAnimations(element.ownerDocument);" & @CRLF & _
" this.nodes = flatten([parent].concat(this.getChildren(parent)).filter(function(container) {" & @CRLF & _
" return container.visible = container.isElementVisible();" & @CRLF & _
" }).map(this.getPseudoElements, this));" & @CRLF & _
" this.fontMetrics = new FontMetrics();" & @CRLF & _
" log("Fetched nodes, total:", this.nodes.length);" & @CRLF & _
" log("Calculate overflow clips");" & @CRLF & _
" this.calculateOverflowClips();" & @CRLF & _
" log("Start fetching images");" & @CRLF & _
" this.images = imageLoader.fetch(this.nodes.filter(isElement));" & @CRLF & _
" this.ready = this.images.ready.then(bind(function() {" & @CRLF & _
" log("Images loaded, starting parsing");" & @CRLF & _
" log("Creating stacking contexts");" & @CRLF & _
" this.createStackingContexts();" & @CRLF & _
" log("Sorting stacking contexts");" & @CRLF & _
" this.sortStackingContexts(this.stack);" & @CRLF & _
" this.parse(this.stack);" & @CRLF & _
" log("Render queue created with " + this.renderQueue.length + " items");" & @CRLF & _
" return new Promise(bind(function(resolve) {" & @CRLF & _
" if (!options.async) {" & @CRLF & _
" this.renderQueue.forEach(this.paint, this);" & @CRLF & _
" resolve();" & @CRLF & _
" } else if (typeof(options.async) === "function") {" & @CRLF & _
" options.async.call(this, this.renderQueue, resolve);" & @CRLF & _
" } else if (this.renderQueue.length > 0){" & @CRLF & _
" this.renderIndex = 0;" & @CRLF & _
" this.asyncRenderer(this.renderQueue, resolve);" & @CRLF & _
" } else {" & @CRLF & _
" resolve();" & @CRLF & _
" }" & @CRLF & _
" }, this));" & @CRLF & _
" }, this));" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.calculateOverflowClips = function() {" & @CRLF & _
" this.nodes.forEach(function(container) {" & @CRLF & _
" if (isElement(container)) {" & @CRLF & _
" if (isPseudoElement(container)) {" & @CRLF & _
" container.appendToDOM();" & @CRLF & _
" }" & @CRLF & _
" container.borders = this.parseBorders(container);" & @CRLF & _
" var clip = (container.css('overflow') === "hidden") ? [container.borders.clip] : [];" & @CRLF & _
" var cssClip = container.parseClip();" & @CRLF & _
" if (cssClip && ["absolute", "fixed"].indexOf(container.css('position')) !== -1) {" & @CRLF & _
" clip.push([["rect"," & @CRLF & _
" container.bounds.left + cssClip.left," & @CRLF & _
" container.bounds.top + cssClip.top," & @CRLF & _
" cssClip.right - cssClip.left," & @CRLF & _
" cssClip.bottom - cssClip.top" & @CRLF & _
" ]]);" & @CRLF & _
" }" & @CRLF & _
" container.clip = hasParentClip(container) ? container.parent.clip.concat(clip) : clip;" & @CRLF & _
" container.backgroundClip = (container.css('overflow') !== "hidden") ? container.clip.concat([container.borders.clip]) : container.clip;" & @CRLF & _
" if (isPseudoElement(container)) {" & @CRLF & _
" container.cleanDOM();" & @CRLF & _
" }" & @CRLF & _
" } else if (isTextNode(container)) {" & @CRLF & _
" container.clip = hasParentClip(container) ? container.parent.clip : [];" & @CRLF & _
" }" & @CRLF & _
" if (!isPseudoElement(container)) {" & @CRLF & _
" container.bounds = null;" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function hasParentClip(container) {" & @CRLF & _
" return container.parent && container.parent.clip.length;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.asyncRenderer = function(queue, resolve, asyncTimer) {" & @CRLF & _
" asyncTimer = asyncTimer || Date.now();" & @CRLF & _
" this.paint(queue[this.renderIndex++]);" & @CRLF & _
" if (queue.length === this.renderIndex) {" & @CRLF & _
" resolve();" & @CRLF & _
" } else if (asyncTimer + 20 > Date.now()) {" & @CRLF & _
" this.asyncRenderer(queue, resolve, asyncTimer);" & @CRLF & _
" } else {" & @CRLF & _
" setTimeout(bind(function() {" & @CRLF & _
" this.asyncRenderer(queue, resolve);" & @CRLF & _
" }, this), 0);" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.createPseudoHideStyles = function(document) {" & @CRLF & _
" this.createStyles(document, '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + ':before { content: "" !important; display: none !important; }' +" & @CRLF & _
" '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER + ':after { content: "" !important; display: none !important; }');" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.disableAnimations = function(document) {" & @CRLF & _
" this.createStyles(document, '* { -webkit-animation: none !important; -moz-animation: none !important; -o-animation: none !important; animation: none !important; ' +" & @CRLF & _
" '-webkit-transition: none !important; -moz-transition: none !important; -o-transition: none !important; transition: none !important;}');" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.createStyles = function(document, styles) {" & @CRLF & _
" var hidePseudoElements = document.createElement('style');" & @CRLF & _
" hidePseudoElements.innerHTML = styles;" & @CRLF & _
" document.body.appendChild(hidePseudoElements);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.getPseudoElements = function(container) {" & @CRLF & _
" var nodes = [[container]];" & @CRLF & _
" if (container.node.nodeType === Node.ELEMENT_NODE) {" & @CRLF & _
" var before = this.getPseudoElement(container, ":before");" & @CRLF & _
" var after = this.getPseudoElement(container, ":after");" & @CRLF & _
"" & @CRLF & _
" if (before) {" & @CRLF & _
" nodes.push(before);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (after) {" & @CRLF & _
" nodes.push(after);" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
" return flatten(nodes);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function toCamelCase(str) {" & @CRLF & _
" return str.replace(/(\-[a-z])/g, function(match){" & @CRLF & _
" return match.toUpperCase().replace('-','');" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.getPseudoElement = function(container, type) {" & @CRLF & _
" var style = container.computedStyle(type);" & @CRLF & _
" if(!style || !style.content || style.content === "none" || style.content === "-moz-alt-content" || style.display === "none") {" & @CRLF & _
" return null;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" var content = stripQuotes(style.content);" & @CRLF & _
" var isImage = content.substr(0, 3) === 'url';" & @CRLF & _
" var pseudoNode = document.createElement(isImage ? 'img' : 'html2canvaspseudoelement');" & @CRLF & _
" var pseudoContainer = new PseudoElementContainer(pseudoNode, container, type);" & @CRLF & _
"" & @CRLF & _
" for (var i = style.length-1; i >= 0; i--) {" & @CRLF & _
" var property = toCamelCase(style.item(i));" & @CRLF & _
" pseudoNode.style[property] = style[property];" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" pseudoNode.className = PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + " " + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER;" & @CRLF & _
"" & @CRLF & _
" if (isImage) {" & @CRLF & _
" pseudoNode.src = parseBackgrounds(content)[0].args[0];" & @CRLF & _
" return [pseudoContainer];" & @CRLF & _
" } else {" & @CRLF & _
" var text = document.createTextNode(content);" & @CRLF & _
" pseudoNode.appendChild(text);" & @CRLF & _
" return [pseudoContainer, new TextContainer(text, pseudoContainer)];" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.getChildren = function(parentContainer) {" & @CRLF & _
" return flatten([].filter.call(parentContainer.node.childNodes, renderableNode).map(function(node) {" & @CRLF & _
" var container = [node.nodeType === Node.TEXT_NODE ? new TextContainer(node, parentContainer) : new NodeContainer(node, parentContainer)].filter(nonIgnoredElement);" & @CRLF & _
" return node.nodeType === Node.ELEMENT_NODE && container.length && node.tagName !== "TEXTAREA" ? (container[0].isElementVisible() ? container.concat(this.getChildren(container[0])) : []) : container;" & @CRLF & _
" }, this));" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.newStackingContext = function(container, hasOwnStacking) {" & @CRLF & _
" var stack = new StackingContext(hasOwnStacking, container.getOpacity(), container.node, container.parent);" & @CRLF & _
" container.cloneTo(stack);" & @CRLF & _
" var parentStack = hasOwnStacking ? stack.getParentStack(this) : stack.parent.stack;" & @CRLF & _
" parentStack.contexts.push(stack);" & @CRLF & _
" container.stack = stack;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.createStackingContexts = function() {" & @CRLF & _
" this.nodes.forEach(function(container) {" & @CRLF & _
" if (isElement(container) && (this.isRootElement(container) || hasOpacity(container) || isPositionedForStacking(container) || this.isBodyWithTransparentRoot(container) || container.hasTransform())) {" & @CRLF & _
" this.newStackingContext(container, true);" & @CRLF & _
" } else if (isElement(container) && ((isPositioned(container) && zIndex0(container)) || isInlineBlock(container) || isFloating(container))) {" & @CRLF & _
" this.newStackingContext(container, false);" & @CRLF & _
" } else {" & @CRLF & _
" container.assignStack(container.parent.stack);" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.isBodyWithTransparentRoot = function(container) {" & @CRLF & _
" return container.node.nodeName === "BODY" && container.parent.color('backgroundColor').isTransparent();" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.isRootElement = function(container) {" & @CRLF & _
" return container.parent === null;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.sortStackingContexts = function(stack) {" & @CRLF & _
" stack.contexts.sort(zIndexSort(stack.contexts.slice(0)));" & @CRLF & _
" stack.contexts.forEach(this.sortStackingContexts, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.parseTextBounds = function(container) {" & @CRLF & _
" return function(text, index, textList) {" & @CRLF & _
" if (container.parent.css("textDecoration").substr(0, 4) !== "none" || text.trim().length !== 0) {" & @CRLF & _
" if (this.support.rangeBounds && !container.parent.hasTransform()) {" & @CRLF & _
" var offset = textList.slice(0, index).join("").length;" & @CRLF & _
" return this.getRangeBounds(container.node, offset, text.length);" & @CRLF & _
" } else if (container.node && typeof(container.node.data) === "string") {" & @CRLF & _
" var replacementNode = container.node.splitText(text.length);" & @CRLF & _
" var bounds = this.getWrapperBounds(container.node, container.parent.hasTransform());" & @CRLF & _
" container.node = replacementNode;" & @CRLF & _
" return bounds;" & @CRLF & _
" }" & @CRLF & _
" } else if(!this.support.rangeBounds || container.parent.hasTransform()){" & @CRLF & _
" container.node = container.node.splitText(text.length);" & @CRLF & _
" }" & @CRLF & _
" return {};" & @CRLF & _
" };" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.getWrapperBounds = function(node, transform) {" & @CRLF & _
" var wrapper = node.ownerDocument.createElement('html2canvaswrapper');" & @CRLF & _
" var parent = node.parentNode," & @CRLF & _
" backupText = node.cloneNode(true);" & @CRLF & _
"" & @CRLF & _
" wrapper.appendChild(node.cloneNode(true));" & @CRLF & _
" parent.replaceChild(wrapper, node);" & @CRLF & _
" var bounds = transform ? offsetBounds(wrapper) : getBounds(wrapper);" & @CRLF & _
" parent.replaceChild(backupText, wrapper);" & @CRLF & _
" return bounds;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.getRangeBounds = function(node, offset, length) {" & @CRLF & _
" var range = this.range || (this.range = node.ownerDocument.createRange());" & @CRLF & _
" range.setStart(node, offset);" & @CRLF & _
" range.setEnd(node, offset + length);" & @CRLF & _
" return range.getBoundingClientRect();" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function ClearTransform() {}" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.parse = function(stack) {" & @CRLF & _
" // http://www.w3.org/TR/CSS21/visuren.html#z-index" & @CRLF & _
" var negativeZindex = stack.contexts.filter(negativeZIndex); // 2. the child stacking contexts with negative stack levels (most negative first)." & @CRLF & _
" var descendantElements = stack.children.filter(isElement);" & @CRLF & _
" var descendantNonFloats = descendantElements.filter(not(isFloating));" & @CRLF & _
" var nonInlineNonPositionedDescendants = descendantNonFloats.filter(not(isPositioned)).filter(not(inlineLevel)); // 3 the in-flow, non-inline-level, non-positioned descendants." & @CRLF & _
" var nonPositionedFloats = descendantElements.filter(not(isPositioned)).filter(isFloating); // 4. the non-positioned floats." & @CRLF & _
" var inFlow = descendantNonFloats.filter(not(isPositioned)).filter(inlineLevel); // 5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks." & @CRLF & _
" var stackLevel0 = stack.contexts.concat(descendantNonFloats.filter(isPositioned)).filter(zIndex0); // 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0." & @CRLF & _
" var text = stack.children.filter(isTextNode).filter(hasText);" & @CRLF & _
" var positiveZindex = stack.contexts.filter(positiveZIndex); // 7. the child stacking contexts with positive stack levels (least positive first)." & @CRLF & _
" negativeZindex.concat(nonInlineNonPositionedDescendants).concat(nonPositionedFloats)" & @CRLF & _
" .concat(inFlow).concat(stackLevel0).concat(text).concat(positiveZindex).forEach(function(container) {" & @CRLF & _
" this.renderQueue.push(container);" & @CRLF & _
" if (isStackingContext(container)) {" & @CRLF & _
" this.parse(container);" & @CRLF & _
" this.renderQueue.push(new ClearTransform());" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.paint = function(container) {" & @CRLF & _
" try {" & @CRLF & _
" if (container instanceof ClearTransform) {" & @CRLF & _
" this.renderer.ctx.restore();" & @CRLF & _
" } else if (isTextNode(container)) {" & @CRLF & _
" if (isPseudoElement(container.parent)) {" & @CRLF & _
" container.parent.appendToDOM();" & @CRLF & _
" }" & @CRLF & _
" this.paintText(container);" & @CRLF & _
" if (isPseudoElement(container.parent)) {" & @CRLF & _
" container.parent.cleanDOM();" & @CRLF & _
" }" & @CRLF & _
" } else {" & @CRLF & _
" this.paintNode(container);" & @CRLF & _
" }" & @CRLF & _
" } catch(e) {" & @CRLF & _
" log(e);" & @CRLF & _
" if (this.options.strict) {" & @CRLF & _
" throw e;" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.paintNode = function(container) {" & @CRLF & _
" if (isStackingContext(container)) {" & @CRLF & _
" this.renderer.setOpacity(container.opacity);" & @CRLF & _
" this.renderer.ctx.save();" & @CRLF & _
" if (container.hasTransform()) {" & @CRLF & _
" this.renderer.setTransform(container.parseTransform());" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (container.node.nodeName === "INPUT" && container.node.type === "checkbox") {" & @CRLF & _
" this.paintCheckbox(container);" & @CRLF & _
" } else if (container.node.nodeName === "INPUT" && container.node.type === "radio") {" & @CRLF & _
" this.paintRadio(container);" & @CRLF & _
" } else {" & @CRLF & _
" this.paintElement(container);" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.paintElement = function(container) {" & @CRLF & _
" var bounds = container.parseBounds();" & @CRLF & _
" this.renderer.clip(container.backgroundClip, function() {" & @CRLF & _
" this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth));" & @CRLF & _
" }, this);" & @CRLF & _
"" & @CRLF & _
" this.renderer.clip(container.clip, function() {" & @CRLF & _
" this.renderer.renderBorders(container.borders.borders);" & @CRLF & _
" }, this);" & @CRLF & _
"" & @CRLF & _
" this.renderer.clip(container.backgroundClip, function() {" & @CRLF & _
" switch (container.node.nodeName) {" & @CRLF & _
" case "svg":" & @CRLF & _
" case "IFRAME":" & @CRLF & _
" var imgContainer = this.images.get(container.node);" & @CRLF & _
" if (imgContainer) {" & @CRLF & _
" this.renderer.renderImage(container, bounds, container.borders, imgContainer);" & @CRLF & _
" } else {" & @CRLF & _
" log("Error loading <" + container.node.nodeName + ">", container.node);" & @CRLF & _
" }" & @CRLF & _
" break;" & @CRLF & _
" case "IMG":" & @CRLF & _
" var imageContainer = this.images.get(container.node.src);" & @CRLF & _
" if (imageContainer) {" & @CRLF & _
" this.renderer.renderImage(container, bounds, container.borders, imageContainer);" & @CRLF & _
" } else {" & @CRLF & _
" log("Error loading <img>", container.node.src);" & @CRLF & _
" }" & @CRLF & _
" break;" & @CRLF & _
" case "CANVAS":" & @CRLF & _
" this.renderer.renderImage(container, bounds, container.borders, {image: container.node});" & @CRLF & _
" break;" & @CRLF & _
" case "SELECT":" & @CRLF & _
" case "INPUT":" & @CRLF & _
" case "TEXTAREA":" & @CRLF & _
" this.paintFormValue(container);" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.paintCheckbox = function(container) {" & @CRLF & _
" var b = container.parseBounds();" & @CRLF & _
"" & @CRLF & _
" var size = Math.min(b.width, b.height);" & @CRLF & _
" var bounds = {width: size - 1, height: size - 1, top: b.top, left: b.left};" & @CRLF & _
" var r = [3, 3];" & @CRLF & _
" var radius = [r, r, r, r];" & @CRLF & _
" var borders = [1,1,1,1].map(function(w) {" & @CRLF & _
" return {color: new Color('#A5A5A5'), width: w};" & @CRLF & _
" });" & @CRLF & _
"" & @CRLF & _
" var borderPoints = calculateCurvePoints(bounds, radius, borders);" & @CRLF & _
"" & @CRLF & _
" this.renderer.clip(container.backgroundClip, function() {" & @CRLF & _
" this.renderer.rectangle(bounds.left + 1, bounds.top + 1, bounds.width - 2, bounds.height - 2, new Color("#DEDEDE"));" & @CRLF & _
" this.renderer.renderBorders(calculateBorders(borders, bounds, borderPoints, radius));" & @CRLF & _
" if (container.node.checked) {" & @CRLF & _
" this.renderer.font(new Color('#424242'), 'normal', 'normal', 'bold', (size - 3) + "px", 'arial');" & @CRLF & _
" this.renderer.text("\u2714", bounds.left + size / 6, bounds.top + size - 1);" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.paintRadio = function(container) {" & @CRLF & _
" var bounds = container.parseBounds();" & @CRLF & _
"" & @CRLF & _
" var size = Math.min(bounds.width, bounds.height) - 2;" & @CRLF & _
"" & @CRLF & _
" this.renderer.clip(container.backgroundClip, function() {" & @CRLF & _
" this.renderer.circleStroke(bounds.left + 1, bounds.top + 1, size, new Color('#DEDEDE'), 1, new Color('#A5A5A5'));" & @CRLF & _
" if (container.node.checked) {" & @CRLF & _
" this.renderer.circle(Math.ceil(bounds.left + size / 4) + 1, Math.ceil(bounds.top + size / 4) + 1, Math.floor(size / 2), new Color('#424242'));" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.paintFormValue = function(container) {" & @CRLF & _
" var value = container.getValue();" & @CRLF & _
" if (value.length > 0) {" & @CRLF & _
" var document = container.node.ownerDocument;" & @CRLF & _
" var wrapper = document.createElement('html2canvaswrapper');" & @CRLF & _
" var properties = ['lineHeight', 'textAlign', 'fontFamily', 'fontWeight', 'fontSize', 'color'," & @CRLF & _
" 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom'," & @CRLF & _
" 'width', 'height', 'borderLeftStyle', 'borderTopStyle', 'borderLeftWidth', 'borderTopWidth'," & @CRLF & _
" 'boxSizing', 'whiteSpace', 'wordWrap'];" & @CRLF & _
"" & @CRLF & _
" properties.forEach(function(property) {" & @CRLF & _
" try {" & @CRLF & _
" wrapper.style[property] = container.css(property);" & @CRLF & _
" } catch(e) {" & @CRLF & _
" // Older IE has issues with "border"" & @CRLF & _
" log("html2canvas: Parse: Exception caught in renderFormValue: " + e.message);" & @CRLF & _
" }" & @CRLF & _
" });" & @CRLF & _
" var bounds = container.parseBounds();" & @CRLF & _
" wrapper.style.position = "fixed";" & @CRLF & _
" wrapper.style.left = bounds.left + "px";" & @CRLF & _
" wrapper.style.top = bounds.top + "px";" & @CRLF & _
" wrapper.textContent = value;" & @CRLF & _
" document.body.appendChild(wrapper);" & @CRLF & _
" this.paintText(new TextContainer(wrapper.firstChild, container));" & @CRLF & _
" document.body.removeChild(wrapper);" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.paintText = function(container) {" & @CRLF & _
" container.applyTextTransform();" & @CRLF & _
" var characters = window.html2canvas.punycode.ucs2.decode(container.node.data);" & @CRLF & _
" var textList = (!this.options.letterRendering || noLetterSpacing(container)) && !hasUnicode(container.node.data) ? getWords(characters) : characters.map(function(character) {" & @CRLF & _
" return window.html2canvas.punycode.ucs2.encode([character]);" & @CRLF & _
" });" & @CRLF & _
"" & @CRLF & _
" var weight = container.parent.fontWeight();" & @CRLF & _
" var size = container.parent.css('fontSize');" & @CRLF & _
" var family = container.parent.css('fontFamily');" & @CRLF & _
" var shadows = container.parent.parseTextShadows();" & @CRLF & _
"" & @CRLF & _
" this.renderer.font(container.parent.color('color'), container.parent.css('fontStyle'), container.parent.css('fontVariant'), weight, size, family);" & @CRLF & _
" if (shadows.length) {" & @CRLF & _
" // TODO: support multiple text shadows" & @CRLF & _
" this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur);" & @CRLF & _
" } else {" & @CRLF & _
" this.renderer.clearShadow();" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" this.renderer.clip(container.parent.clip, function() {" & @CRLF & _
" textList.map(this.parseTextBounds(container), this).forEach(function(bounds, index) {" & @CRLF & _
" if (bounds) {" & @CRLF & _
" this.renderer.text(textList[index], bounds.left, bounds.bottom);" & @CRLF & _
" this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
" }, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) {" & @CRLF & _
" switch(container.css("textDecoration").split(" ")[0]) {" & @CRLF & _
" case "underline":" & @CRLF & _
" // Draws a line at the baseline of the font" & @CRLF & _
" // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size" & @CRLF & _
" this.renderer.rectangle(bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, container.color("color"));" & @CRLF & _
" break;" & @CRLF & _
" case "overline":" & @CRLF & _
" this.renderer.rectangle(bounds.left, Math.round(bounds.top), bounds.width, 1, container.color("color"));" & @CRLF & _
" break;" & @CRLF & _
" case "line-through":" & @CRLF & _
" // TODO try and find exact position for line-through" & @CRLF & _
" this.renderer.rectangle(bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, container.color("color"));" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"var borderColorTransforms = {" & @CRLF & _
" inset: [" & @CRLF & _
" ["darken", 0.60]," & @CRLF & _
" ["darken", 0.10]," & @CRLF & _
" ["darken", 0.10]," & @CRLF & _
" ["darken", 0.60]" & @CRLF & _
" ]" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.parseBorders = function(container) {" & @CRLF & _
" var nodeBounds = container.parseBounds();" & @CRLF & _
" var radius = getBorderRadiusData(container);" & @CRLF & _
" var borders = ["Top", "Right", "Bottom", "Left"].map(function(side, index) {" & @CRLF & _
" var style = container.css('border' + side + 'Style');" & @CRLF & _
" var color = container.color('border' + side + 'Color');" & @CRLF & _
" if (style === "inset" && color.isBlack()) {" & @CRLF & _
" color = new Color([255, 255, 255, color.a]); // this is wrong, but" & @CRLF & _
" }" & @CRLF & _
" var colorTransform = borderColorTransforms[style] ? borderColorTransforms[style][index] : null;" & @CRLF & _
" return {" & @CRLF & _
" width: container.cssInt('border' + side + 'Width')," & @CRLF & _
" color: colorTransform ? color[colorTransform[0]](colorTransform[1]) : color," & @CRLF & _
" args: null" & @CRLF & _
" };" & @CRLF & _
" });" & @CRLF & _
" var borderPoints = calculateCurvePoints(nodeBounds, radius, borders);" & @CRLF & _
"" & @CRLF & _
" return {" & @CRLF & _
" clip: this.parseBackgroundClip(container, borderPoints, borders, radius, nodeBounds)," & @CRLF & _
" borders: calculateBorders(borders, nodeBounds, borderPoints, radius)" & @CRLF & _
" };" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function calculateBorders(borders, nodeBounds, borderPoints, radius) {" & @CRLF & _
" return borders.map(function(border, borderSide) {" & @CRLF & _
" if (border.width > 0) {" & @CRLF & _
" var bx = nodeBounds.left;" & @CRLF & _
" var by = nodeBounds.top;" & @CRLF & _
" var bw = nodeBounds.width;" & @CRLF & _
" var bh = nodeBounds.height - (borders[2].width);" & @CRLF & _
"" & @CRLF & _
" switch(borderSide) {" & @CRLF & _
" case 0:" & @CRLF & _
" // top border" & @CRLF & _
" bh = borders[0].width;" & @CRLF & _
" border.args = drawSide({" & @CRLF & _
" c1: [bx, by]," & @CRLF & _
" c2: [bx + bw, by]," & @CRLF & _
" c3: [bx + bw - borders[1].width, by + bh]," & @CRLF & _
" c4: [bx + borders[3].width, by + bh]" & @CRLF & _
" }, radius[0], radius[1]," & @CRLF & _
" borderPoints.topLeftOuter, borderPoints.topLeftInner, borderPoints.topRightOuter, borderPoints.topRightInner);" & @CRLF & _
" break;" & @CRLF & _
" case 1:" & @CRLF & _
" // right border" & @CRLF & _
" bx = nodeBounds.left + nodeBounds.width - (borders[1].width);" & @CRLF & _
" bw = borders[1].width;" & @CRLF & _
"" & @CRLF & _
" border.args = drawSide({" & @CRLF & _
" c1: [bx + bw, by]," & @CRLF & _
" c2: [bx + bw, by + bh + borders[2].width]," & @CRLF & _
" c3: [bx, by + bh]," & @CRLF & _
" c4: [bx, by + borders[0].width]" & @CRLF & _
" }, radius[1], radius[2]," & @CRLF & _
" borderPoints.topRightOuter, borderPoints.topRightInner, borderPoints.bottomRightOuter, borderPoints.bottomRightInner);" & @CRLF & _
" break;" & @CRLF & _
" case 2:" & @CRLF & _
" // bottom border" & @CRLF & _
" by = (by + nodeBounds.height) - (borders[2].width);" & @CRLF & _
" bh = borders[2].width;" & @CRLF & _
" border.args = drawSide({" & @CRLF & _
" c1: [bx + bw, by + bh]," & @CRLF & _
" c2: [bx, by + bh]," & @CRLF & _
" c3: [bx + borders[3].width, by]," & @CRLF & _
" c4: [bx + bw - borders[3].width, by]" & @CRLF & _
" }, radius[2], radius[3]," & @CRLF & _
" borderPoints.bottomRightOuter, borderPoints.bottomRightInner, borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner);" & @CRLF & _
" break;" & @CRLF & _
" case 3:" & @CRLF & _
" // left border" & @CRLF & _
" bw = borders[3].width;" & @CRLF & _
" border.args = drawSide({" & @CRLF & _
" c1: [bx, by + bh + borders[2].width]," & @CRLF & _
" c2: [bx, by]," & @CRLF & _
" c3: [bx + bw, by + borders[0].width]," & @CRLF & _
" c4: [bx + bw, by + bh]" & @CRLF & _
" }, radius[3], radius[0]," & @CRLF & _
" borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner, borderPoints.topLeftOuter, borderPoints.topLeftInner);" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
" return border;" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"NodeParser.prototype.parseBackgroundClip = function(container, borderPoints, borders, radius, bounds) {" & @CRLF & _
" var backgroundClip = container.css('backgroundClip')," & @CRLF & _
" borderArgs = [];" & @CRLF & _
"" & @CRLF & _
" switch(backgroundClip) {" & @CRLF & _
" case "content-box":" & @CRLF & _
" case "padding-box":" & @CRLF & _
" parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftInner, borderPoints.topRightInner, bounds.left + borders[3].width, bounds.top + borders[0].width);" & @CRLF & _
" parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightInner, borderPoints.bottomRightInner, bounds.left + bounds.width - borders[1].width, bounds.top + borders[0].width);" & @CRLF & _
" parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightInner, borderPoints.bottomLeftInner, bounds.left + bounds.width - borders[1].width, bounds.top + bounds.height - borders[2].width);" & @CRLF & _
" parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftInner, borderPoints.topLeftInner, bounds.left + borders[3].width, bounds.top + bounds.height - borders[2].width);" & @CRLF & _
" break;" & @CRLF & _
"" & @CRLF & _
" default:" & @CRLF & _
" parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftOuter, borderPoints.topRightOuter, bounds.left, bounds.top);" & @CRLF & _
" parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightOuter, borderPoints.bottomRightOuter, bounds.left + bounds.width, bounds.top);" & @CRLF & _
" parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightOuter, borderPoints.bottomLeftOuter, bounds.left + bounds.width, bounds.top + bounds.height);" & @CRLF & _
" parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftOuter, borderPoints.topLeftOuter, bounds.left, bounds.top + bounds.height);" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return borderArgs;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function getCurvePoints(x, y, r1, r2) {" & @CRLF & _
" var kappa = 4 * ((Math.sqrt(2) - 1) / 3);" & @CRLF & _
" var ox = (r1) * kappa, // control point offset horizontal" & @CRLF & _
" oy = (r2) * kappa, // control point offset vertical" & @CRLF & _
" xm = x + r1, // x-middle" & @CRLF & _
" ym = y + r2; // y-middle" & @CRLF & _
" return {" & @CRLF & _
" topLeft: bezierCurve({x: x, y: ym}, {x: x, y: ym - oy}, {x: xm - ox, y: y}, {x: xm, y: y})," & @CRLF & _
" topRight: bezierCurve({x: x, y: y}, {x: x + ox,y: y}, {x: xm, y: ym - oy}, {x: xm, y: ym})," & @CRLF & _
" bottomRight: bezierCurve({x: xm, y: y}, {x: xm, y: y + oy}, {x: x + ox, y: ym}, {x: x, y: ym})," & @CRLF & _
" bottomLeft: bezierCurve({x: xm, y: ym}, {x: xm - ox, y: ym}, {x: x, y: y + oy}, {x: x, y:y})" & @CRLF & _
" };" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function calculateCurvePoints(bounds, borderRadius, borders) {" & @CRLF & _
" var x = bounds.left," & @CRLF & _
" y = bounds.top," & @CRLF & _
" width = bounds.width," & @CRLF & _
" height = bounds.height," & @CRLF & _
"" & @CRLF & _
" tlh = borderRadius[0][0]," & @CRLF & _
" tlv = borderRadius[0][1]," & @CRLF & _
" trh = borderRadius[1][0]," & @CRLF & _
" trv = borderRadius[1][1]," & @CRLF & _
" brh = borderRadius[2][0]," & @CRLF & _
" brv = borderRadius[2][1]," & @CRLF & _
" blh = borderRadius[3][0]," & @CRLF & _
" blv = borderRadius[3][1];" & @CRLF & _
"" & @CRLF & _
" var topWidth = width - trh," & @CRLF & _
" rightHeight = height - brv," & @CRLF & _
" bottomWidth = width - brh," & @CRLF & _
" leftHeight = height - blv;" & @CRLF & _
"" & @CRLF & _
" return {" & @CRLF & _
" topLeftOuter: getCurvePoints(x, y, tlh, tlv).topLeft.subdivide(0.5)," & @CRLF & _
" topLeftInner: getCurvePoints(x + borders[3].width, y + borders[0].width, Math.max(0, tlh - borders[3].width), Math.max(0, tlv - borders[0].width)).topLeft.subdivide(0.5)," & @CRLF & _
" topRightOuter: getCurvePoints(x + topWidth, y, trh, trv).topRight.subdivide(0.5)," & @CRLF & _
" topRightInner: getCurvePoints(x + Math.min(topWidth, width + borders[3].width), y + borders[0].width, (topWidth > width + borders[3].width) ? 0 :trh - borders[3].width, trv - borders[0].width).topRight.subdivide(0.5)," & @CRLF & _
" bottomRightOuter: getCurvePoints(x + bottomWidth, y + rightHeight, brh, brv).bottomRight.subdivide(0.5)," & @CRLF & _
" bottomRightInner: getCurvePoints(x + Math.min(bottomWidth, width - borders[3].width), y + Math.min(rightHeight, height + borders[0].width), Math.max(0, brh - borders[1].width), brv - borders[2].width).bottomRight.subdivide(0.5)," & @CRLF & _
" bottomLeftOuter: getCurvePoints(x, y + leftHeight, blh, blv).bottomLeft.subdivide(0.5)," & @CRLF & _
" bottomLeftInner: getCurvePoints(x + borders[3].width, y + leftHeight, Math.max(0, blh - borders[3].width), blv - borders[2].width).bottomLeft.subdivide(0.5)" & @CRLF & _
" };" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function bezierCurve(start, startControl, endControl, end) {" & @CRLF & _
" var lerp = function (a, b, t) {" & @CRLF & _
" return {" & @CRLF & _
" x: a.x + (b.x - a.x) * t," & @CRLF & _
" y: a.y + (b.y - a.y) * t" & @CRLF & _
" };" & @CRLF & _
" };" & @CRLF & _
"" & @CRLF & _
" return {" & @CRLF & _
" start: start," & @CRLF & _
" startControl: startControl," & @CRLF & _
" endControl: endControl," & @CRLF & _
" end: end," & @CRLF & _
" subdivide: function(t) {" & @CRLF & _
" var ab = lerp(start, startControl, t)," & @CRLF & _
" bc = lerp(startControl, endControl, t)," & @CRLF & _
" cd = lerp(endControl, end, t)," & @CRLF & _
" abbc = lerp(ab, bc, t)," & @CRLF & _
" bccd = lerp(bc, cd, t)," & @CRLF & _
" dest = lerp(abbc, bccd, t);" & @CRLF & _
" return [bezierCurve(start, ab, abbc, dest), bezierCurve(dest, bccd, cd, end)];" & @CRLF & _
" }," & @CRLF & _
" curveTo: function(borderArgs) {" & @CRLF & _
" borderArgs.push(["bezierCurve", startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y]);" & @CRLF & _
" }," & @CRLF & _
" curveToReversed: function(borderArgs) {" & @CRLF & _
" borderArgs.push(["bezierCurve", endControl.x, endControl.y, startControl.x, startControl.y, start.x, start.y]);" & @CRLF & _
" }" & @CRLF & _
" };" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function drawSide(borderData, radius1, radius2, outer1, inner1, outer2, inner2) {" & @CRLF & _
" var borderArgs = [];" & @CRLF & _
"" & @CRLF & _
" if (radius1[0] > 0 || radius1[1] > 0) {" & @CRLF & _
" borderArgs.push(["line", outer1[1].start.x, outer1[1].start.y]);" & @CRLF & _
" outer1[1].curveTo(borderArgs);" & @CRLF & _
" } else {" & @CRLF & _
" borderArgs.push([ "line", borderData.c1[0], borderData.c1[1]]);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (radius2[0] > 0 || radius2[1] > 0) {" & @CRLF & _
" borderArgs.push(["line", outer2[0].start.x, outer2[0].start.y]);" & @CRLF & _
" outer2[0].curveTo(borderArgs);" & @CRLF & _
" borderArgs.push(["line", inner2[0].end.x, inner2[0].end.y]);" & @CRLF & _
" inner2[0].curveToReversed(borderArgs);" & @CRLF & _
" } else {" & @CRLF & _
" borderArgs.push(["line", borderData.c2[0], borderData.c2[1]]);" & @CRLF & _
" borderArgs.push(["line", borderData.c3[0], borderData.c3[1]]);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (radius1[0] > 0 || radius1[1] > 0) {" & @CRLF & _
" borderArgs.push(["line", inner1[1].end.x, inner1[1].end.y]);" & @CRLF & _
" inner1[1].curveToReversed(borderArgs);" & @CRLF & _
" } else {" & @CRLF & _
" borderArgs.push(["line", borderData.c4[0], borderData.c4[1]]);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return borderArgs;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function parseCorner(borderArgs, radius1, radius2, corner1, corner2, x, y) {" & @CRLF & _
" if (radius1[0] > 0 || radius1[1] > 0) {" & @CRLF & _
" borderArgs.push(["line", corner1[0].start.x, corner1[0].start.y]);" & @CRLF & _
" corner1[0].curveTo(borderArgs);" & @CRLF & _
" corner1[1].curveTo(borderArgs);" & @CRLF & _
" } else {" & @CRLF & _
" borderArgs.push(["line", x, y]);" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (radius2[0] > 0 || radius2[1] > 0) {" & @CRLF & _
" borderArgs.push(["line", corner2[0].start.x, corner2[0].start.y]);" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function negativeZIndex(container) {" & @CRLF & _
" return container.cssInt("zIndex") < 0;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function positiveZIndex(container) {" & @CRLF & _
" return container.cssInt("zIndex") > 0;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function zIndex0(container) {" & @CRLF & _
" return container.cssInt("zIndex") === 0;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function inlineLevel(container) {" & @CRLF & _
" return ["inline", "inline-block", "inline-table"].indexOf(container.css("display")) !== -1;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isStackingContext(container) {" & @CRLF & _
" return (container instanceof StackingContext);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function hasText(container) {" & @CRLF & _
" return container.node.data.trim().length > 0;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function noLetterSpacing(container) {" & @CRLF & _
" return (/^(normal|none|0px)$/.test(container.parent.css("letterSpacing")));" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getBorderRadiusData(container) {" & @CRLF & _
" return ["TopLeft", "TopRight", "BottomRight", "BottomLeft"].map(function(side) {" & @CRLF & _
" var value = container.css('border' + side + 'Radius');" & @CRLF & _
" var arr = value.split(" ");" & @CRLF & _
" if (arr.length <= 1) {" & @CRLF & _
" arr[1] = arr[0];" & @CRLF & _
" }" & @CRLF & _
" return arr.map(asInt);" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function renderableNode(node) {" & @CRLF & _
" return (node.nodeType === Node.TEXT_NODE || node.nodeType === Node.ELEMENT_NODE);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isPositionedForStacking(container) {" & @CRLF & _
" var position = container.css("position");" & @CRLF & _
" var zIndex = (["absolute", "relative", "fixed"].indexOf(position) !== -1) ? container.css("zIndex") : "auto";" & @CRLF & _
" return zIndex !== "auto";" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isPositioned(container) {" & @CRLF & _
" return container.css("position") !== "static";" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isFloating(container) {" & @CRLF & _
" return container.css("float") !== "none";" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isInlineBlock(container) {" & @CRLF & _
" return ["inline-block", "inline-table"].indexOf(container.css("display")) !== -1;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function not(callback) {" & @CRLF & _
" var context = this;" & @CRLF & _
" return function() {" & @CRLF & _
" return !callback.apply(context, arguments);" & @CRLF & _
" };" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isElement(container) {" & @CRLF & _
" return container.node.nodeType === Node.ELEMENT_NODE;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isPseudoElement(container) {" & @CRLF & _
" return container.isPseudoElement === true;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isTextNode(container) {" & @CRLF & _
" return container.node.nodeType === Node.TEXT_NODE;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function zIndexSort(contexts) {" & @CRLF & _
" return function(a, b) {" & @CRLF & _
" return (a.cssInt("zIndex") + (contexts.indexOf(a) / contexts.length)) - (b.cssInt("zIndex") + (contexts.indexOf(b) / contexts.length));" & @CRLF & _
" };" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function hasOpacity(container) {" & @CRLF & _
" return container.getOpacity() < 1;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function bind(callback, context) {" & @CRLF & _
" return function() {" & @CRLF & _
" return callback.apply(context, arguments);" & @CRLF & _
" };" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function asInt(value) {" & @CRLF & _
" return parseInt(value, 10);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getWidth(border) {" & @CRLF & _
" return border.width;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function nonIgnoredElement(nodeContainer) {" & @CRLF & _
" return (nodeContainer.node.nodeType !== Node.ELEMENT_NODE || ["SCRIPT", "HEAD", "TITLE", "OBJECT", "BR", "OPTION"].indexOf(nodeContainer.node.nodeName) === -1);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function flatten(arrays) {" & @CRLF & _
" return [].concat.apply([], arrays);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function stripQuotes(content) {" & @CRLF & _
" var first = content.substr(0, 1);" & @CRLF & _
" return (first === content.substr(content.length - 1) && first.match(/'|"/)) ? content.substr(1, content.length - 2) : content;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function getWords(characters) {" & @CRLF & _
" var words = [], i = 0, onWordBoundary = false, word;" & @CRLF & _
" while(characters.length) {" & @CRLF & _
" if (isWordBoundary(characters[i]) === onWordBoundary) {" & @CRLF & _
" word = characters.splice(0, i);" & @CRLF & _
" if (word.length) {" & @CRLF & _
" words.push(window.html2canvas.punycode.ucs2.encode(word));" & @CRLF & _
" }" & @CRLF & _
" onWordBoundary =! onWordBoundary;" & @CRLF & _
" i = 0;" & @CRLF & _
" } else {" & @CRLF & _
" i++;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" if (i >= characters.length) {" & @CRLF & _
" word = characters.splice(0, i);" & @CRLF & _
" if (word.length) {" & @CRLF & _
" words.push(window.html2canvas.punycode.ucs2.encode(word));" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
" return words;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function isWordBoundary(characterCode) {" & @CRLF & _
" return [" & @CRLF & _
" 32, // <space>" & @CRLF & _
" 13, // \r" & @CRLF & _
" 10, // \n" & @CRLF & _
" 9, // \t" & @CRLF & _
" 45 // -" & @CRLF & _
" ].indexOf(characterCode) !== -1;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function hasUnicode(string) {" & @CRLF & _
" return (/[^\u0000-\u00ff]/).test(string);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function Proxy(src, proxyUrl, document) {" & @CRLF & _
" if (!proxyUrl) {" & @CRLF & _
" return Promise.reject("No proxy configured");" & @CRLF & _
" }" & @CRLF & _
" var callback = createCallback(supportsCORS);" & @CRLF & _
" var url = createProxyUrl(proxyUrl, src, callback);" & @CRLF & _
"" & @CRLF & _
" return supportsCORS ? XHR(url) : (jsonp(document, url, callback).then(function(response) {" & @CRLF & _
" return decode64(response.content);" & @CRLF & _
" }));" & @CRLF & _
"}" & @CRLF & _
"var proxyCount = 0;" & @CRLF & _
"" & @CRLF & _
"var supportsCORS = ('withCredentials' in new XMLHttpRequest());" & @CRLF & _
"var supportsCORSImage = ('crossOrigin' in new Image());" & @CRLF & _
"" & @CRLF & _
"function ProxyURL(src, proxyUrl, document) {" & @CRLF & _
" var callback = createCallback(supportsCORSImage);" & @CRLF & _
" var url = createProxyUrl(proxyUrl, src, callback);" & @CRLF & _
" return (supportsCORSImage ? Promise.resolve(url) : jsonp(document, url, callback).then(function(response) {" & @CRLF & _
" return "data:" + response.type + ";base64," + response.content;" & @CRLF & _
" }));" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function jsonp(document, url, callback) {" & @CRLF & _
" return new Promise(function(resolve, reject) {" & @CRLF & _
" var s = document.createElement("script");" & @CRLF & _
" var cleanup = function() {" & @CRLF & _
" delete window.html2canvas.proxy[callback];" & @CRLF & _
" document.body.removeChild(s);" & @CRLF & _
" };" & @CRLF & _
" window.html2canvas.proxy[callback] = function(response) {" & @CRLF & _
" cleanup();" & @CRLF & _
" resolve(response);" & @CRLF & _
" };" & @CRLF & _
" s.src = url;" & @CRLF & _
" s.onerror = function(e) {" & @CRLF & _
" cleanup();" & @CRLF & _
" reject(e);" & @CRLF & _
" };" & @CRLF & _
" document.body.appendChild(s);" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function createCallback(useCORS) {" & @CRLF & _
" return !useCORS ? "html2canvas_" + Date.now() + "_" + (++proxyCount) + "_" + Math.round(Math.random() * 100000) : "";" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function createProxyUrl(proxyUrl, src, callback) {" & @CRLF & _
" return proxyUrl + "?url=" + encodeURIComponent(src) + (callback.length ? "&callback=html2canvas.proxy." + callback : "");" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function ProxyImageContainer(src, proxy) {" & @CRLF & _
" var script = document.createElement("script");" & @CRLF & _
" var link = document.createElement("a");" & @CRLF & _
" link.href = src;" & @CRLF & _
" src = link.href;" & @CRLF & _
" this.src = src;" & @CRLF & _
" this.image = new Image();" & @CRLF & _
" var self = this;" & @CRLF & _
" this.promise = new Promise(function(resolve, reject) {" & @CRLF & _
" self.image.crossOrigin = "Anonymous";" & @CRLF & _
" self.image.onload = resolve;" & @CRLF & _
" self.image.onerror = reject;" & @CRLF & _
"" & @CRLF & _
" new ProxyURL(src, proxy, document).then(function(url) {" & @CRLF & _
" self.image.src = url;" & @CRLF & _
" })['catch'](reject);" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function PseudoElementContainer(node, parent, type) {" & @CRLF & _
" NodeContainer.call(this, node, parent);" & @CRLF & _
" this.isPseudoElement = true;" & @CRLF & _
" this.before = type === ":before";" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"PseudoElementContainer.prototype.cloneTo = function(stack) {" & @CRLF & _
" PseudoElementContainer.prototype.cloneTo.call(this, stack);" & @CRLF & _
" stack.isPseudoElement = true;" & @CRLF & _
" stack.before = this.before;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"PseudoElementContainer.prototype = Object.create(NodeContainer.prototype);" & @CRLF & _
"" & @CRLF & _
"PseudoElementContainer.prototype.appendToDOM = function() {" & @CRLF & _
" if (this.before) {" & @CRLF & _
" this.parent.node.insertBefore(this.node, this.parent.node.firstChild);" & @CRLF & _
" } else {" & @CRLF & _
" this.parent.node.appendChild(this.node);" & @CRLF & _
" }" & @CRLF & _
" this.parent.node.className += " " + this.getHideClass();" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"PseudoElementContainer.prototype.cleanDOM = function() {" & @CRLF & _
" this.node.parentNode.removeChild(this.node);" & @CRLF & _
" this.parent.node.className = this.parent.node.className.replace(this.getHideClass(), "");" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"PseudoElementContainer.prototype.getHideClass = function() {" & @CRLF & _
" return this["PSEUDO_HIDE_ELEMENT_CLASS_" + (this.before ? "BEFORE" : "AFTER")];" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE = "___html2canvas___pseudoelement_before";" & @CRLF & _
"PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER = "___html2canvas___pseudoelement_after";" & @CRLF & _
"" & @CRLF & _
"function Renderer(width, height, images, options, document) {" & @CRLF & _
" this.width = width;" & @CRLF & _
" this.height = height;" & @CRLF & _
" this.images = images;" & @CRLF & _
" this.options = options;" & @CRLF & _
" this.document = document;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"Renderer.prototype.renderImage = function(container, bounds, borderData, imageContainer) {" & @CRLF & _
" var paddingLeft = container.cssInt('paddingLeft')," & @CRLF & _
" paddingTop = container.cssInt('paddingTop')," & @CRLF & _
" paddingRight = container.cssInt('paddingRight')," & @CRLF & _
" paddingBottom = container.cssInt('paddingBottom')," & @CRLF & _
" borders = borderData.borders;" & @CRLF & _
"" & @CRLF & _
" var width = bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight);" & @CRLF & _
" var height = bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom);" & @CRLF & _
" this.drawImage(" & @CRLF & _
" imageContainer," & @CRLF & _
" 0," & @CRLF & _
" 0," & @CRLF & _
" imageContainer.image.width || width," & @CRLF & _
" imageContainer.image.height || height," & @CRLF & _
" bounds.left + paddingLeft + borders[3].width," & @CRLF & _
" bounds.top + paddingTop + borders[0].width," & @CRLF & _
" width," & @CRLF & _
" height" & @CRLF & _
" );" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Renderer.prototype.renderBackground = function(container, bounds, borderData) {" & @CRLF & _
" if (bounds.height > 0 && bounds.width > 0) {" & @CRLF & _
" this.renderBackgroundColor(container, bounds);" & @CRLF & _
" this.renderBackgroundImage(container, bounds, borderData);" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Renderer.prototype.renderBackgroundColor = function(container, bounds) {" & @CRLF & _
" var color = container.color("backgroundColor");" & @CRLF & _
" if (!color.isTransparent()) {" & @CRLF & _
" this.rectangle(bounds.left, bounds.top, bounds.width, bounds.height, color);" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Renderer.prototype.renderBorders = function(borders) {" & @CRLF & _
" borders.forEach(this.renderBorder, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Renderer.prototype.renderBorder = function(data) {" & @CRLF & _
" if (!data.color.isTransparent() && data.args !== null) {" & @CRLF & _
" this.drawShape(data.args, data.color);" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Renderer.prototype.renderBackgroundImage = function(container, bounds, borderData) {" & @CRLF & _
" var backgroundImages = container.parseBackgroundImages();" & @CRLF & _
" backgroundImages.reverse().forEach(function(backgroundImage, index, arr) {" & @CRLF & _
" switch(backgroundImage.method) {" & @CRLF & _
" case "url":" & @CRLF & _
" var image = this.images.get(backgroundImage.args[0]);" & @CRLF & _
" if (image) {" & @CRLF & _
" this.renderBackgroundRepeating(container, bounds, image, arr.length - (index+1), borderData);" & @CRLF & _
" } else {" & @CRLF & _
" log("Error loading background-image", backgroundImage.args[0]);" & @CRLF & _
" }" & @CRLF & _
" break;" & @CRLF & _
" case "linear-gradient":" & @CRLF & _
" case "gradient":" & @CRLF & _
" var gradientImage = this.images.get(backgroundImage.value);" & @CRLF & _
" if (gradientImage) {" & @CRLF & _
" this.renderBackgroundGradient(gradientImage, bounds, borderData);" & @CRLF & _
" } else {" & @CRLF & _
" log("Error loading background-image", backgroundImage.args[0]);" & @CRLF & _
" }" & @CRLF & _
" break;" & @CRLF & _
" case "none":" & @CRLF & _
" break;" & @CRLF & _
" default:" & @CRLF & _
" log("Unknown background-image type", backgroundImage.args[0]);" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Renderer.prototype.renderBackgroundRepeating = function(container, bounds, imageContainer, index, borderData) {" & @CRLF & _
" var size = container.parseBackgroundSize(bounds, imageContainer.image, index);" & @CRLF & _
" var position = container.parseBackgroundPosition(bounds, imageContainer.image, index, size);" & @CRLF & _
" var repeat = container.parseBackgroundRepeat(index);" & @CRLF & _
" switch (repeat) {" & @CRLF & _
" case "repeat-x":" & @CRLF & _
" case "repeat no-repeat":" & @CRLF & _
" this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + borderData[3], bounds.top + position.top + borderData[0], 99999, size.height, borderData);" & @CRLF & _
" break;" & @CRLF & _
" case "repeat-y":" & @CRLF & _
" case "no-repeat repeat":" & @CRLF & _
" this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + position.left + borderData[3], bounds.top + borderData[0], size.width, 99999, borderData);" & @CRLF & _
" break;" & @CRLF & _
" case "no-repeat":" & @CRLF & _
" this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + position.left + borderData[3], bounds.top + position.top + borderData[0], size.width, size.height, borderData);" & @CRLF & _
" break;" & @CRLF & _
" default:" & @CRLF & _
" this.renderBackgroundRepeat(imageContainer, position, size, {top: bounds.top, left: bounds.left}, borderData[3], borderData[0]);" & @CRLF & _
" break;" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function StackingContext(hasOwnStacking, opacity, element, parent) {" & @CRLF & _
" NodeContainer.call(this, element, parent);" & @CRLF & _
" this.ownStacking = hasOwnStacking;" & @CRLF & _
" this.contexts = [];" & @CRLF & _
" this.children = [];" & @CRLF & _
" this.opacity = (this.parent ? this.parent.stack.opacity : 1) * opacity;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"StackingContext.prototype = Object.create(NodeContainer.prototype);" & @CRLF & _
"" & @CRLF & _
"StackingContext.prototype.getParentStack = function(context) {" & @CRLF & _
" var parentStack = (this.parent) ? this.parent.stack : null;" & @CRLF & _
" return parentStack ? (parentStack.ownStacking ? parentStack : parentStack.getParentStack(context)) : context.stack;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function Support(document) {" & @CRLF & _
" this.rangeBounds = this.testRangeBounds(document);" & @CRLF & _
" this.cors = this.testCORS();" & @CRLF & _
" this.svg = this.testSVG();" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"Support.prototype.testRangeBounds = function(document) {" & @CRLF & _
" var range, testElement, rangeBounds, rangeHeight, support = false;" & @CRLF & _
"" & @CRLF & _
" if (document.createRange) {" & @CRLF & _
" range = document.createRange();" & @CRLF & _
" if (range.getBoundingClientRect) {" & @CRLF & _
" testElement = document.createElement('boundtest');" & @CRLF & _
" testElement.style.height = "123px";" & @CRLF & _
" testElement.style.display = "block";" & @CRLF & _
" document.body.appendChild(testElement);" & @CRLF & _
"" & @CRLF & _
" range.selectNode(testElement);" & @CRLF & _
" rangeBounds = range.getBoundingClientRect();" & @CRLF & _
" rangeHeight = rangeBounds.height;" & @CRLF & _
"" & @CRLF & _
" if (rangeHeight === 123) {" & @CRLF & _
" support = true;" & @CRLF & _
" }" & @CRLF & _
" document.body.removeChild(testElement);" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return support;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Support.prototype.testCORS = function() {" & @CRLF & _
" return typeof((new Image()).crossOrigin) !== "undefined";" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"Support.prototype.testSVG = function() {" & @CRLF & _
" var img = new Image();" & @CRLF & _
" var canvas = document.createElement("canvas");" & @CRLF & _
" var ctx = canvas.getContext("2d");" & @CRLF & _
" img.src = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>";" & @CRLF & _
"" & @CRLF & _
" try {" & @CRLF & _
" ctx.drawImage(img, 0, 0);" & @CRLF & _
" canvas.toDataURL();" & @CRLF & _
" } catch(e) {" & @CRLF & _
" return false;" & @CRLF & _
" }" & @CRLF & _
" return true;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function SVGContainer(src) {" & @CRLF & _
" this.src = src;" & @CRLF & _
" this.image = null;" & @CRLF & _
" var self = this;" & @CRLF & _
"" & @CRLF & _
" this.promise = this.hasFabric().then(function() {" & @CRLF & _
" return (self.isInline(src) ? Promise.resolve(self.inlineFormatting(src)) : XHR(src));" & @CRLF & _
" }).then(function(svg) {" & @CRLF & _
" return new Promise(function(resolve) {" & @CRLF & _
" html2canvas.fabric.loadSVGFromString(svg, self.createCanvas.call(self, resolve));" & @CRLF & _
" });" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"SVGContainer.prototype.hasFabric = function() {" & @CRLF & _
" return !html2canvas.fabric ? Promise.reject(new Error("html2canvas.svg.js is not loaded, cannot render svg")) : Promise.resolve();" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"SVGContainer.prototype.inlineFormatting = function(src) {" & @CRLF & _
" return (/^data:image\/svg\+xml;base64,/.test(src)) ? this.decode64(this.removeContentType(src)) : this.removeContentType(src);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"SVGContainer.prototype.removeContentType = function(src) {" & @CRLF & _
" return src.replace(/^data:image\/svg\+xml(;base64)?,/,'');" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"SVGContainer.prototype.isInline = function(src) {" & @CRLF & _
" return (/^data:image\/svg\+xml/i.test(src));" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"SVGContainer.prototype.createCanvas = function(resolve) {" & @CRLF & _
" var self = this;" & @CRLF & _
" return function (objects, options) {" & @CRLF & _
" var canvas = new html2canvas.fabric.StaticCanvas('c');" & @CRLF & _
" self.image = canvas.lowerCanvasEl;" & @CRLF & _
" canvas" & @CRLF & _
" .setWidth(options.width)" & @CRLF & _
" .setHeight(options.height)" & @CRLF & _
" .add(html2canvas.fabric.util.groupSVGElements(objects, options))" & @CRLF & _
" .renderAll();" & @CRLF & _
" resolve(canvas.lowerCanvasEl);" & @CRLF & _
" };" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"SVGContainer.prototype.decode64 = function(str) {" & @CRLF & _
" return (typeof(window.atob) === "function") ? window.atob(str) : decode64(str);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"/*" & @CRLF & _
" * base64-arraybuffer" & @CRLF & _
" * https://github.com/niklasvh/base64-arraybuffer" & @CRLF & _
" *" & @CRLF & _
" * Copyright (c) 2012 Niklas von Hertzen" & @CRLF & _
" * Licensed under the MIT license." & @CRLF & _
" */" & @CRLF & _
"" & @CRLF & _
"function decode64(base64) {" & @CRLF & _
" var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";" & @CRLF & _
" var len = base64.length, i, encoded1, encoded2, encoded3, encoded4, byte1, byte2, byte3;" & @CRLF & _
"" & @CRLF & _
" var output = "";" & @CRLF & _
"" & @CRLF & _
" for (i = 0; i < len; i+=4) {" & @CRLF & _
" encoded1 = chars.indexOf(base64[i]);" & @CRLF & _
" encoded2 = chars.indexOf(base64[i+1]);" & @CRLF & _
" encoded3 = chars.indexOf(base64[i+2]);" & @CRLF & _
" encoded4 = chars.indexOf(base64[i+3]);" & @CRLF & _
"" & @CRLF & _
" byte1 = (encoded1 << 2) | (encoded2 >> 4);" & @CRLF & _
" byte2 = ((encoded2 & 15) << 4) | (encoded3 >> 2);" & @CRLF & _
" byte3 = ((encoded3 & 3) << 6) | encoded4;" & @CRLF & _
" if (encoded3 === 64) {" & @CRLF & _
" output += String.fromCharCode(byte1);" & @CRLF & _
" } else if (encoded4 === 64 || encoded4 === -1) {" & @CRLF & _
" output += String.fromCharCode(byte1, byte2);" & @CRLF & _
" } else{" & @CRLF & _
" output += String.fromCharCode(byte1, byte2, byte3);" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return output;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function SVGNodeContainer(node, native) {" & @CRLF & _
" this.src = node;" & @CRLF & _
" this.image = null;" & @CRLF & _
" var self = this;" & @CRLF & _
"" & @CRLF & _
" this.promise = native ? new Promise(function(resolve, reject) {" & @CRLF & _
" self.image = new Image();" & @CRLF & _
" self.image.onload = resolve;" & @CRLF & _
" self.image.onerror = reject;" & @CRLF & _
" self.image.src = "data:image/svg+xml," + (new XMLSerializer()).serializeToString(node);" & @CRLF & _
" if (self.image.complete === true) {" & @CRLF & _
" resolve(self.image);" & @CRLF & _
" }" & @CRLF & _
" }) : this.hasFabric().then(function() {" & @CRLF & _
" return new Promise(function(resolve) {" & @CRLF & _
" html2canvas.fabric.parseSVGDocument(node, self.createCanvas.call(self, resolve));" & @CRLF & _
" });" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"SVGNodeContainer.prototype = Object.create(SVGContainer.prototype);" & @CRLF & _
"" & @CRLF & _
"function TextContainer(node, parent) {" & @CRLF & _
" NodeContainer.call(this, node, parent);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"TextContainer.prototype = Object.create(NodeContainer.prototype);" & @CRLF & _
"" & @CRLF & _
"TextContainer.prototype.applyTextTransform = function() {" & @CRLF & _
" this.node.data = this.transform(this.parent.css("textTransform"));" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"TextContainer.prototype.transform = function(transform) {" & @CRLF & _
" var text = this.node.data;" & @CRLF & _
" switch(transform){" & @CRLF & _
" case "lowercase":" & @CRLF & _
" return text.toLowerCase();" & @CRLF & _
" case "capitalize":" & @CRLF & _
" return text.replace(/(^|\s|:|-|\(|\))([a-z])/g, capitalize);" & @CRLF & _
" case "uppercase":" & @CRLF & _
" return text.toUpperCase();" & @CRLF & _
" default:" & @CRLF & _
" return text;" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function capitalize(m, p1, p2) {" & @CRLF & _
" if (m.length > 0) {" & @CRLF & _
" return p1 + p2.toUpperCase();" & @CRLF & _
" }" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function WebkitGradientContainer(imageData) {" & @CRLF & _
" GradientContainer.apply(this, arguments);" & @CRLF & _
" this.type = (imageData.args[0] === "linear") ? this.TYPES.LINEAR : this.TYPES.RADIAL;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"WebkitGradientContainer.prototype = Object.create(GradientContainer.prototype);" & @CRLF & _
"" & @CRLF & _
"function XHR(url) {" & @CRLF & _
" return new Promise(function(resolve, reject) {" & @CRLF & _
" var xhr = new XMLHttpRequest();" & @CRLF & _
" xhr.open('GET', url);" & @CRLF & _
"" & @CRLF & _
" xhr.onload = function() {" & @CRLF & _
" if (xhr.status === 200) {" & @CRLF & _
" resolve(xhr.responseText);" & @CRLF & _
" } else {" & @CRLF & _
" reject(new Error(xhr.statusText));" & @CRLF & _
" }" & @CRLF & _
" };" & @CRLF & _
"" & @CRLF & _
" xhr.onerror = function() {" & @CRLF & _
" reject(new Error("Network Error"));" & @CRLF & _
" };" & @CRLF & _
"" & @CRLF & _
" xhr.send();" & @CRLF & _
" });" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"function CanvasRenderer(width, height) {" & @CRLF & _
" Renderer.apply(this, arguments);" & @CRLF & _
" this.canvas = this.options.canvas || this.document.createElement("canvas");" & @CRLF & _
" if (!this.options.canvas) {" & @CRLF & _
" this.canvas.width = width;" & @CRLF & _
" this.canvas.height = height;" & @CRLF & _
" }" & @CRLF & _
" this.ctx = this.canvas.getContext("2d");" & @CRLF & _
" this.taintCtx = this.document.createElement("canvas").getContext("2d");" & @CRLF & _
" this.ctx.textBaseline = "bottom";" & @CRLF & _
" this.variables = {};" & @CRLF & _
" log("Initialized CanvasRenderer with size", width, "x", height);" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype = Object.create(Renderer.prototype);" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.setFillStyle = function(fillStyle) {" & @CRLF & _
" this.ctx.fillStyle = typeof(fillStyle) === "object" && !!fillStyle.isColor ? fillStyle.toString() : fillStyle;" & @CRLF & _
" return this.ctx;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.rectangle = function(left, top, width, height, color) {" & @CRLF & _
" this.setFillStyle(color).fillRect(left, top, width, height);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.circle = function(left, top, size, color) {" & @CRLF & _
" this.setFillStyle(color);" & @CRLF & _
" this.ctx.beginPath();" & @CRLF & _
" this.ctx.arc(left + size / 2, top + size / 2, size / 2, 0, Math.PI*2, true);" & @CRLF & _
" this.ctx.closePath();" & @CRLF & _
" this.ctx.fill();" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.circleStroke = function(left, top, size, color, stroke, strokeColor) {" & @CRLF & _
" this.circle(left, top, size, color);" & @CRLF & _
" this.ctx.strokeStyle = strokeColor.toString();" & @CRLF & _
" this.ctx.stroke();" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.drawShape = function(shape, color) {" & @CRLF & _
" this.shape(shape);" & @CRLF & _
" this.setFillStyle(color).fill();" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.taints = function(imageContainer) {" & @CRLF & _
" if (imageContainer.tainted === null) {" & @CRLF & _
" this.taintCtx.drawImage(imageContainer.image, 0, 0);" & @CRLF & _
" try {" & @CRLF & _
" this.taintCtx.getImageData(0, 0, 1, 1);" & @CRLF & _
" imageContainer.tainted = false;" & @CRLF & _
" } catch(e) {" & @CRLF & _
" this.taintCtx = document.createElement("canvas").getContext("2d");" & @CRLF & _
" imageContainer.tainted = true;" & @CRLF & _
" }" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return imageContainer.tainted;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.drawImage = function(imageContainer, sx, sy, sw, sh, dx, dy, dw, dh) {" & @CRLF & _
" if (!this.taints(imageContainer) || this.options.allowTaint) {" & @CRLF & _
" this.ctx.drawImage(imageContainer.image, sx, sy, sw, sh, dx, dy, dw, dh);" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.clip = function(shapes, callback, context) {" & @CRLF & _
" this.ctx.save();" & @CRLF & _
" shapes.filter(hasEntries).forEach(function(shape) {" & @CRLF & _
" this.shape(shape).clip();" & @CRLF & _
" }, this);" & @CRLF & _
" callback.call(context);" & @CRLF & _
" this.ctx.restore();" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.shape = function(shape) {" & @CRLF & _
" this.ctx.beginPath();" & @CRLF & _
" shape.forEach(function(point, index) {" & @CRLF & _
" if (point[0] === "rect") {" & @CRLF & _
" this.ctx.rect.apply(this.ctx, point.slice(1));" & @CRLF & _
" } else {" & @CRLF & _
" this.ctx[(index === 0) ? "moveTo" : point[0] + "To" ].apply(this.ctx, point.slice(1));" & @CRLF & _
" }" & @CRLF & _
" }, this);" & @CRLF & _
" this.ctx.closePath();" & @CRLF & _
" return this.ctx;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.font = function(color, style, variant, weight, size, family) {" & @CRLF & _
" this.setFillStyle(color).font = [style, variant, weight, size, family].join(" ").split(",")[0];" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.fontShadow = function(color, offsetX, offsetY, blur) {" & @CRLF & _
" this.setVariable("shadowColor", color.toString())" & @CRLF & _
" .setVariable("shadowOffsetY", offsetX)" & @CRLF & _
" .setVariable("shadowOffsetX", offsetY)" & @CRLF & _
" .setVariable("shadowBlur", blur);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.clearShadow = function() {" & @CRLF & _
" this.setVariable("shadowColor", "rgba(0,0,0,0)");" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.setOpacity = function(opacity) {" & @CRLF & _
" this.ctx.globalAlpha = opacity;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.setTransform = function(transform) {" & @CRLF & _
" this.ctx.translate(transform.origin[0], transform.origin[1]);" & @CRLF & _
" this.ctx.transform.apply(this.ctx, transform.matrix);" & @CRLF & _
" this.ctx.translate(-transform.origin[0], -transform.origin[1]);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.setVariable = function(property, value) {" & @CRLF & _
" if (this.variables[property] !== value) {" & @CRLF & _
" this.variables[property] = this.ctx[property] = value;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" return this;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.text = function(text, left, bottom) {" & @CRLF & _
" this.ctx.fillText(text, left, bottom);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.backgroundRepeatShape = function(imageContainer, backgroundPosition, size, bounds, left, top, width, height, borderData) {" & @CRLF & _
" var shape = [" & @CRLF & _
" ["line", Math.round(left), Math.round(top)]," & @CRLF & _
" ["line", Math.round(left + width), Math.round(top)]," & @CRLF & _
" ["line", Math.round(left + width), Math.round(height + top)]," & @CRLF & _
" ["line", Math.round(left), Math.round(height + top)]" & @CRLF & _
" ];" & @CRLF & _
" this.clip([shape], function() {" & @CRLF & _
" this.renderBackgroundRepeat(imageContainer, backgroundPosition, size, bounds, borderData[3], borderData[0]);" & @CRLF & _
" }, this);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.renderBackgroundRepeat = function(imageContainer, backgroundPosition, size, bounds, borderLeft, borderTop) {" & @CRLF & _
" var offsetX = Math.round(bounds.left + backgroundPosition.left + borderLeft), offsetY = Math.round(bounds.top + backgroundPosition.top + borderTop);" & @CRLF & _
" this.setFillStyle(this.ctx.createPattern(this.resizeImage(imageContainer, size), "repeat"));" & @CRLF & _
" this.ctx.translate(offsetX, offsetY);" & @CRLF & _
" this.ctx.fill();" & @CRLF & _
" this.ctx.translate(-offsetX, -offsetY);" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.renderBackgroundGradient = function(gradientImage, bounds) {" & @CRLF & _
" if (gradientImage instanceof LinearGradientContainer) {" & @CRLF & _
" var gradient = this.ctx.createLinearGradient(" & @CRLF & _
" bounds.left + bounds.width * gradientImage.x0," & @CRLF & _
" bounds.top + bounds.height * gradientImage.y0," & @CRLF & _
" bounds.left + bounds.width * gradientImage.x1," & @CRLF & _
" bounds.top + bounds.height * gradientImage.y1);" & @CRLF & _
" gradientImage.colorStops.forEach(function(colorStop) {" & @CRLF & _
" gradient.addColorStop(colorStop.stop, colorStop.color.toString());" & @CRLF & _
" });" & @CRLF & _
" this.rectangle(bounds.left, bounds.top, bounds.width, bounds.height, gradient);" & @CRLF & _
" }" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"CanvasRenderer.prototype.resizeImage = function(imageContainer, size) {" & @CRLF & _
" var image = imageContainer.image;" & @CRLF & _
" if(image.width === size.width && image.height === size.height) {" & @CRLF & _
" return image;" & @CRLF & _
" }" & @CRLF & _
"" & @CRLF & _
" var ctx, canvas = document.createElement('canvas');" & @CRLF & _
" canvas.width = size.width;" & @CRLF & _
" canvas.height = size.height;" & @CRLF & _
" ctx = canvas.getContext("2d");" & @CRLF & _
" ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, size.width, size.height );" & @CRLF & _
" return canvas;" & @CRLF & _
"};" & @CRLF & _
"" & @CRLF & _
"function hasEntries(array) {" & @CRLF & _
" return array.length > 0;" & @CRLF & _
"}" & @CRLF & _
"" & @CRLF & _
"}).call({}, typeof(window) !== "undefined" ? window : undefined, typeof(document) !== "undefined" ? document : undefined);"
Local $aArray = StringRegExp($sString, $sRegex, $STR_REGEXPARRAYGLOBALFULLMATCH)
Local $aFullArray[0]
For $i = 0 To UBound($aArray) -1
_ArrayConcatenate($aFullArray, $aArray[$i])
Next
$aArray = $aFullArray
; Present the entire match result
_ArrayDisplay($aArray, "Result")
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for AutoIt, please visit: https://www.autoitscript.com/autoit3/docs/functions/StringRegExp.htm