diff --git a/Makefile b/Makefile index e2858625..1e7c4afa 100644 --- a/Makefile +++ b/Makefile @@ -30,9 +30,9 @@ QTIP_CSS_MIN = ${DIST_DIR}/jquery.qtip.min.css QTIP_VER = `cat version.txt` VER = sed s/@VERSION/${QTIP_VER}/ -JS_ENGINE = `which nodejs node` +JS_ENGINE = `which node` JS_LINT = ${JS_ENGINE} $(BUILD_DIR)/jslint-check.js -JS_MINIFIER = ${JS_ENGINE} ${BUILD_DIR}/uglify.js --extra +JS_MINIFIER = ${JS_ENGINE} ${BUILD_DIR}/uglify.js CSS_MINIFIER = java -Xmx96m -jar ${BUILD_DIR}/yuicompressor.jar DATE=`git log --pretty=format:'%ad' -1` diff --git a/build/jslint-check.js b/build/jslint-check.js index 4f374c8d..6863bbff 100755 --- a/build/jslint-check.js +++ b/build/jslint-check.js @@ -1,5 +1,4 @@ var JSLINT = require("./lib/jslint").JSLINT, - print = require("sys").print, src = require("fs").readFileSync("dist/jquery.qtip.js", "utf8"); JSLINT(src, { evil: true, forin: true, maxerr: 100 }); @@ -21,16 +20,15 @@ var e = JSLINT.errors, found = 0, w; for ( var i = 0; i < e.length; i++ ) { w = e[i]; - if ( !ok[ w.reason ] ) { - found++; - print( "\n" + w.evidence + "\n" ); - print( " Problem at line " + w.line + " character " + w.character + ": " + w.reason ); + if (w && w.reason && w.evidence && !ok[ w.reason ] ) { + console.log( "\n" + w.evidence + "\n" ); + console.log( " Problem at line " + w.line + " character " + w.character + ": " + w.reason ); } } if ( found > 0 ) { - print( "\n" + found + " Error(s) found.\n" ); + console.log( "\n" + found + " Error(s) found.\n" ); } else { - print( "Success!\n" ); + console.log( "Success!\n" ); } diff --git a/build/lib/parse-js.js b/build/lib/parse-js.js index 7e4fd0e2..d966eb06 100644 --- a/build/lib/parse-js.js +++ b/build/lib/parse-js.js @@ -65,6 +65,7 @@ var KEYWORDS = array_to_hash([ "catch", "const", "continue", + "debugger", "default", "delete", "do", @@ -93,7 +94,6 @@ var RESERVED_WORDS = array_to_hash([ "byte", "char", "class", - "debugger", "double", "enum", "export", @@ -182,8 +182,6 @@ var OPERATORS = array_to_hash([ ">>=", "<<=", ">>>=", - "~=", - "%=", "|=", "^=", "&=", @@ -191,9 +189,9 @@ var OPERATORS = array_to_hash([ "||" ]); -var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t")); +var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000")); -var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:")); +var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{(,.;:")); var PUNC_CHARS = array_to_hash(characters("[]{}(),;:")); @@ -201,20 +199,47 @@ var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy")); /* -----[ Tokenizer ]----- */ -function is_alphanumeric_char(ch) { - ch = ch.charCodeAt(0); - return (ch >= 48 && ch <= 57) || - (ch >= 65 && ch <= 90) || - (ch >= 97 && ch <= 122); +// regexps adapted from http://xregexp.com/plugins/#unicode +var UNICODE = { + letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"), + non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"), + space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"), + connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]") }; -function is_identifier_char(ch) { - return is_alphanumeric_char(ch) || ch == "$" || ch == "_"; +function is_letter(ch) { + return UNICODE.letter.test(ch); }; function is_digit(ch) { ch = ch.charCodeAt(0); - return ch >= 48 && ch <= 57; + return ch >= 48 && ch <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9 +}; + +function is_alphanumeric_char(ch) { + return is_digit(ch) || is_letter(ch); +}; + +function is_unicode_combining_mark(ch) { + return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch); +}; + +function is_unicode_connector_punctuation(ch) { + return UNICODE.connector_punctuation.test(ch); +}; + +function is_identifier_start(ch) { + return ch == "$" || ch == "_" || is_letter(ch); +}; + +function is_identifier_char(ch) { + return is_identifier_start(ch) + || is_unicode_combining_mark(ch) + || is_digit(ch) + || is_unicode_connector_punctuation(ch) + || ch == "\u200c" // zero-width non-joiner + || ch == "\u200d" // zero-width joiner (in my ECMA-262 PDF, this is also 200c) + ; }; function parse_js_number(num) { @@ -229,14 +254,10 @@ function parse_js_number(num) { function JS_Parse_Error(message, line, col, pos) { this.message = message; - this.line = line; - this.col = col; - this.pos = pos; - try { - ({})(); - } catch(ex) { - this.stack = ex.stack; - }; + this.line = line + 1; + this.col = col + 1; + this.pos = pos + 1; + this.stack = new Error().stack; }; JS_Parse_Error.prototype.toString = function() { @@ -253,28 +274,29 @@ function is_token(token, type, val) { var EX_EOF = {}; -function tokenizer($TEXT, skip_comments) { +function tokenizer($TEXT) { var S = { - text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), - pos : 0, - tokpos : 0, - line : 0, - tokline : 0, - col : 0, - tokcol : 0, - newline_before : false, - regex_allowed : false + text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), + pos : 0, + tokpos : 0, + line : 0, + tokline : 0, + col : 0, + tokcol : 0, + newline_before : false, + regex_allowed : false, + comments_before : [] }; function peek() { return S.text.charAt(S.pos); }; - function next(signal_eof) { + function next(signal_eof, in_string) { var ch = S.text.charAt(S.pos++); if (signal_eof && !ch) throw EX_EOF; if (ch == "\n") { - S.newline_before = true; + S.newline_before = S.newline_before || !in_string; ++S.line; S.col = 0; } else { @@ -299,18 +321,23 @@ function tokenizer($TEXT, skip_comments) { S.tokpos = S.pos; }; - function token(type, value) { + function token(type, value, is_comment) { S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); var ret = { - type : type, - value : value, - line : S.tokline, - col : S.tokcol, - pos : S.tokpos, - nlb : S.newline_before + type : type, + value : value, + line : S.tokline, + col : S.tokcol, + pos : S.tokpos, + endpos : S.pos, + nlb : S.newline_before }; + if (!is_comment) { + ret.comments_before = S.comments_before; + S.comments_before = []; + } S.newline_before = false; return ret; }; @@ -351,7 +378,7 @@ function tokenizer($TEXT, skip_comments) { if (ch == "+") return after_e; after_e = false; if (ch == ".") { - if (!has_dot) + if (!has_dot && !has_x) return has_dot = true; return false; } @@ -367,18 +394,19 @@ function tokenizer($TEXT, skip_comments) { } }; - function read_escaped_char() { - var ch = next(true); + function read_escaped_char(in_string) { + var ch = next(true, in_string); switch (ch) { case "n" : return "\n"; case "r" : return "\r"; case "t" : return "\t"; case "b" : return "\b"; - case "v" : return "\v"; + case "v" : return "\u000b"; case "f" : return "\f"; case "0" : return "\0"; case "x" : return String.fromCharCode(hex_bytes(2)); case "u" : return String.fromCharCode(hex_bytes(4)); + case "\n": return ""; default : return ch; } }; @@ -399,7 +427,24 @@ function tokenizer($TEXT, skip_comments) { var quote = next(), ret = ""; for (;;) { var ch = next(true); - if (ch == "\\") ch = read_escaped_char(); + if (ch == "\\") { + // read OctalEscapeSequence (XXX: deprecated if "strict mode") + // https://github.com/mishoo/UglifyJS/issues/178 + var octal_len = 0, first = null; + ch = read_while(function(ch){ + if (ch >= "0" && ch <= "7") { + if (!first) { + first = ch; + return ++octal_len; + } + else if (first <= "3" && octal_len <= 2) return ++octal_len; + else if (first >= "4" && octal_len <= 1) return ++octal_len; + } + return false; + }); + if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8)); + else ch = read_escaped_char(true); + } else if (ch == quote) break; ret += ch; } @@ -417,25 +462,55 @@ function tokenizer($TEXT, skip_comments) { ret = S.text.substring(S.pos, i); S.pos = i; } - return token("comment1", ret); + return token("comment1", ret, true); }; function read_multiline_comment() { next(); return with_eof_error("Unterminated multiline comment", function(){ var i = find("*/", true), - text = S.text.substring(S.pos, i), - tok = token("comment2", text); + text = S.text.substring(S.pos, i); S.pos = i + 2; S.line += text.split("\n").length - 1; S.newline_before = text.indexOf("\n") >= 0; - return tok; + + // https://github.com/mishoo/UglifyJS/issues/#issue/100 + if (/^@cc_on/i.test(text)) { + warn("WARNING: at line " + S.line); + warn("*** Found \"conditional comment\": " + text); + warn("*** UglifyJS DISCARDS ALL COMMENTS. This means your code might no longer work properly in Internet Explorer."); + } + + return token("comment2", text, true); }); }; - function read_regexp() { + function read_name() { + var backslash = false, name = "", ch, escaped = false, hex; + while ((ch = peek()) != null) { + if (!backslash) { + if (ch == "\\") escaped = backslash = true, next(); + else if (is_identifier_char(ch)) name += next(); + else break; + } + else { + if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); + ch = read_escaped_char(); + if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); + name += ch; + backslash = false; + } + } + if (HOP(KEYWORDS, name) && escaped) { + hex = name.charCodeAt(0).toString(16).toUpperCase(); + name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1); + } + return name; + }; + + function read_regexp(regexp) { return with_eof_error("Unterminated regular expression", function(){ - var prev_backslash = false, regexp = "", ch, in_class = false; + var prev_backslash = false, ch, in_class = false; while ((ch = next(true))) if (prev_backslash) { regexp += "\\" + ch; prev_backslash = false; @@ -452,15 +527,14 @@ function tokenizer($TEXT, skip_comments) { } else { regexp += ch; } - var mods = read_while(function(ch){ - return HOP(REGEXP_MODIFIERS, ch); - }); + var mods = read_name(); return token("regexp", [ regexp, mods ]); }); }; function read_operator(prefix) { function grow(op) { + if (!peek()) return op; var bigger = op + peek(); if (HOP(OPERATORS, bigger)) { next(); @@ -472,21 +546,20 @@ function tokenizer($TEXT, skip_comments) { return token("operator", grow(prefix || next())); }; - var handle_slash = skip_comments ? function() { + function handle_slash() { next(); var regex_allowed = S.regex_allowed; switch (peek()) { - case "/": read_line_comment(); S.regex_allowed = regex_allowed; return next_token(); - case "*": read_multiline_comment(); S.regex_allowed = regex_allowed; return next_token(); + case "/": + S.comments_before.push(read_line_comment()); + S.regex_allowed = regex_allowed; + return next_token(); + case "*": + S.comments_before.push(read_multiline_comment()); + S.regex_allowed = regex_allowed; + return next_token(); } - return S.regex_allowed ? read_regexp() : read_operator("/"); - } : function() { - next(); - switch (peek()) { - case "/": return read_line_comment(); - case "*": return read_multiline_comment(); - } - return S.regex_allowed ? read_regexp() : read_operator("/"); + return S.regex_allowed ? read_regexp("") : read_operator("/"); }; function handle_dot() { @@ -497,7 +570,7 @@ function tokenizer($TEXT, skip_comments) { }; function read_word() { - var word = read_while(is_identifier_char); + var word = read_name(); return !HOP(KEYWORDS, word) ? token("name", word) : HOP(OPERATORS, word) @@ -517,8 +590,8 @@ function tokenizer($TEXT, skip_comments) { }; function next_token(force_regexp) { - if (force_regexp) - return read_regexp(); + if (force_regexp != null) + return read_regexp(force_regexp); skip_whitespace(); start_token(); var ch = peek(); @@ -529,7 +602,7 @@ function tokenizer($TEXT, skip_comments) { if (ch == ".") return handle_dot(); if (ch == "/") return handle_slash(); if (HOP(OPERATOR_CHARS, ch)) return read_operator(); - if (is_identifier_char(ch)) return read_word(); + if (ch == "\\" || is_identifier_start(ch)) return read_word(); parse_error("Unexpected character '" + ch + "'"); }; @@ -565,7 +638,7 @@ var ASSIGNMENT = (function(a, ret, i){ } return ret; })( - ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "~=", "%=", "|=", "^=", "&="], + ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="], { "=": true }, 0 ); @@ -608,16 +681,17 @@ function NodeWithToken(str, start, end) { NodeWithToken.prototype.toString = function() { return this.name; }; -function parse($TEXT, strict_mode, embed_tokens) { +function parse($TEXT, exigent_mode, embed_tokens) { var S = { - input: tokenizer($TEXT, true), - token: null, - prev: null, - peeked: null, - in_function: 0, - in_loop: 0, - labels: [] + input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT, + token : null, + prev : null, + peeked : null, + in_function : 0, + in_directives : true, + in_loop : 0, + labels : [] }; S.token = next(); @@ -636,6 +710,9 @@ function parse($TEXT, strict_mode, embed_tokens) { } else { S.token = S.input(); } + S.in_directives = S.in_directives && ( + S.token.type == "string" || is("punc", ";") + ); return S.token; }; @@ -671,7 +748,7 @@ function parse($TEXT, strict_mode, embed_tokens) { function expect(punc) { return expect_token("punc", punc); }; function can_insert_semicolon() { - return !strict_mode && ( + return !exigent_mode && ( S.token.nlb || is("eof") || is("punc", "}") ); }; @@ -693,24 +770,31 @@ function parse($TEXT, strict_mode, embed_tokens) { }; function add_tokens(str, start, end) { - return new NodeWithToken(str, start, end); + return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end); }; - var statement = embed_tokens ? function() { - var start = S.token; - var stmt = $statement(); - stmt[0] = add_tokens(stmt[0], start, prev()); - return stmt; - } : $statement; + function maybe_embed_tokens(parser) { + if (embed_tokens) return function() { + var start = S.token; + var ast = parser.apply(this, arguments); + ast[0] = add_tokens(ast[0], start, prev()); + return ast; + }; + else return parser; + }; - function $statement() { - if (is("operator", "/")) { + var statement = maybe_embed_tokens(function() { + if (is("operator", "/") || is("operator", "/=")) { S.peeked = null; - S.token = S.input(true); // force regexp + S.token = S.input(S.token.value.substr(1)); // force regexp } switch (S.token.type) { - case "num": case "string": + var dir = S.in_directives, stat = simple_statement(); + if (dir && stat[1][0] == "string" && !is("punc", ",")) + return as("directive", stat[1][1]); + return stat; + case "num": case "regexp": case "operator": case "atom": @@ -776,6 +860,8 @@ function parse($TEXT, strict_mode, embed_tokens) { return as("switch", parenthesised(), switch_block_()); case "throw": + if (S.token.nlb) + croak("Illegal newline after 'throw'"); return as("throw", prog1(expression, semicolon)); case "try": @@ -797,12 +883,12 @@ function parse($TEXT, strict_mode, embed_tokens) { unexpected(); } } - }; + }); function labeled_statement(label) { S.labels.push(label); var start = S.token, stat = statement(); - if (strict_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) + if (exigent_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) unexpected(start); S.labels.pop(); return as("label", label, stat); @@ -813,7 +899,10 @@ function parse($TEXT, strict_mode, embed_tokens) { }; function break_cont(type) { - var name = is("name") ? S.token.value : null; + var name; + if (!can_insert_semicolon()) { + name = is("name") ? S.token.value : null; + } if (name != null) { next(); if (!member(name, S.labels)) @@ -827,29 +916,38 @@ function parse($TEXT, strict_mode, embed_tokens) { function for_() { expect("("); - var has_var = is("keyword", "var"); - if (has_var) - next(); - if (is("name") && is_token(peek(), "operator", "in")) { - // for (i in foo) - var name = S.token.value; - next(); next(); - var obj = expression(); - expect(")"); - return as("for-in", has_var, name, obj, in_loop(statement)); - } else { - // classic for - var init = is("punc", ";") ? null : has_var ? var_() : expression(); - expect(";"); - var test = is("punc", ";") ? null : expression(); - expect(";"); - var step = is("punc", ")") ? null : expression(); - expect(")"); - return as("for", init, test, step, in_loop(statement)); + var init = null; + if (!is("punc", ";")) { + init = is("keyword", "var") + ? (next(), var_(true)) + : expression(true, true); + if (is("operator", "in")) { + if (init[0] == "var" && init[1].length > 1) + croak("Only one variable declaration allowed in for..in loop"); + return for_in(init); + } } + return regular_for(init); }; - function function_(in_statement) { + function regular_for(init) { + expect(";"); + var test = is("punc", ";") ? null : expression(); + expect(";"); + var step = is("punc", ")") ? null : expression(); + expect(")"); + return as("for", init, test, step, in_loop(statement)); + }; + + function for_in(init) { + var lhs = init[0] == "var" ? as("name", init[1][0]) : init; + next(); + var obj = expression(); + expect(")"); + return as("for-in", init, lhs, obj, in_loop(statement)); + }; + + var function_ = function(in_statement) { var name = is("name") ? prog1(S.token.value, next) : null; if (in_statement && !name) unexpected(); @@ -871,6 +969,7 @@ function parse($TEXT, strict_mode, embed_tokens) { (function(){ ++S.in_function; var loop = S.in_loop; + S.in_directives = true; S.in_loop = 0; var a = block_(); --S.in_function; @@ -946,7 +1045,7 @@ function parse($TEXT, strict_mode, embed_tokens) { return as("try", body, bcatch, bfinally); }; - function vardefs() { + function vardefs(no_in) { var a = []; for (;;) { if (!is("name")) @@ -955,7 +1054,7 @@ function parse($TEXT, strict_mode, embed_tokens) { next(); if (is("operator", "=")) { next(); - a.push([ name, expression(false) ]); + a.push([ name, expression(false, no_in) ]); } else { a.push([ name ]); } @@ -966,8 +1065,8 @@ function parse($TEXT, strict_mode, embed_tokens) { return a; }; - function var_() { - return as("var", vardefs()); + function var_(no_in) { + return as("var", vardefs(no_in)); }; function const_() { @@ -985,16 +1084,11 @@ function parse($TEXT, strict_mode, embed_tokens) { return subscripts(as("new", newexp, args), true); }; - function expr_atom(allow_calls) { + var expr_atom = maybe_embed_tokens(function(allow_calls) { if (is("operator", "new")) { next(); return new_(); } - if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) { - return make_unary("unary-prefix", - prog1(S.token.value, next), - expr_atom(allow_calls)); - } if (is("punc")) { switch (S.token.value) { case "(": @@ -1020,29 +1114,32 @@ function parse($TEXT, strict_mode, embed_tokens) { return subscripts(prog1(atom, next), allow_calls); } unexpected(); - }; + }); - function expr_list(closing, allow_trailing_comma) { + function expr_list(closing, allow_trailing_comma, allow_empty) { var first = true, a = []; while (!is("punc", closing)) { if (first) first = false; else expect(","); - if (allow_trailing_comma && is("punc", closing)) - break; - a.push(expression(false)); + if (allow_trailing_comma && is("punc", closing)) break; + if (is("punc", ",") && allow_empty) { + a.push([ "atom", "undefined" ]); + } else { + a.push(expression(false)); + } } next(); return a; }; function array_() { - return as("array", expr_list("]", !strict_mode)); + return as("array", expr_list("]", !exigent_mode, true)); }; function object_() { var first = true, a = []; while (!is("punc", "}")) { if (first) first = false; else expect(","); - if (!strict_mode && is("punc", "}")) + if (!exigent_mode && is("punc", "}")) // allow trailing comma break; var type = S.token.type; @@ -1092,77 +1189,91 @@ function parse($TEXT, strict_mode, embed_tokens) { next(); return subscripts(as("call", expr, expr_list(")")), true); } - if (allow_calls && is("operator") && HOP(UNARY_POSTFIX, S.token.value)) { - return prog1(curry(make_unary, "unary-postfix", S.token.value, expr), - next); - } return expr; }; + function maybe_unary(allow_calls) { + if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) { + return make_unary("unary-prefix", + prog1(S.token.value, next), + maybe_unary(allow_calls)); + } + var val = expr_atom(allow_calls); + while (is("operator") && HOP(UNARY_POSTFIX, S.token.value) && !S.token.nlb) { + val = make_unary("unary-postfix", S.token.value, val); + next(); + } + return val; + }; + function make_unary(tag, op, expr) { if ((op == "++" || op == "--") && !is_assignable(expr)) croak("Invalid use of " + op + " operator"); return as(tag, op, expr); }; - function expr_op(left, min_prec) { + function expr_op(left, min_prec, no_in) { var op = is("operator") ? S.token.value : null; + if (op && op == "in" && no_in) op = null; var prec = op != null ? PRECEDENCE[op] : null; if (prec != null && prec > min_prec) { next(); - var right = expr_op(expr_atom(true), prec); - return expr_op(as("binary", op, left, right), min_prec); + var right = expr_op(maybe_unary(true), prec, no_in); + return expr_op(as("binary", op, left, right), min_prec, no_in); } return left; }; - function expr_ops() { - return expr_op(expr_atom(true), 0); + function expr_ops(no_in) { + return expr_op(maybe_unary(true), 0, no_in); }; - function maybe_conditional() { - var expr = expr_ops(); + function maybe_conditional(no_in) { + var expr = expr_ops(no_in); if (is("operator", "?")) { next(); var yes = expression(false); expect(":"); - return as("conditional", expr, yes, expression(false)); + return as("conditional", expr, yes, expression(false, no_in)); } return expr; }; function is_assignable(expr) { - switch (expr[0]) { + if (!exigent_mode) return true; + switch (expr[0]+"") { case "dot": case "sub": + case "new": + case "call": return true; case "name": return expr[1] != "this"; } }; - function maybe_assign() { - var left = maybe_conditional(), val = S.token.value; + function maybe_assign(no_in) { + var left = maybe_conditional(no_in), val = S.token.value; if (is("operator") && HOP(ASSIGNMENT, val)) { if (is_assignable(left)) { next(); - return as("assign", ASSIGNMENT[val], left, maybe_assign()); + return as("assign", ASSIGNMENT[val], left, maybe_assign(no_in)); } croak("Invalid assignment"); } return left; }; - function expression(commas) { + var expression = maybe_embed_tokens(function(commas, no_in) { if (arguments.length == 0) commas = true; - var expr = maybe_assign(); + var expr = maybe_assign(no_in); if (commas && is("punc", ",")) { next(); - return as("seq", expr, expression()); + return as("seq", expr, expression(true, no_in)); } return expr; - }; + }); function in_loop(cont) { try { @@ -1204,7 +1315,7 @@ function array_to_hash(a) { }; function slice(a, start) { - return Array.prototype.slice.call(a, start == null ? 0 : start); + return Array.prototype.slice.call(a, start || 0); }; function characters(str) { @@ -1213,7 +1324,7 @@ function characters(str) { function member(name, array) { for (var i = array.length; --i >= 0;) - if (array[i] === name) + if (array[i] == name) return true; return false; }; @@ -1222,6 +1333,8 @@ function HOP(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }; +var warn = function() {}; + /* -----[ Exports ]----- */ exports.tokenizer = tokenizer; @@ -1237,3 +1350,6 @@ exports.KEYWORDS = KEYWORDS; exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN; exports.OPERATORS = OPERATORS; exports.is_alphanumeric_char = is_alphanumeric_char; +exports.set_logger = function(logger) { + warn = logger; +}; \ No newline at end of file diff --git a/build/lib/process.js b/build/lib/process.js index edcf599d..8c8963d1 100644 --- a/build/lib/process.js +++ b/build/lib/process.js @@ -10,14 +10,13 @@ Exported functions: - - ast_mangle(ast, include_toplevel) -- mangles the - variable/function names in the AST. Returns an AST. Pass true - as second argument to mangle toplevel names too. + - ast_mangle(ast, options) -- mangles the variable/function names + in the AST. Returns an AST. - ast_squeeze(ast) -- employs various optimizations to make the final generated code even smaller. Returns an AST. - - gen_code(ast, beautify) -- generates JS code from the AST. Pass + - gen_code(ast, options) -- generates JS code from the AST. Pass true (or an object, see the code for some options) as second argument to get "pretty" (indented) code. @@ -67,141 +66,145 @@ var jsp = require("./parse-js"), /* -----[ helper for AST traversal ]----- */ -function ast_walker(ast) { +function ast_walker() { function _vardefs(defs) { - return MAP(defs, function(def){ + return [ this[0], MAP(defs, function(def){ var a = [ def[0] ]; if (def.length > 1) a[1] = walk(def[1]); return a; - }); + }) ]; + }; + function _block(statements) { + var out = [ this[0] ]; + if (statements != null) + out.push(MAP(statements, walk)); + return out; }; var walkers = { "string": function(str) { - return [ "string", str ]; + return [ this[0], str ]; }, "num": function(num) { - return [ "num", num ]; + return [ this[0], num ]; }, "name": function(name) { - return [ "name", name ]; + return [ this[0], name ]; }, "toplevel": function(statements) { - return [ "toplevel", MAP(statements, walk) ]; - }, - "block": function(statements) { - var out = [ "block" ]; - if (statements != null) - out.push(MAP(statements, walk)); - return out; - }, - "var": function(defs) { - return [ "var", _vardefs(defs) ]; - }, - "const": function(defs) { - return [ "const", _vardefs(defs) ]; + return [ this[0], MAP(statements, walk) ]; }, + "block": _block, + "splice": _block, + "var": _vardefs, + "const": _vardefs, "try": function(t, c, f) { return [ - "try", + this[0], MAP(t, walk), c != null ? [ c[0], MAP(c[1], walk) ] : null, f != null ? MAP(f, walk) : null ]; }, "throw": function(expr) { - return [ "throw", walk(expr) ]; + return [ this[0], walk(expr) ]; }, "new": function(ctor, args) { - return [ "new", walk(ctor), MAP(args, walk) ]; + return [ this[0], walk(ctor), MAP(args, walk) ]; }, "switch": function(expr, body) { - return [ "switch", walk(expr), MAP(body, function(branch){ + return [ this[0], walk(expr), MAP(body, function(branch){ return [ branch[0] ? walk(branch[0]) : null, MAP(branch[1], walk) ]; }) ]; }, "break": function(label) { - return [ "break", label ]; + return [ this[0], label ]; }, "continue": function(label) { - return [ "continue", label ]; + return [ this[0], label ]; }, "conditional": function(cond, t, e) { - return [ "conditional", walk(cond), walk(t), walk(e) ]; + return [ this[0], walk(cond), walk(t), walk(e) ]; }, "assign": function(op, lvalue, rvalue) { - return [ "assign", op, walk(lvalue), walk(rvalue) ]; + return [ this[0], op, walk(lvalue), walk(rvalue) ]; }, "dot": function(expr) { - return [ "dot", walk(expr) ].concat(slice(arguments, 1)); + return [ this[0], walk(expr) ].concat(slice(arguments, 1)); }, "call": function(expr, args) { - return [ "call", walk(expr), MAP(args, walk) ]; + return [ this[0], walk(expr), MAP(args, walk) ]; }, "function": function(name, args, body) { - return [ "function", name, args.slice(), MAP(body, walk) ]; + return [ this[0], name, args.slice(), MAP(body, walk) ]; + }, + "debugger": function() { + return [ this[0] ]; }, "defun": function(name, args, body) { - return [ "defun", name, args.slice(), MAP(body, walk) ]; + return [ this[0], name, args.slice(), MAP(body, walk) ]; }, "if": function(conditional, t, e) { - return [ "if", walk(conditional), walk(t), walk(e) ]; + return [ this[0], walk(conditional), walk(t), walk(e) ]; }, "for": function(init, cond, step, block) { - return [ "for", walk(init), walk(cond), walk(step), walk(block) ]; + return [ this[0], walk(init), walk(cond), walk(step), walk(block) ]; }, - "for-in": function(has_var, key, hash, block) { - return [ "for-in", has_var, key, walk(hash), walk(block) ]; + "for-in": function(vvar, key, hash, block) { + return [ this[0], walk(vvar), walk(key), walk(hash), walk(block) ]; }, "while": function(cond, block) { - return [ "while", walk(cond), walk(block) ]; + return [ this[0], walk(cond), walk(block) ]; }, "do": function(cond, block) { - return [ "do", walk(cond), walk(block) ]; + return [ this[0], walk(cond), walk(block) ]; }, "return": function(expr) { - return [ "return", walk(expr) ]; + return [ this[0], walk(expr) ]; }, "binary": function(op, left, right) { - return [ "binary", op, walk(left), walk(right) ]; + return [ this[0], op, walk(left), walk(right) ]; }, "unary-prefix": function(op, expr) { - return [ "unary-prefix", op, walk(expr) ]; + return [ this[0], op, walk(expr) ]; }, "unary-postfix": function(op, expr) { - return [ "unary-postfix", op, walk(expr) ]; + return [ this[0], op, walk(expr) ]; }, "sub": function(expr, subscript) { - return [ "sub", walk(expr), walk(subscript) ]; + return [ this[0], walk(expr), walk(subscript) ]; }, "object": function(props) { - return [ "object", MAP(props, function(p){ + return [ this[0], MAP(props, function(p){ return p.length == 2 ? [ p[0], walk(p[1]) ] : [ p[0], walk(p[1]), p[2] ]; // get/set-ter }) ]; }, "regexp": function(rx, mods) { - return [ "regexp", rx, mods ]; + return [ this[0], rx, mods ]; }, "array": function(elements) { - return [ "array", MAP(elements, walk) ]; + return [ this[0], MAP(elements, walk) ]; }, "stat": function(stat) { - return [ "stat", walk(stat) ]; + return [ this[0], walk(stat) ]; }, "seq": function() { - return [ "seq" ].concat(MAP(slice(arguments), walk)); + return [ this[0] ].concat(MAP(slice(arguments), walk)); }, "label": function(name, block) { - return [ "label", name, walk(block) ]; + return [ this[0], name, walk(block) ]; }, "with": function(expr, block) { - return [ "with", walk(expr), walk(block) ]; + return [ this[0], walk(expr), walk(block) ]; }, "atom": function(name) { - return [ "atom", name ]; + return [ this[0], name ]; + }, + "directive": function(dir) { + return [ this[0], dir ]; } }; @@ -226,6 +229,17 @@ function ast_walker(ast) { } }; + function dive(ast) { + if (ast == null) + return null; + try { + stack.push(ast); + return walkers[ast[0]].apply(ast, ast.slice(1)); + } finally { + stack.pop(); + } + }; + function with_walkers(walkers, cont){ var save = {}, i; for (i in walkers) if (HOP(walkers, i)) { @@ -242,6 +256,7 @@ function ast_walker(ast) { return { walk: walk, + dive: dive, with_walkers: with_walkers, parent: function() { return stack[stack.length - 2]; // last one is current node @@ -260,8 +275,8 @@ function Scope(parent) { this.rev_mangled = {}; // reverse lookup (mangled => orig.name) this.cname = -1; // current mangled name this.refs = {}; // names referenced from this scope - this.uses_with = false; // will become TRUE if eval() is detected in this or any subscopes - this.uses_eval = false; // will become TRUE if with() is detected in this or any subscopes + this.uses_with = false; // will become TRUE if with() is detected in this or any subscopes + this.uses_eval = false; // will become TRUE if eval() is detected in this or any subscopes this.parent = parent; // parent scope this.children = []; // sub-scopes if (parent) { @@ -273,12 +288,13 @@ function Scope(parent) { }; var base54 = (function(){ - var DIGITS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_"; + var DIGITS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; return function(num) { - var ret = ""; + var ret = "", base = 54; do { - ret = DIGITS.charAt(num % 54) + ret; - num = Math.floor(num / 54); + ret += DIGITS.charAt(num % base); + num = Math.floor(num / base); + base = 64; } while (num > 0); return ret; }; @@ -342,20 +358,27 @@ Scope.prototype = { return m; } }, + set_mangle: function(name, m) { + this.rev_mangled[m] = name; + return this.mangled[name] = m; + }, get_mangled: function(name, newMangle) { if (this.uses_eval || this.uses_with) return name; // no mangle if eval or with is in use var s = this.has(name); if (!s) return name; // not in visible scope, no mangle if (HOP(s.mangled, name)) return s.mangled[name]; // already mangled in this scope if (!newMangle) return name; // not found and no mangling requested - - var m = s.next_mangled(); - s.rev_mangled[m] = name; - return s.mangled[name] = m; + return s.set_mangle(name, s.next_mangled()); }, - define: function(name) { - if (name != null) - return this.names[name] = name; + references: function(name) { + return name && !this.parent || this.uses_with || this.uses_eval || this.refs[name]; + }, + define: function(name, type) { + if (name != null) { + if (type == "var" || !HOP(this.names, name)) + this.names[name] = type || "var"; + return name; + } } }; @@ -367,14 +390,15 @@ function ast_add_scope(ast) { function with_new_scope(cont) { current_scope = new Scope(current_scope); + current_scope.labels = new Scope(); var ret = current_scope.body = cont(); ret.scope = current_scope; current_scope = current_scope.parent; return ret; }; - function define(name) { - return current_scope.define(name); + function define(name, type) { + return current_scope.define(name, type); }; function reference(name) { @@ -382,32 +406,47 @@ function ast_add_scope(ast) { }; function _lambda(name, args, body) { - return [ this[0], define(name), args, with_new_scope(function(){ - MAP(args, define); + var is_defun = this[0] == "defun"; + return [ this[0], is_defun ? define(name, "defun") : name, args, with_new_scope(function(){ + if (!is_defun) define(name, "lambda"); + MAP(args, function(name){ define(name, "arg") }); return MAP(body, walk); })]; }; + function _vardefs(type) { + return function(defs) { + MAP(defs, function(d){ + define(d[0], type); + if (d[1]) reference(d[0]); + }); + }; + }; + + function _breacont(label) { + if (label) + current_scope.labels.refs[label] = true; + }; + return with_new_scope(function(){ // process AST var ret = w.with_walkers({ "function": _lambda, "defun": _lambda, + "label": function(name, stat) { current_scope.labels.define(name) }, + "break": _breacont, + "continue": _breacont, "with": function(expr, block) { for (var s = current_scope; s; s = s.parent) s.uses_with = true; }, - "var": function(defs) { - MAP(defs, function(d){ define(d[0]) }); - }, - "const": function(defs) { - MAP(defs, function(d){ define(d[0]) }); - }, + "var": _vardefs("var"), + "const": _vardefs("const"), "try": function(t, c, f) { if (c != null) return [ - "try", + this[0], MAP(t, walk), - [ define(c[0]), MAP(c[1], walk) ], + [ define(c[0], "catch"), MAP(c[1], walk) ], f != null ? MAP(f, walk) : null ]; }, @@ -415,10 +454,6 @@ function ast_add_scope(ast) { if (name == "eval") having_eval.push(current_scope); reference(name); - }, - "for-in": function(has_var, name) { - if (has_var) define(name); - else reference(name); } }, function(){ return walk(ast); @@ -461,26 +496,58 @@ function ast_add_scope(ast) { /* -----[ mangle names ]----- */ -function ast_mangle(ast, do_toplevel) { +function ast_mangle(ast, options) { var w = ast_walker(), walk = w.walk, scope; + options = options || {}; function get_mangled(name, newMangle) { - if (!do_toplevel && !scope.parent) return name; // don't mangle toplevel + if (!options.toplevel && !scope.parent) return name; // don't mangle toplevel + if (options.except && member(name, options.except)) + return name; return scope.get_mangled(name, newMangle); }; + function get_define(name) { + if (options.defines) { + // we always lookup a defined symbol for the current scope FIRST, so declared + // vars trump a DEFINE symbol, but if no such var is found, then match a DEFINE value + if (!scope.has(name)) { + if (HOP(options.defines, name)) { + return options.defines[name]; + } + } + return null; + } + }; + function _lambda(name, args, body) { - if (name) name = get_mangled(name); + if (!options.no_functions) { + var is_defun = this[0] == "defun", extra; + if (name) { + if (is_defun) name = get_mangled(name); + else if (body.scope.references(name)) { + extra = {}; + if (!(scope.uses_eval || scope.uses_with)) + name = extra[name] = scope.next_mangled(); + else + extra[name] = name; + } + else name = null; + } + } body = with_scope(body.scope, function(){ args = MAP(args, function(name){ return get_mangled(name) }); return MAP(body, walk); - }); + }, extra); return [ this[0], name, args, body ]; }; - function with_scope(s, cont) { + function with_scope(s, cont, extra) { var _scope = scope; scope = s; + if (extra) for (var i in extra) if (HOP(extra, i)) { + s.set_mangle(i, extra[i]); + } for (var i in s.names) if (HOP(s.names, i)) { get_mangled(i, true); } @@ -491,9 +558,13 @@ function ast_mangle(ast, do_toplevel) { }; function _vardefs(defs) { - return MAP(defs, function(d){ + return [ this[0], MAP(defs, function(d){ return [ get_mangled(d[0]), walk(d[1]) ]; - }); + }) ]; + }; + + function _breacont(label) { + if (label) return [ this[0], scope.labels.get_mangled(label) ]; }; return w.with_walkers({ @@ -510,28 +581,35 @@ function ast_mangle(ast, do_toplevel) { } return ast; }, - "var": function(defs) { - return [ "var", _vardefs(defs) ]; - }, - "const": function(defs) { - return [ "const", _vardefs(defs) ]; + "label": function(label, stat) { + if (scope.labels.refs[label]) return [ + this[0], + scope.labels.get_mangled(label, true), + walk(stat) + ]; + return walk(stat); }, + "break": _breacont, + "continue": _breacont, + "var": _vardefs, + "const": _vardefs, "name": function(name) { - return [ "name", get_mangled(name) ]; + return get_define(name) || [ this[0], get_mangled(name) ]; }, "try": function(t, c, f) { - return [ "try", + return [ this[0], MAP(t, walk), c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null, f != null ? MAP(f, walk) : null ]; }, "toplevel": function(body) { - return with_scope(this.scope, function(){ - return [ "toplevel", MAP(body, walk) ]; + var self = this; + return with_scope(self.scope, function(){ + return [ self[0], MAP(body, walk) ]; }); }, - "for-in": function(has_var, name, obj, stat) { - return [ "for-in", has_var, get_mangled(name), walk(obj), walk(stat) ]; + "directive": function() { + return MAP.at_top(this); } }, function() { return walk(ast_add_scope(ast)); @@ -562,160 +640,439 @@ function last_stat(b) { } function aborts(t) { - if (t) { - t = last_stat(t); - if (t[0] == "return" || t[0] == "break" || t[0] == "continue" || t[0] == "throw") - return true; + if (t) switch (last_stat(t)[0]) { + case "return": + case "break": + case "continue": + case "throw": + return true; } }; -function negate(c) { - var not_c = [ "unary-prefix", "!", c ]; - switch (c[0]) { - case "unary-prefix": - return c[1] == "!" ? c[2] : not_c; - case "binary": - var op = c[1], left = c[2], right = c[3]; - switch (op) { - case "<=": return [ "binary", ">", left, right ]; - case "<": return [ "binary", ">=", left, right ]; - case ">=": return [ "binary", "<", left, right ]; - case ">": return [ "binary", "<=", left, right ]; - case "==": return [ "binary", "!=", left, right ]; - case "!=": return [ "binary", "==", left, right ]; - case "===": return [ "binary", "!==", left, right ]; - case "!==": return [ "binary", "===", left, right ]; - case "&&": return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]); - case "||": return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]); - } - break; - } - return not_c; -}; +function boolean_expr(expr) { + return ( (expr[0] == "unary-prefix" + && member(expr[1], [ "!", "delete" ])) || -function make_conditional(c, t, e) { - if (c[0] == "unary-prefix" && c[1] == "!") { - return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ]; - } else { - return e ? [ "conditional", c, t, e ] : [ "binary", "&&", c, t ]; - } + (expr[0] == "binary" + && member(expr[1], [ "in", "instanceof", "==", "!=", "===", "!==", "<", "<=", ">=", ">" ])) || + + (expr[0] == "binary" + && member(expr[1], [ "&&", "||" ]) + && boolean_expr(expr[2]) + && boolean_expr(expr[3])) || + + (expr[0] == "conditional" + && boolean_expr(expr[2]) + && boolean_expr(expr[3])) || + + (expr[0] == "assign" + && expr[1] === true + && boolean_expr(expr[3])) || + + (expr[0] == "seq" + && boolean_expr(expr[expr.length - 1])) + ); }; function empty(b) { return !b || (b[0] == "block" && (!b[1] || b[1].length == 0)); }; -function ast_squeeze(ast, options) { - options = defaults(options, { - make_seqs : true, - dead_code : true, - no_warnings : false, - extra : false - }); - - var w = ast_walker(), walk = w.walk, scope; +function is_string(node) { + return (node[0] == "string" || + node[0] == "unary-prefix" && node[1] == "typeof" || + node[0] == "binary" && node[1] == "+" && + (is_string(node[2]) || is_string(node[3]))); +}; - function with_scope(s, cont) { - var _scope = scope; - scope = s; - var ret = cont(); - ret.scope = s; - scope = _scope; - return ret; +var when_constant = (function(){ + + var $NOT_CONSTANT = {}; + + // this can only evaluate constant expressions. If it finds anything + // not constant, it throws $NOT_CONSTANT. + function evaluate(expr) { + switch (expr[0]) { + case "string": + case "num": + return expr[1]; + case "name": + case "atom": + switch (expr[1]) { + case "true": return true; + case "false": return false; + case "null": return null; + } + break; + case "unary-prefix": + switch (expr[1]) { + case "!": return !evaluate(expr[2]); + case "typeof": return typeof evaluate(expr[2]); + case "~": return ~evaluate(expr[2]); + case "-": return -evaluate(expr[2]); + case "+": return +evaluate(expr[2]); + } + break; + case "binary": + var left = expr[2], right = expr[3]; + switch (expr[1]) { + case "&&" : return evaluate(left) && evaluate(right); + case "||" : return evaluate(left) || evaluate(right); + case "|" : return evaluate(left) | evaluate(right); + case "&" : return evaluate(left) & evaluate(right); + case "^" : return evaluate(left) ^ evaluate(right); + case "+" : return evaluate(left) + evaluate(right); + case "*" : return evaluate(left) * evaluate(right); + case "/" : return evaluate(left) / evaluate(right); + case "%" : return evaluate(left) % evaluate(right); + case "-" : return evaluate(left) - evaluate(right); + case "<<" : return evaluate(left) << evaluate(right); + case ">>" : return evaluate(left) >> evaluate(right); + case ">>>" : return evaluate(left) >>> evaluate(right); + case "==" : return evaluate(left) == evaluate(right); + case "===" : return evaluate(left) === evaluate(right); + case "!=" : return evaluate(left) != evaluate(right); + case "!==" : return evaluate(left) !== evaluate(right); + case "<" : return evaluate(left) < evaluate(right); + case "<=" : return evaluate(left) <= evaluate(right); + case ">" : return evaluate(left) > evaluate(right); + case ">=" : return evaluate(left) >= evaluate(right); + case "in" : return evaluate(left) in evaluate(right); + case "instanceof" : return evaluate(left) instanceof evaluate(right); + } + } + throw $NOT_CONSTANT; }; - function is_constant(node) { - return node[0] == "string" || node[0] == "num"; + return function(expr, yes, no) { + try { + var val = evaluate(expr), ast; + switch (typeof val) { + case "string": ast = [ "string", val ]; break; + case "number": ast = [ "num", val ]; break; + case "boolean": ast = [ "name", String(val) ]; break; + default: + if (val === null) { ast = [ "atom", "null" ]; break; } + throw new Error("Can't handle constant of type: " + (typeof val)); + } + return yes.call(expr, ast, val); + } catch(ex) { + if (ex === $NOT_CONSTANT) { + if (expr[0] == "binary" + && (expr[1] == "===" || expr[1] == "!==") + && ((is_string(expr[2]) && is_string(expr[3])) + || (boolean_expr(expr[2]) && boolean_expr(expr[3])))) { + expr[1] = expr[1].substr(0, 2); + } + else if (no && expr[0] == "binary" + && (expr[1] == "||" || expr[1] == "&&")) { + // the whole expression is not constant but the lval may be... + try { + var lval = evaluate(expr[2]); + expr = ((expr[1] == "&&" && (lval ? expr[3] : lval)) || + (expr[1] == "||" && (lval ? lval : expr[3])) || + expr); + } catch(ex2) { + // IGNORE... lval is not constant + } + } + return no ? no.call(expr, expr) : null; + } + else throw ex; + } }; - function find_first_execute(node) { - if (!node) - return false; +})(); - switch (node[0]) { - case "num": - case "string": - case "name": - return node; - case "call": - case "conditional": - case "for": - case "if": - case "new": - case "return": - case "stat": - case "switch": - case "throw": - return find_first_execute(node[1]); - case "binary": - return find_first_execute(node[2]); - case "assign": - if (node[1] === true) - return find_first_execute(node[3]); - break; - case "var": - if (node[1][0].length > 1) - return find_first_execute(node[1][0][1]); - break; - } - return null; - } +function warn_unreachable(ast) { + if (!empty(ast)) + warn("Dropping unreachable code: " + gen_code(ast, true)); +}; - function find_assign_recursive(p, v) { - if (p[0] == "assign" && p[1] != true || p[0] == "unary-prefix") { - if (p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1]) - return true; - return false; +function prepare_ifs(ast) { + var w = ast_walker(), walk = w.walk; + // In this first pass, we rewrite ifs which abort with no else with an + // if-else. For example: + // + // if (x) { + // blah(); + // return y; + // } + // foobar(); + // + // is rewritten into: + // + // if (x) { + // blah(); + // return y; + // } else { + // foobar(); + // } + function redo_if(statements) { + statements = MAP(statements, walk); + + for (var i = 0; i < statements.length; ++i) { + var fi = statements[i]; + if (fi[0] != "if") continue; + + if (fi[3] && walk(fi[3])) continue; + + var t = walk(fi[2]); + if (!aborts(t)) continue; + + var conditional = walk(fi[1]); + + var e_body = redo_if(statements.slice(i + 1)); + var e = e_body.length == 1 ? e_body[0] : [ "block", e_body ]; + + return statements.slice(0, i).concat([ [ + fi[0], // "if" + conditional, // conditional + t, // then + e // else + ] ]); } - if (p[0] != "assign" || p[1] !== true) - return false; + return statements; + }; - if ((is_constant(p[3]) && p[3][0] == v[0] && p[3][1] == v[1]) || - (p[3][0] == "name" && v[0] == "name" && p[3][1] == v[1]) || - (p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1])) - return true; + function redo_if_lambda(name, args, body) { + body = redo_if(body); + return [ this[0], name, args, body ]; + }; - return find_assign_recursive(p[3], v); + function redo_if_block(statements) { + return [ this[0], statements != null ? redo_if(statements) : null ]; }; - function rmblock(block) { - if (block != null && block[0] == "block" && block[1] && block[1].length == 1) - block = block[1][0]; - return block; + return w.with_walkers({ + "defun": redo_if_lambda, + "function": redo_if_lambda, + "block": redo_if_block, + "splice": redo_if_block, + "toplevel": function(statements) { + return [ this[0], redo_if(statements) ]; + }, + "try": function(t, c, f) { + return [ + this[0], + redo_if(t), + c != null ? [ c[0], redo_if(c[1]) ] : null, + f != null ? redo_if(f) : null + ]; + } + }, function() { + return walk(ast); + }); +}; + +function for_side_effects(ast, handler) { + var w = ast_walker(), walk = w.walk; + var $stop = {}, $restart = {}; + function stop() { throw $stop }; + function restart() { throw $restart }; + function found(){ return handler.call(this, this, w, stop, restart) }; + function unary(op) { + if (op == "++" || op == "--") + return found.apply(this, arguments); }; + return w.with_walkers({ + "try": found, + "throw": found, + "return": found, + "new": found, + "switch": found, + "break": found, + "continue": found, + "assign": found, + "call": found, + "if": found, + "for": found, + "for-in": found, + "while": found, + "do": found, + "return": found, + "unary-prefix": unary, + "unary-postfix": unary, + "defun": found + }, function(){ + while (true) try { + walk(ast); + break; + } catch(ex) { + if (ex === $stop) break; + if (ex === $restart) continue; + throw ex; + } + }); +}; - function clone(obj) { - if (obj && obj.constructor == Array) - return MAP(obj, clone); - return obj; +function ast_lift_variables(ast) { + var w = ast_walker(), walk = w.walk, scope; + function do_body(body, env) { + var _scope = scope; + scope = env; + body = MAP(body, walk); + var hash = {}, names = MAP(env.names, function(type, name){ + if (type != "var") return MAP.skip; + if (!env.references(name)) return MAP.skip; + hash[name] = true; + return [ name ]; + }); + if (names.length > 0) { + // looking for assignments to any of these variables. + // we can save considerable space by moving the definitions + // in the var declaration. + for_side_effects([ "block", body ], function(ast, walker, stop, restart) { + if (ast[0] == "assign" + && ast[1] === true + && ast[2][0] == "name" + && HOP(hash, ast[2][1])) { + // insert the definition into the var declaration + for (var i = names.length; --i >= 0;) { + if (names[i][0] == ast[2][1]) { + if (names[i][1]) // this name already defined, we must stop + stop(); + names[i][1] = ast[3]; // definition + names.push(names.splice(i, 1)[0]); + break; + } + } + // remove this assignment from the AST. + var p = walker.parent(); + if (p[0] == "seq") { + var a = p[2]; + a.unshift(0, p.length); + p.splice.apply(p, a); + } + else if (p[0] == "stat") { + p.splice(0, p.length, "block"); // empty statement + } + else { + stop(); + } + restart(); + } + stop(); + }); + body.unshift([ "var", names ]); + } + scope = _scope; + return body; }; + function _vardefs(defs) { + var ret = null; + for (var i = defs.length; --i >= 0;) { + var d = defs[i]; + if (!d[1]) continue; + d = [ "assign", true, [ "name", d[0] ], d[1] ]; + if (ret == null) ret = d; + else ret = [ "seq", d, ret ]; + } + if (ret == null) { + if (w.parent()[0] == "for-in") + return [ "name", defs[0][0] ]; + return MAP.skip; + } + return [ "stat", ret ]; + }; + function _toplevel(body) { + return [ this[0], do_body(body, this.scope) ]; + }; + return w.with_walkers({ + "function": function(name, args, body){ + for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);) + args.pop(); + if (!body.scope.references(name)) name = null; + return [ this[0], name, args, do_body(body, body.scope) ]; + }, + "defun": function(name, args, body){ + if (!scope.references(name)) return MAP.skip; + for (var i = args.length; --i >= 0 && !body.scope.references(args[i]);) + args.pop(); + return [ this[0], name, args, do_body(body, body.scope) ]; + }, + "var": _vardefs, + "toplevel": _toplevel + }, function(){ + return walk(ast_add_scope(ast)); + }); +}; - function make_seq_to_statements(node) { - if (node[0] != "seq") { - switch (node[0]) { - case "var": - case "const": - return [ node ]; - default: - return [ [ "stat", node ] ]; +function ast_squeeze(ast, options) { + options = defaults(options, { + make_seqs : true, + dead_code : true, + no_warnings : false, + keep_comps : true + }); + + var w = ast_walker(), walk = w.walk; + + function negate(c) { + var not_c = [ "unary-prefix", "!", c ]; + switch (c[0]) { + case "unary-prefix": + return c[1] == "!" && boolean_expr(c[2]) ? c[2] : not_c; + case "seq": + c = slice(c); + c[c.length - 1] = negate(c[c.length - 1]); + return c; + case "conditional": + return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]); + case "binary": + var op = c[1], left = c[2], right = c[3]; + if (!options.keep_comps) switch (op) { + case "<=" : return [ "binary", ">", left, right ]; + case "<" : return [ "binary", ">=", left, right ]; + case ">=" : return [ "binary", "<", left, right ]; + case ">" : return [ "binary", "<=", left, right ]; } + switch (op) { + case "==" : return [ "binary", "!=", left, right ]; + case "!=" : return [ "binary", "==", left, right ]; + case "===" : return [ "binary", "!==", left, right ]; + case "!==" : return [ "binary", "===", left, right ]; + case "&&" : return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]); + case "||" : return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]); + } + break; } + return not_c; + }; - var ret = []; - for (var i = 1; i < node.length; i++) - ret.push.apply(ret, make_seq_to_statements(node[i])); + function make_conditional(c, t, e) { + var make_real_conditional = function() { + if (c[0] == "unary-prefix" && c[1] == "!") { + return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ]; + } else { + return e ? best_of( + [ "conditional", c, t, e ], + [ "conditional", negate(c), e, t ] + ) : [ "binary", "&&", c, t ]; + } + }; + // shortcut the conditional if the expression has a constant value + return when_constant(c, function(ast, val){ + warn_unreachable(val ? e : t); + return (val ? t : e); + }, make_real_conditional); + }; - return ret; + function rmblock(block) { + if (block != null && block[0] == "block" && block[1]) { + if (block[1].length == 1) + block = block[1][0]; + else if (block[1].length == 0) + block = [ "block" ]; + } + return block; }; function _lambda(name, args, body) { - return [ this[0], name, args, with_scope(body.scope, function(){ - return tighten(MAP(body, walk), "lambda"); - }) ]; + return [ this[0], name, args, tighten(body, "lambda") ]; }; - // we get here for blocks that have been already transformed. // this function does a few things: // 1. discard useless blocks // 2. join consecutive var declarations @@ -723,6 +1080,8 @@ function ast_squeeze(ast, options) { // 4. transform consecutive statements using the comma operator // 5. if block_type == "lambda" and it detects constructs like if(foo) return ... - rewrite like if (!foo) { ... } function tighten(statements, block_type) { + statements = MAP(statements, walk); + statements = statements.reduce(function(a, stat){ if (stat[0] == "block") { if (stat[1]) { @@ -734,64 +1093,6 @@ function ast_squeeze(ast, options) { return a; }, []); - if (options.extra) { - // Detightening things. We do this because then we can assume that the - // statements are structured in a specific way. - statements = (function(a, prev) { - statements.forEach(function(cur) { - switch (cur[0]) { - case "for": - if (cur[1] != null) { - a.push.apply(a, make_seq_to_statements(cur[1])); - cur[1] = null; - } - a.push(cur); - break; - case "stat": - var stats = make_seq_to_statements(cur[1]); - stats.forEach(function(s) { - if (s[1][0] == "unary-postfix") - s[1][0] = "unary-prefix"; - }); - a.push.apply(a, stats); - break; - default: - a.push(cur); - } - }); - return a; - })([]); - - statements = (function(a, prev) { - statements.forEach(function(cur) { - if (!(prev && prev[0] == "stat")) { - a.push(cur); - prev = cur; - return; - } - - var p = prev[1]; - var c = find_first_execute(cur); - if (c && find_assign_recursive(p, c)) { - var old_cur = clone(cur); - c.splice(0, c.length); - c.push.apply(c, p); - var tmp_cur = best_of(cur, [ "toplevel", [ prev, old_cur ] ]); - if (tmp_cur == cur) { - a[a.length -1] = cur; - } else { - cur = old_cur; - a.push(cur); - } - } else { - a.push(cur); - } - prev = cur; - }); - return a; - })([]); - } - statements = (function(a, prev){ statements.forEach(function(cur){ if (prev && ((cur[0] == "var" && prev[0] == "var") || @@ -808,11 +1109,21 @@ function ast_squeeze(ast, options) { if (options.dead_code) statements = (function(a, has_quit){ statements.forEach(function(st){ if (has_quit) { - if (member(st[0], [ "function", "defun" , "var", "const" ])) { + if (st[0] == "function" || st[0] == "defun") { + a.push(st); + } + else if (st[0] == "var" || st[0] == "const") { + if (!options.no_warnings) + warn("Variables declared in unreachable code"); + st[1] = MAP(st[1], function(def){ + if (def[1] && !options.no_warnings) + warn_unreachable([ "assign", true, [ "name", def[0] ], def[1] ]); + return [ def[0] ]; + }); a.push(st); } else if (!options.no_warnings) - warn("Removing unreachable code: " + gen_code(st, true)); + warn_unreachable(st); } else { a.push(st); @@ -832,48 +1143,69 @@ function ast_squeeze(ast, options) { prev = cur; } }); + if (a.length >= 2 + && a[a.length-2][0] == "stat" + && (a[a.length-1][0] == "return" || a[a.length-1][0] == "throw") + && a[a.length-1][1]) + { + a.splice(a.length - 2, 2, + [ a[a.length-1][0], + [ "seq", a[a.length-2][1], a[a.length-1][1] ]]); + } return a; })([]); - if (options.extra) { - statements = (function(a, prev){ - statements.forEach(function(cur){ - var replaced = false; - if (prev && cur[0] == "for" && cur[1] == null && (prev[0] == "var" || prev[0] == "const" || prev[0] == "stat")) { - cur[1] = prev; - a[a.length - 1] = cur; - } else { - a.push(cur); - } - prev = cur; - }); - return a; - })([]); - } - - if (block_type == "lambda") statements = (function(i, a, stat){ - while (i < statements.length) { - stat = statements[i++]; - if (stat[0] == "if" && !stat[3]) { - if (stat[2][0] == "return" && stat[2][1] == null) { - a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ])); - break; - } - var last = last_stat(stat[2]); - if (last[0] == "return" && last[1] == null) { - a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ])); - break; - } - } - a.push(stat); - } - return a; - })(0, []); + // this increases jQuery by 1K. Probably not such a good idea after all.. + // part of this is done in prepare_ifs anyway. + // if (block_type == "lambda") statements = (function(i, a, stat){ + // while (i < statements.length) { + // stat = statements[i++]; + // if (stat[0] == "if" && !stat[3]) { + // if (stat[2][0] == "return" && stat[2][1] == null) { + // a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ])); + // break; + // } + // var last = last_stat(stat[2]); + // if (last[0] == "return" && last[1] == null) { + // a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ])); + // break; + // } + // } + // a.push(stat); + // } + // return a; + // })(0, []); return statements; }; function make_if(c, t, e) { + return when_constant(c, function(ast, val){ + if (val) { + t = walk(t); + warn_unreachable(e); + return t || [ "block" ]; + } else { + e = walk(e); + warn_unreachable(t); + return e || [ "block" ]; + } + }, function() { + return make_real_if(c, t, e); + }); + }; + + function abort_else(c, t, e) { + var ret = [ [ "if", negate(c), e ] ]; + if (t[0] == "block") { + if (t[1]) ret = ret.concat(t[1]); + } else { + ret.push(t); + } + return walk([ "block", ret ]); + }; + + function make_real_if(c, t, e) { c = walk(c); t = walk(t); e = walk(e); @@ -901,17 +1233,21 @@ function ast_squeeze(ast, options) { if (empty(e) && empty(t)) return [ "stat", c ]; var ret = [ "if", c, t, e ]; - if (t[0] == "stat") { + if (t[0] == "if" && empty(t[3]) && empty(e)) { + ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ])); + } + else if (t[0] == "stat") { if (e) { - if (e[0] == "stat") { + if (e[0] == "stat") ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]); - } + else if (aborts(e)) + ret = abort_else(c, t, e); } else { ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]); } } - else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw")) { + else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw") && t[1] && e[1]) { ret = best_of(ret, [ t[0], make_conditional(c, t[1], e[1] ) ]); } else if (e && aborts(t)) { @@ -925,36 +1261,40 @@ function ast_squeeze(ast, options) { ret = walk([ "block", ret ]); } else if (t && aborts(e)) { - ret = [ [ "if", negate(c), e ] ]; - if (t[0] == "block") { - if (t[1]) ret = ret.concat(t[1]); - } else { - ret.push(t); - } - ret = walk([ "block", ret ]); + ret = abort_else(c, t, e); } return ret; }; + function _do_while(cond, body) { + return when_constant(cond, function(cond, val){ + if (!val) { + warn_unreachable(body); + return [ "block" ]; + } else { + return [ "for", null, null, null, walk(body) ]; + } + }); + }; + return w.with_walkers({ "sub": function(expr, subscript) { if (subscript[0] == "string") { var name = subscript[1]; - if (is_identifier(name)) { + if (is_identifier(name)) return [ "dot", walk(expr), name ]; - } + else if (/^[1-9][0-9]*$/.test(name) || name === "0") + return [ "sub", walk(expr), [ "num", parseInt(name, 10) ] ]; } }, "if": make_if, "toplevel": function(body) { - return [ "toplevel", with_scope(this.scope, function(){ - return tighten(MAP(body, walk)); - }) ]; + return [ "toplevel", tighten(body) ]; }, "switch": function(expr, body) { var last = body.length - 1; return [ "switch", walk(expr), MAP(body, function(branch, i){ - var block = tighten(MAP(branch[1], walk)); + var block = tighten(branch[1]); if (i == last && block.length > 0) { var node = block[block.length - 1]; if (node[0] == "break" && !node[1]) @@ -966,32 +1306,22 @@ function ast_squeeze(ast, options) { "function": _lambda, "defun": _lambda, "block": function(body) { - if (body) return rmblock([ "block", tighten(MAP(body, walk)) ]); + if (body) return rmblock([ "block", tighten(body) ]); }, "binary": function(op, left, right) { - left = walk(left); - right = walk(right); - var best = [ "binary", op, left, right ]; - if (is_constant(right)) { - if (is_constant(left)) { - var val = null; - switch (op) { - case "+": val = left[1] + right[1]; break; - case "*": val = left[1] * right[1]; break; - case "/": val = left[1] / right[1]; break; - case "-": val = left[1] - right[1]; break; - case "<<": val = left[1] << right[1]; break; - case ">>": val = left[1] >> right[1]; break; - case ">>>": val = left[1] >>> right[1]; break; - } - if (val != null) { - best = best_of(best, [ typeof val == "string" ? "string" : "num", val ]); - } - } else if (left[0] == "binary" && left[1] == "+" && left[3][0] == "string") { - best = best_of(best, [ "binary", "+", left[2], [ "string", left[3][1] + right[1] ] ]); - } - } - return best; + return when_constant([ "binary", op, walk(left), walk(right) ], function yes(c){ + return best_of(walk(c), this); + }, function no() { + return function(){ + if(op != "==" && op != "!=") return; + var l = walk(left), r = walk(right); + if(l && l[0] == "unary-prefix" && l[1] == "!" && l[2][0] == "num") + left = ['num', +!l[2][1]]; + else if (r && r[0] == "unary-prefix" && r[1] == "!" && r[2][0] == "num") + right = ['num', +!r[2][1]]; + return ["binary", op, left, right]; + }() || this; + }); }, "conditional": function(c, t, e) { return make_conditional(walk(c), walk(t), walk(e)); @@ -999,22 +1329,19 @@ function ast_squeeze(ast, options) { "try": function(t, c, f) { return [ "try", - tighten(MAP(t, walk)), - c != null ? [ c[0], tighten(MAP(c[1], walk)) ] : null, - f != null ? tighten(MAP(f, walk)) : null + tighten(t), + c != null ? [ c[0], tighten(c[1]) ] : null, + f != null ? tighten(f) : null ]; }, - "unary-prefix": function(op, cond) { - if (op == "!") { - cond = walk(cond); - if (cond[0] == "unary-prefix" && cond[1] == "!") { - var p = w.parent(); - if (p[0] == "unary-prefix" && p[1] == "!") - return cond[2]; - return [ "unary-prefix", "!", cond ]; - } - return best_of(this, negate(cond)); - } + "unary-prefix": function(op, expr) { + expr = walk(expr); + var ret = [ "unary-prefix", op, expr ]; + if (op == "!") + ret = best_of(ret, negate(expr)); + return when_constant(ret, function(ast, val){ + return walk(ast); // it's either true or false, so minifies to !0 or !1 + }, function() { return ret }); }, "name": function(name) { switch (name) { @@ -1022,22 +1349,24 @@ function ast_squeeze(ast, options) { case "false": return [ "unary-prefix", "!", [ "num", 1 ]]; } }, - "new": function(ctor, args) { - if (ctor[0] == "name" && ctor[1] == "Array" && !scope.has("Array")) { - if (args.length != 1) { - return [ "array", args ]; - } else { - return [ "call", [ "name", "Array" ], args ]; - } - } - }, - "call": function(expr, args) { - if (expr[0] == "name" && expr[1] == "Array" && args.length != 1 && !scope.has("Array")) { - return [ "array", args ]; + "while": _do_while, + "assign": function(op, lvalue, rvalue) { + lvalue = walk(lvalue); + rvalue = walk(rvalue); + var okOps = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ]; + if (op === true && lvalue[0] === "name" && rvalue[0] === "binary" && + ~okOps.indexOf(rvalue[1]) && rvalue[2][0] === "name" && + rvalue[2][1] === lvalue[1]) { + return [ this[0], rvalue[1], lvalue, rvalue[3] ] } + return [ this[0], op, lvalue, rvalue ]; } }, function() { - return walk(ast_add_scope(ast)); + for (var i = 0; i < 2; ++i) { + ast = prepare_ifs(ast); + ast = walk(ast); + } + return ast; }); }; @@ -1046,51 +1375,81 @@ function ast_squeeze(ast, options) { var DOT_CALL_NO_PARENS = jsp.array_to_hash([ "name", "array", + "object", "string", "dot", "sub", "call", - "regexp" + "regexp", + "defun" ]); -function make_string(str) { +function make_string(str, ascii_only) { var dq = 0, sq = 0; - str = str.replace(/[\\\b\f\n\r\t\x22\x27]/g, function(s){ + str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){ switch (s) { case "\\": return "\\\\"; case "\b": return "\\b"; case "\f": return "\\f"; case "\n": return "\\n"; case "\r": return "\\r"; - case "\t": return "\\t"; + case "\u2028": return "\\u2028"; + case "\u2029": return "\\u2029"; case '"': ++dq; return '"'; case "'": ++sq; return "'"; + case "\0": return "\\0"; } return s; }); - if (dq > sq) { - return "'" + str.replace(/\x27/g, "\\'") + "'"; - } else { - return '"' + str.replace(/\x22/g, '\\"') + '"'; - } + if (ascii_only) str = to_ascii(str); + if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; + else return '"' + str.replace(/\x22/g, '\\"') + '"'; +}; + +function to_ascii(str) { + return str.replace(/[\u0080-\uffff]/g, function(ch) { + var code = ch.charCodeAt(0).toString(16); + while (code.length < 4) code = "0" + code; + return "\\u" + code; + }); }; -function gen_code(ast, beautify) { - if (beautify) beautify = defaults(beautify, { +var SPLICE_NEEDS_BRACKETS = jsp.array_to_hash([ "if", "while", "do", "for", "for-in", "with" ]); + +function gen_code(ast, options) { + options = defaults(options, { indent_start : 0, indent_level : 4, quote_keys : false, - space_colon : false + space_colon : false, + beautify : false, + ascii_only : false, + inline_script: false }); + var beautify = !!options.beautify; var indentation = 0, newline = beautify ? "\n" : "", space = beautify ? " " : ""; + function encode_string(str) { + var ret = make_string(str, options.ascii_only); + if (options.inline_script) + ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); + return ret; + }; + + function make_name(name) { + name = name.toString(); + if (options.ascii_only) + name = to_ascii(name); + return name; + }; + function indent(line) { if (line == null) line = ""; if (beautify) - line = repeat_string(" ", beautify.indent_start + indentation * beautify.indent_level) + line; + line = repeat_string(" ", options.indent_start + indentation * options.indent_level) + line; return line; }; @@ -1144,7 +1503,7 @@ function gen_code(ast, beautify) { }; function needs_parens(expr) { - if (expr[0] == "function") { + if (expr[0] == "function" || expr[0] == "object") { // dot/call on a literal function requires the // function literal itself to be parenthesized // only if it's the first "thing" in a @@ -1153,12 +1512,11 @@ function gen_code(ast, beautify) { // we're the first in this "seq" and the // parent is "stat", and so on. Messy stuff, // but it worths the trouble. - var a = slice($stack), self = a.pop(), p = a.pop(); + var a = slice(w.stack()), self = a.pop(), p = a.pop(); while (p) { if (p[0] == "stat") return true; - if ((p[0] == "seq" && p[1] === self) || - (p[0] == "call" && p[1] === self) || - (p[0] == "binary" && p[2] === self)) { + if (((p[0] == "seq" || p[0] == "call" || p[0] == "dot" || p[0] == "sub" || p[0] == "conditional") && p[1] === self) || + ((p[0] == "binary" || p[0] == "assign" || p[0] == "unary-postfix") && p[2] === self)) { self = p; p = a.pop(); } else { @@ -1172,8 +1530,13 @@ function gen_code(ast, beautify) { function make_num(num) { var str = num.toString(10), a = [ str.replace(/^0\./, ".") ], m; if (Math.floor(num) === num) { - a.push("0x" + num.toString(16).toLowerCase(), // probably pointless - "0" + num.toString(8)); // same. + if (num >= 0) { + a.push("0x" + num.toString(16).toLowerCase(), // probably pointless + "0" + num.toString(8)); // same. + } else { + a.push("-0x" + (-num).toString(16).toLowerCase(), // probably pointless + "-0" + (-num).toString(8)); // same. + } if ((m = /^(.*?)(0+)$/.exec(num))) { a.push(m[1] + "e" + m[2].length); } @@ -1184,14 +1547,30 @@ function gen_code(ast, beautify) { return best_of(a); }; - var generators = { - "string": make_string, + var w = ast_walker(); + var make = w.walk; + return w.with_walkers({ + "string": encode_string, "num": make_num, "name": make_name, + "debugger": function(){ return "debugger" }, "toplevel": function(statements) { return make_block_statements(statements) .join(newline + newline); }, + "splice": function(statements) { + var parent = w.parent(); + if (HOP(SPLICE_NEEDS_BRACKETS, parent)) { + // we need block brackets in this case + return make_block.apply(this, arguments); + } else { + return MAP(make_block_statements(statements, true), + function(line, i) { + // the first line is already indented + return i > 0 ? indent(line) : line; + }).join(newline); + } + }, "block": make_block, "var": function(defs) { return "var " + add_commas(MAP(defs, make_1vardef)) + ";"; @@ -1209,7 +1588,9 @@ function gen_code(ast, beautify) { return add_spaces([ "throw", make(expr) ]) + ";"; }, "new": function(ctor, args) { - args = args.length > 0 ? "(" + add_commas(MAP(args, make)) + ")" : ""; + args = args.length > 0 ? "(" + add_commas(MAP(args, function(expr){ + return parenthesize(expr, "seq"); + })) + ")" : ""; return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){ var w = ast_walker(), has_call = {}; try { @@ -1253,9 +1634,10 @@ function gen_code(ast, beautify) { }, "dot": function(expr) { var out = make(expr), i = 1; - if (expr[0] == "num") - out += "."; - else if (needs_parens(expr)) + if (expr[0] == "num") { + if (!/\./.test(expr[1])) + out += "."; + } else if (expr[0] != "function" && needs_parens(expr)) out = "(" + out + ")"; while (i < arguments.length) out += "." + make_name(arguments[i++]); @@ -1263,7 +1645,7 @@ function gen_code(ast, beautify) { }, "call": function(func, args) { var f = make(func); - if (needs_parens(func)) + if (f.charAt(0) != "(" && needs_parens(func)) f = "(" + f + ")"; return f + "(" + add_commas(MAP(args, function(expr){ return parenthesize(expr, "seq"); @@ -1288,12 +1670,11 @@ function gen_code(ast, beautify) { out.push("(" + args + ")", make(block)); return add_spaces(out); }, - "for-in": function(has_var, key, hash, block) { - var out = add_spaces([ "for", "(" ]); - if (has_var) - out += "var "; - out += add_spaces([ make_name(key) + " in " + make(hash) + ")", make(block) ]); - return out; + "for-in": function(vvar, key, hash, block) { + return add_spaces([ "for", "(" + + (vvar ? make(vvar).replace(/;+$/, "") : make(key)), + "in", + make(hash) + ")", make(block) ]); }, "while": function(condition, block) { return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]); @@ -1312,13 +1693,19 @@ function gen_code(ast, beautify) { // we need to be smarter. // adding parens all the time is the safest bet. if (member(lvalue[0], [ "assign", "conditional", "seq" ]) || - lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]]) { + lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]] || + lvalue[0] == "function" && needs_parens(this)) { left = "(" + left + ")"; } if (member(rvalue[0], [ "assign", "conditional", "seq" ]) || - rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]]) { + rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]] && + !(rvalue[1] == operator && member(operator, [ "&&", "||", "*" ]))) { right = "(" + right + ")"; } + else if (!beautify && options.inline_script && (operator == "<" || operator == "<<") + && rvalue[0] == "regexp" && /^script/i.test(rvalue[1])) { + right = " " + right; + } return add_spaces([ left, operator, right ]); }, "unary-prefix": function(operator, expr) { @@ -1340,35 +1727,39 @@ function gen_code(ast, beautify) { return hash + "[" + make(subscript) + "]"; }, "object": function(props) { + var obj_needs_parens = needs_parens(this); if (props.length == 0) - return "{}"; - return "{" + newline + with_indent(function(){ + return obj_needs_parens ? "({})" : "{}"; + var out = "{" + newline + with_indent(function(){ return MAP(props, function(p){ if (p.length == 3) { // getter/setter. The name is in p[0], the arg.list in p[1][2], the // body in p[1][3] and type ("get" / "set") in p[2]. - return indent(make_function(p[0], p[1][2], p[1][3], p[2])); + return indent(make_function(p[0], p[1][2], p[1][3], p[2], true)); } - var key = p[0], val = make(p[1]); - if (beautify && beautify.quote_keys) { - key = make_string(key); - } else if (typeof key == "number" || !beautify && +key + "" == key) { + var key = p[0], val = parenthesize(p[1], "seq"); + if (options.quote_keys) { + key = encode_string(key); + } else if ((typeof key == "number" || !beautify && +key + "" == key) + && parseFloat(key) >= 0) { key = make_num(+key); } else if (!is_identifier(key)) { - key = make_string(key); + key = encode_string(key); } - return indent(add_spaces(beautify && beautify.space_colon + return indent(add_spaces(beautify && options.space_colon ? [ key, ":", val ] : [ key + ":", val ])); }).join("," + newline); }) + newline + indent("}"); + return obj_needs_parens ? "(" + out + ")" : out; }, "regexp": function(rx, mods) { return "/" + rx + "/" + mods; }, "array": function(elements) { if (elements.length == 0) return "[]"; - return add_spaces([ "[", add_commas(MAP(elements, function(el){ + return add_spaces([ "[", add_commas(MAP(elements, function(el, i){ + if (!beautify && el[0] == "atom" && el[1] == "undefined") return i === elements.length - 1 ? "," : ""; return parenthesize(el, "seq"); })), "]" ]); }, @@ -1387,13 +1778,10 @@ function gen_code(ast, beautify) { "atom": function(name) { return make_name(name); }, - "comment1": function(text) { - return "//" + text + "\n"; - }, - "comment2": function(text) { - return "/*" + text + "*/"; + "directive": function(dir) { + return make_string(dir) + ";"; } - }; + }, function(){ return make(ast) }); // The squeezer replaces "block"-s that contain only a single // statement with the statement itself; technically, the AST @@ -1403,12 +1791,13 @@ function gen_code(ast, beautify) { // to the inner IF). This function checks for this case and // adds the block brackets if needed. function make_then(th) { + if (th == null) return ";"; if (th[0] == "do") { // https://github.com/mishoo/UglifyJS/issues/#issue/57 // IE croaks with "syntax error" on code like this: // if (foo) do ... while(cond); else ... // we need block brackets around do/while - return make([ "block", [ th ]]); + return make_block([ th ]); } var b = th; while (true) { @@ -1426,30 +1815,48 @@ function gen_code(ast, beautify) { return make(th); }; - function make_function(name, args, body, keyword) { + function make_function(name, args, body, keyword, no_parens) { var out = keyword || "function"; if (name) { out += " " + make_name(name); } out += "(" + add_commas(MAP(args, make_name)) + ")"; - return add_spaces([ out, make_block(body) ]); + out = add_spaces([ out, make_block(body) ]); + return (!no_parens && needs_parens(this)) ? "(" + out + ")" : out; }; - function make_name(name) { - return name.toString(); + function must_has_semicolon(node) { + switch (node[0]) { + case "with": + case "while": + return empty(node[2]); // `with' or `while' with empty body? + case "for": + case "for-in": + return empty(node[4]); // `for' with empty body? + case "if": + if (empty(node[2]) && !node[3]) return true; // `if' with empty `then' and no `else' + if (node[3]) { + if (empty(node[3])) return true; // `else' present but empty + return must_has_semicolon(node[3]); // dive into the `else' branch + } + return must_has_semicolon(node[2]); // dive into the `then' branch + case "directive": + return true; + } }; - function make_block_statements(statements) { + function make_block_statements(statements, noindent) { for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) { var stat = statements[i]; var code = make(stat); if (code != ";") { - if (!beautify && i == last) + if (!beautify && i == last && !must_has_semicolon(stat)) { code = code.replace(/;+\s*$/, ""); + } a.push(code); } } - return MAP(a, indent); + return noindent ? a : MAP(a, indent); }; function make_switch_block(body) { @@ -1480,24 +1887,53 @@ function gen_code(ast, beautify) { function make_1vardef(def) { var name = def[0], val = def[1]; if (val != null) - name = add_spaces([ name, "=", make(val) ]); + name = add_spaces([ make_name(name), "=", parenthesize(val, "seq") ]); return name; }; - var $stack = []; - - function make(node) { - var type = node[0]; - var gen = generators[type]; - if (!gen) - throw new Error("Can't find generator for \"" + type + "\""); - $stack.push(node); - var ret = gen.apply(type, node.slice(1)); - $stack.pop(); - return ret; - }; +}; - return make(ast); +function split_lines(code, max_line_length) { + var splits = [ 0 ]; + jsp.parse(function(){ + var next_token = jsp.tokenizer(code); + var last_split = 0; + var prev_token; + function current_length(tok) { + return tok.pos - last_split; + }; + function split_here(tok) { + last_split = tok.pos; + splits.push(last_split); + }; + function custom(){ + var tok = next_token.apply(this, arguments); + out: { + if (prev_token) { + if (prev_token.type == "keyword") break out; + } + if (current_length(tok) > max_line_length) { + switch (tok.type) { + case "keyword": + case "atom": + case "name": + case "punc": + split_here(tok); + break out; + } + } + } + prev_token = tok; + return tok; + }; + custom.context = function() { + return next_token.context.apply(this, arguments); + }; + return custom; + }()); + return splits.map(function(pos, i){ + return code.substring(pos, splits[i + 1] || code.length); + }).join("\n"); }; /* -----[ Utilities ]----- */ @@ -1539,16 +1975,34 @@ var MAP; (function(){ MAP = function(a, f, o) { - var ret = []; - for (var i = 0; i < a.length; ++i) { + var ret = [], top = [], i; + function doit() { var val = f.call(o, a[i], i); - if (val instanceof AtTop) ret.unshift(val.v); - else ret.push(val); - } - return ret; + if (val instanceof AtTop) { + val = val.v; + if (val instanceof Splice) { + top.push.apply(top, val.v); + } else { + top.push(val); + } + } + else if (val != skip) { + if (val instanceof Splice) { + ret.push.apply(ret, val.v); + } else { + ret.push(val); + } + } + }; + if (a instanceof Array) for (i = 0; i < a.length; ++i) doit(); + else for (i in a) if (HOP(a, i)) doit(); + return top.concat(ret); }; MAP.at_top = function(val) { return new AtTop(val) }; + MAP.splice = function(val) { return new Splice(val) }; + var skip = MAP.skip = {}; function AtTop(val) { this.v = val }; + function Splice(val) { this.v = val }; })(); /* -----[ Exports ]----- */ @@ -1556,7 +2010,13 @@ var MAP; exports.ast_walker = ast_walker; exports.ast_mangle = ast_mangle; exports.ast_squeeze = ast_squeeze; +exports.ast_lift_variables = ast_lift_variables; exports.gen_code = gen_code; exports.ast_add_scope = ast_add_scope; -exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more; exports.set_logger = function(logger) { warn = logger }; +exports.make_string = make_string; +exports.split_lines = split_lines; +exports.MAP = MAP; + +// keep this last! +exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more; \ No newline at end of file diff --git a/build/lib/squeeze-more.js b/build/lib/squeeze-more.js index 12380af8..8aba082f 100644 --- a/build/lib/squeeze-more.js +++ b/build/lib/squeeze-more.js @@ -2,21 +2,72 @@ var jsp = require("./parse-js"), pro = require("./process"), slice = jsp.slice, member = jsp.member, + curry = jsp.curry, + MAP = pro.MAP, PRECEDENCE = jsp.PRECEDENCE, OPERATORS = jsp.OPERATORS; function ast_squeeze_more(ast) { - var w = pro.ast_walker(), walk = w.walk; + var w = pro.ast_walker(), walk = w.walk, scope; + function with_scope(s, cont) { + var save = scope, ret; + scope = s; + ret = cont(); + scope = save; + return ret; + }; + function _lambda(name, args, body) { + return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ]; + }; return w.with_walkers({ + "toplevel": function(body) { + return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ]; + }, + "function": _lambda, + "defun": _lambda, + "new": function(ctor, args) { + if (ctor[0] == "name") { + if (ctor[1] == "Array" && !scope.has("Array")) { + if (args.length != 1) { + return [ "array", args ]; + } else { + return walk([ "call", [ "name", "Array" ], args ]); + } + } else if (ctor[1] == "Object" && !scope.has("Object")) { + if (!args.length) { + return [ "object", [] ]; + } else { + return walk([ "call", [ "name", "Object" ], args ]); + } + } else if ((ctor[1] == "RegExp" || ctor[1] == "Function" || ctor[1] == "Error") && !scope.has(ctor[1])) { + return walk([ "call", [ "name", ctor[1] ], args]); + } + } + }, "call": function(expr, args) { + if (expr[0] == "dot" && expr[1][0] == "string" && args.length == 1 + && (args[0][1] > 0 && expr[2] == "substring" || expr[2] == "substr")) { + return [ "call", [ "dot", expr[1], "slice"], args]; + } if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) { // foo.toString() ==> foo+"" return [ "binary", "+", expr[1], [ "string", "" ]]; } + if (expr[0] == "name") { + if (expr[1] == "Array" && args.length != 1 && !scope.has("Array")) { + return [ "array", args ]; + } + if (expr[1] == "Object" && !args.length && !scope.has("Object")) { + return [ "object", [] ]; + } + if (expr[1] == "String" && !scope.has("String")) { + return [ "binary", "+", args[0], [ "string", "" ]]; + } + } } }, function() { - return walk(ast); + return walk(pro.ast_add_scope(ast)); }); }; -exports.ast_squeeze_more = ast_squeeze_more; +exports.ast_squeeze_more = ast_squeeze_more; \ No newline at end of file diff --git a/build/uglify.js b/build/uglify.js index aded6a4d..e55c1ac8 100644 --- a/build/uglify.js +++ b/build/uglify.js @@ -1,34 +1,40 @@ -#! /usr/bin/env node -// -*- js2 -*- +#!/usr/bin/env node +// -*- js -*- -global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "sys"); -var fs = require("fs"), - jsp = require("./lib/parse-js"), - pro = require("./lib/process"); - -pro.set_logger(function(msg){ - sys.debug(msg); -}); +global.sys = require(/^v0\.[012]/.test(process.version) ? "sys" : "util"); +var fs = require("fs"); +var uglify = require("./lib/uglify-js"), // symlink ~/.node_libraries/uglify-js.js to ../uglify-js.js + consolidator = uglify.consolidator, + jsp = uglify.parser, + pro = uglify.uglify; var options = { ast: false, + consolidate: false, mangle: true, mangle_toplevel: false, + no_mangle_functions: false, squeeze: true, make_seqs: true, dead_code: true, - beautify: false, verbose: false, show_copyright: true, out_same_file: false, - extra: false, - unsafe: false, // XXX: extra & unsafe? but maybe we don't want both, so.... - beautify_options: { + max_line_length: 32 * 1024, + unsafe: false, + reserved_names: null, + defines: { }, + lift_vars: false, + codegen_options: { + ascii_only: false, + beautify: false, indent_level: 4, indent_start: 0, quote_keys: false, - space_colon: false + space_colon: false, + inline_script: false }, + make: false, output: true // stdout }; @@ -40,20 +46,28 @@ out: while (args.length > 0) { switch (v) { case "-b": case "--beautify": - options.beautify = true; + options.codegen_options.beautify = true; + break; + case "-c": + case "--consolidate-primitive-values": + options.consolidate = true; break; case "-i": case "--indent": - options.beautify_options.indent_level = args.shift(); + options.codegen_options.indent_level = args.shift(); break; case "-q": case "--quote-keys": - options.beautify_options.quote_keys = true; + options.codegen_options.quote_keys = true; break; case "-mt": case "--mangle-toplevel": options.mangle_toplevel = true; break; + case "-nmf": + case "--no-mangle-functions": + options.no_mangle_functions = true; + break; case "--no-mangle": case "-nm": options.mangle = false; @@ -86,26 +100,136 @@ out: while (args.length > 0) { case "--ast": options.ast = true; break; - case "--extra": - options.extra = true; - break; case "--unsafe": options.unsafe = true; break; + case "--max-line-len": + options.max_line_length = parseInt(args.shift(), 10); + break; + case "--reserved-names": + options.reserved_names = args.shift().split(","); + break; + case "--lift-vars": + options.lift_vars = true; + break; + case "-d": + case "--define": + var defarg = args.shift(); + try { + var defsym = function(sym) { + // KEYWORDS_ATOM doesn't include NaN or Infinity - should we check + // for them too ?? We don't check reserved words and the like as the + // define values are only substituted AFTER parsing + if (jsp.KEYWORDS_ATOM.hasOwnProperty(sym)) { + throw "Don't define values for inbuilt constant '"+sym+"'"; + } + return sym; + }, + defval = function(v) { + if (v.match(/^"(.*)"$/) || v.match(/^'(.*)'$/)) { + return [ "string", RegExp.$1 ]; + } + else if (!isNaN(parseFloat(v))) { + return [ "num", parseFloat(v) ]; + } + else if (v.match(/^[a-z\$_][a-z\$_0-9]*$/i)) { + return [ "name", v ]; + } + else if (!v.match(/"/)) { + return [ "string", v ]; + } + else if (!v.match(/'/)) { + return [ "string", v ]; + } + throw "Can't understand the specified value: "+v; + }; + if (defarg.match(/^([a-z_\$][a-z_\$0-9]*)(=(.*))?$/i)) { + var sym = defsym(RegExp.$1), + val = RegExp.$2 ? defval(RegExp.$2.substr(1)) : [ 'name', 'true' ]; + options.defines[sym] = val; + } + else { + throw "The --define option expects SYMBOL[=value]"; + } + } catch(ex) { + sys.print("ERROR: In option --define "+defarg+"\n"+ex+"\n"); + process.exit(1); + } + break; + case "--define-from-module": + var defmodarg = args.shift(), + defmodule = require(defmodarg), + sym, + val; + for (sym in defmodule) { + if (defmodule.hasOwnProperty(sym)) { + options.defines[sym] = function(val) { + if (typeof val == "string") + return [ "string", val ]; + if (typeof val == "number") + return [ "num", val ]; + if (val === true) + return [ 'name', 'true' ]; + if (val === false) + return [ 'name', 'false' ]; + if (val === null) + return [ 'name', 'null' ]; + if (val === undefined) + return [ 'name', 'undefined' ]; + sys.print("ERROR: In option --define-from-module "+defmodarg+"\n"); + sys.print("ERROR: Unknown object type for: "+sym+"="+val+"\n"); + process.exit(1); + return null; + }(defmodule[sym]); + } + } + break; + case "--ascii": + options.codegen_options.ascii_only = true; + break; + case "--make": + options.make = true; + break; + case "--inline-script": + options.codegen_options.inline_script = true; + break; default: filename = v; break out; } } -if (filename) { - fs.readFile(filename, "utf8", function(err, text){ - if (err) { - throw err; +if (options.verbose) { + pro.set_logger(function(msg){ + sys.debug(msg); + }); +} + +jsp.set_logger(function(msg){ + sys.debug(msg); +}); + +if (options.make) { + options.out_same_file = false; // doesn't make sense in this case + var makefile = JSON.parse(fs.readFileSync(filename || "Makefile.uglify.js").toString()); + output(makefile.files.map(function(file){ + var code = fs.readFileSync(file.name); + if (file.module) { + code = "!function(exports, global){global = this;\n" + code + "\n;this." + file.module + " = exports;}({})"; + } + else if (file.hide) { + code = "(function(){" + code + "}());"; } + return squeeze_it(code); + }).join("\n")); +} +else if (filename) { + fs.readFile(filename, "utf8", function(err, text){ + if (err) throw err; output(squeeze_it(text)); }); -} else { +} +else { var stdin = process.openStdin(); stdin.setEncoding("utf8"); var text = ""; @@ -130,8 +254,10 @@ function output(text) { mode: 0644 }); } - out.write(text + ';'); - out.end(); + out.write(text.replace(/;*$/, ";")); + if (options.output !== true) { + out.end(); + } }; // --------- main ends here. @@ -152,41 +278,48 @@ function show_copyright(comments) { function squeeze_it(code) { var result = ""; if (options.show_copyright) { - var initial_comments = []; - // keep first comment - var tok = jsp.tokenizer(code, false), c; + var tok = jsp.tokenizer(code), c; c = tok(); - var prev = null; - while (/^comment/.test(c.type) && (!prev || prev == c.type)) { - initial_comments.push(c); - prev = c.type; - c = tok(); - } - result += show_copyright(initial_comments); + result += show_copyright(c.comments_before); } try { var ast = time_it("parse", function(){ return jsp.parse(code); }); - if (options.mangle) - ast = time_it("mangle", function(){ return pro.ast_mangle(ast, options.mangle_toplevel); }); - if (options.squeeze) - ast = time_it("squeeze", function(){ - ast = pro.ast_squeeze(ast, { - make_seqs : options.make_seqs, - dead_code : options.dead_code, - extra : options.extra - }); - if (options.unsafe) - ast = pro.ast_squeeze_more(ast); - return ast; + if (options.consolidate) ast = time_it("consolidate", function(){ + return consolidator.ast_consolidate(ast); + }); + if (options.lift_vars) { + ast = time_it("lift", function(){ return pro.ast_lift_variables(ast); }); + } + if (options.mangle) ast = time_it("mangle", function(){ + return pro.ast_mangle(ast, { + toplevel : options.mangle_toplevel, + defines : options.defines, + except : options.reserved_names, + no_functions : options.no_mangle_functions + }); + }); + if (options.squeeze) ast = time_it("squeeze", function(){ + ast = pro.ast_squeeze(ast, { + make_seqs : options.make_seqs, + dead_code : options.dead_code, + keep_comps : !options.unsafe }); + if (options.unsafe) + ast = pro.ast_squeeze_more(ast); + return ast; + }); if (options.ast) return sys.inspect(ast, null, null); - result += time_it("generate", function(){ return pro.gen_code(ast, options.beautify && options.beautify_options) }); + result += time_it("generate", function(){ return pro.gen_code(ast, options.codegen_options) }); + if (!options.codegen_options.beautify && options.max_line_length) { + result = time_it("split", function(){ return pro.split_lines(result, options.max_line_length) }); + } return result; } catch(ex) { sys.debug(ex.stack); sys.debug(sys.inspect(ex)); sys.debug(JSON.stringify(ex)); + process.exit(1); } }; @@ -196,4 +329,4 @@ function time_it(name, cont) { var t1 = new Date().getTime(); try { return cont(); } finally { sys.debug("// " + name + ": " + ((new Date().getTime() - t1) / 1000).toFixed(3) + " sec."); } -}; +}; \ No newline at end of file diff --git a/dist/jquery.qtip.basic.js b/dist/jquery.qtip.basic.js index 70ba6b46..2ba229a0 100644 --- a/dist/jquery.qtip.basic.js +++ b/dist/jquery.qtip.basic.js @@ -9,7 +9,7 @@ * http://en.wikipedia.org/wiki/MIT_License * http://en.wikipedia.org/wiki/GNU_General_Public_License * -* Date: Sat Mar 3 17:00:08 2012 +0000 +* Date: Sat Mar 3 17:04:40 2012 +0000 */ /*jslint browser: true, onevar: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true */ @@ -1064,7 +1064,7 @@ function QTip(target, options, id, attr) } // Clear animation queue if same target - if(sameTarget) { tooltip.stop(0, 1); } + if(sameTarget) { tooltip.stop(1, 0); } // If no effect type is supplied, use a simple toggle if(opts.effect === FALSE) { diff --git a/dist/jquery.qtip.css b/dist/jquery.qtip.css index da04c5ef..5f34f79a 100644 --- a/dist/jquery.qtip.css +++ b/dist/jquery.qtip.css @@ -9,7 +9,7 @@ * http://en.wikipedia.org/wiki/MIT_License * http://en.wikipedia.org/wiki/GNU_General_Public_License * -* Date: Sat Mar 3 17:00:08 2012 +0000 +* Date: Sat Mar 3 17:04:40 2012 +0000 */ /* Core qTip styles */ diff --git a/dist/jquery.qtip.js b/dist/jquery.qtip.js index 29e704c0..eaa39219 100644 --- a/dist/jquery.qtip.js +++ b/dist/jquery.qtip.js @@ -9,7 +9,7 @@ * http://en.wikipedia.org/wiki/MIT_License * http://en.wikipedia.org/wiki/GNU_General_Public_License * -* Date: Sat Mar 3 17:00:08 2012 +0000 +* Date: Sat Mar 3 17:04:40 2012 +0000 */ /*jslint browser: true, onevar: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true */ @@ -1064,7 +1064,7 @@ function QTip(target, options, id, attr) } // Clear animation queue if same target - if(sameTarget) { tooltip.stop(0, 1); } + if(sameTarget) { tooltip.stop(1, 0); } // If no effect type is supplied, use a simple toggle if(opts.effect === FALSE) { diff --git a/dist/jquery.qtip.min.js b/dist/jquery.qtip.min.js index f8b82967..af47ac79 100644 --- a/dist/jquery.qtip.min.js +++ b/dist/jquery.qtip.min.js @@ -9,5 +9,7 @@ * http://en.wikipedia.org/wiki/MIT_License * http://en.wikipedia.org/wiki/GNU_General_Public_License * -* Date: Sat Mar 3 17:00:08 2012 +0000 -*//*jslint browser: true, onevar: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true *//*global window: false, jQuery: false, console: false, define: false */(function(a){typeof define==="function"&&define.amd?define(["jquery"],a):a(jQuery)})(function(a){function D(f,h){function w(a){var b=a.precedance==="y",c=n[b?"width":"height"],d=n[b?"height":"width"],e=a.string().indexOf("center")>-1,f=c*(e?.5:1),g=Math.pow,h=Math.round,i,j,k,l=Math.sqrt(g(f,2)+g(d,2)),m=[p/f*l,p/d*l];m[2]=Math.sqrt(g(m[0],2)-g(p,2)),m[3]=Math.sqrt(g(m[1],2)-g(p,2)),i=l+m[2]+m[3]+(e?0:m[0]),j=i/l,k=[h(j*d),h(j*c)];return{height:k[b?0:1],width:k[b?1:0]}}function v(b){var c=k.titlebar&&b.y==="top",d=c?k.titlebar:k.content,e=a.browser.mozilla,f=e?"-moz-":a.browser.webkit?"-webkit-":"",g=b.y+(e?"":"-")+b.x,h=f+(e?"border-radius-"+g:"border-"+g+"-radius");return parseInt(d.css(h),10)||parseInt(l.css(h),10)||0}function u(a,b,c){b=b?b:a[a.precedance];var d=l.hasClass(q),e=k.titlebar&&a.y==="top",f=e?k.titlebar:k.content,g="border-"+b+"-width",h;l.addClass(q),h=parseInt(f.css(g),10),h=(c?h||parseInt(l.css(g),10):h)||0,l.toggleClass(q,d);return h}function t(a,d,g,h){if(k.tip){var l=i.corner.clone(),n=g.adjusted,o=f.options.position.adjust.method.split(" "),p=o[0],q=o[1]||o[0],r={left:c,top:c,x:0,y:0},s,t={},u;i.corner.fixed!==b&&(p==="shift"&&l.precedance==="x"&&n.left&&l.y!=="center"?l.precedance=l.precedance==="x"?"y":"x":p==="flip"&&n.left&&(l.x=l.x==="center"?n.left>0?"left":"right":l.x==="left"?"right":"left"),q==="shift"&&l.precedance==="y"&&n.top&&l.x!=="center"?l.precedance=l.precedance==="y"?"x":"y":q==="flip"&&n.top&&(l.y=l.y==="center"?n.top>0?"top":"bottom":l.y==="top"?"bottom":"top"),l.string()!==m.corner.string()&&(m.top!==n.top||m.left!==n.left)&&i.update(l,c)),s=i.position(l,n),s.right!==e&&(s.left=-s.right),s.bottom!==e&&(s.top=-s.bottom),s.user=Math.max(0,j.offset);if(r.left=p==="shift"&&!!n.left)l.x==="center"?t["margin-left"]=r.x=s["margin-left"]-n.left:(u=s.right!==e?[n.left,-s.left]:[-n.left,s.left],(r.x=Math.max(u[0],u[1]))>u[0]&&(g.left-=n.left,r.left=c),t[s.right!==e?"right":"left"]=r.x);if(r.top=q==="shift"&&!!n.top)l.y==="center"?t["margin-top"]=r.y=s["margin-top"]-n.top:(u=s.bottom!==e?[n.top,-s.top]:[-n.top,s.top],(r.y=Math.max(u[0],u[1]))>u[0]&&(g.top-=n.top,r.top=c),t[s.bottom!==e?"bottom":"top"]=r.y);k.tip.css(t).toggle(!(r.x&&r.y||l.x==="center"&&r.y||l.y==="center"&&r.x)),g.left-=s.left.charAt?s.user:p!=="shift"||r.top||!r.left&&!r.top?s.left:0,g.top-=s.top.charAt?s.user:q!=="shift"||r.left||!r.left&&!r.top?s.top:0,m.left=n.left,m.top=n.top,m.corner=l.clone()}}var i=this,j=f.options.style.tip,k=f.elements,l=k.tooltip,m={top:0,left:0},n={width:j.width,height:j.height},o={},p=j.border||0,r=".qtip-tip",s=!!(a("")[0]||{}).getContext;i.mimic=i.corner=d,i.border=p,i.offset=j.offset,i.size=n,f.checks.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){i.init()||i.destroy(),f.reposition()},"^style.tip.(height|width)$":function(){n={width:j.width,height:j.height},i.create(),i.update(),f.reposition()},"^content.title.text|style.(classes|widget)$":function(){k.tip&&i.update()}},a.extend(i,{init:function(){var b=i.detectCorner()&&(s||a.browser.msie);b&&(i.create(),i.update(),l.unbind(r).bind("tooltipmove"+r,t));return b},detectCorner:function(){var a=j.corner,d=f.options.position,e=d.at,h=d.my.string?d.my.string():d.my;if(a===c||h===c&&e===c)return c;a===b?i.corner=new g.Corner(h):a.string||(i.corner=new g.Corner(a),i.corner.fixed=b),m.corner=new g.Corner(i.corner.string());return i.corner.string()!=="centercenter"},detectColours:function(b){var c,d,e,g=k.tip.css("cssText",""),h=b||i.corner,m=h[h.precedance],p="border-"+m+"-color",r="border"+m.charAt(0)+m.substr(1)+"Color",s=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,t="background-color",u="transparent",v=" !important",w=a(document.body).css("color"),x=f.elements.content.css("color"),y=k.titlebar&&(h.y==="top"||h.y==="center"&&g.position().top+n.height/2+j.offset",{"class":"ui-tooltip-tip"}).css({width:b,height:c}).prependTo(l),s?a("").appendTo(k.tip)[0].getContext("2d").save():(d='',k.tip.html(d+d),a("*",k.tip).bind("click mousedown",function(a){a.stopPropagation()}))},update:function(e,f){var h=k.tip,l=h.children(),q=n.width,r=n.height,t="px solid ",v="px dashed transparent",x=j.mimic,y=Math.round,z,A,B,D,E;e||(e=m.corner||i.corner),x===c?x=e:(x=new g.Corner(x),x.precedance=e.precedance,x.x==="inherit"?x.x=e.x:x.y==="inherit"?x.y=e.y:x.x===x.y&&(x[e.precedance]=e[e.precedance])),z=x.precedance,i.detectColours(e),o.border!=="transparent"&&o.border!=="#123456"?(p=u(e,d,b),j.border===0&&p>0&&(o.fill=o.border),i.border=p=j.border!==b?j.border:p):i.border=p=0,B=C(x,q,r),i.size=E=w(e),h.css(E),e.precedance==="y"?D=[y(x.x==="left"?p:x.x==="right"?E.width-q-p:(E.width-q)/2),y(x.y==="top"?E.height-r:0)]:D=[y(x.x==="left"?E.width-q:0),y(x.y==="top"?p:x.y==="bottom"?E.height-r-p:(E.height-r)/2)],s?(l.attr(E),A=l[0].getContext("2d"),A.restore(),A.save(),A.clearRect(0,0,3e3,3e3),A.translate(D[0],D[1]),A.beginPath(),A.moveTo(B[0][0],B[0][1]),A.lineTo(B[1][0],B[1][1]),A.lineTo(B[2][0],B[2][1]),A.closePath(),A.fillStyle=o.fill,A.strokeStyle=o.border,A.lineWidth=p*2,A.lineJoin="miter",A.miterLimit=100,p&&A.stroke(),A.fill()):(B="m"+B[0][0]+","+B[0][1]+" l"+B[1][0]+","+B[1][1]+" "+B[2][0]+","+B[2][1]+" xe",D[2]=p&&/^(r|b)/i.test(e.string())?parseFloat(a.browser.version,10)===8?2:1:0,l.css({antialias:""+(x.string().indexOf("center")>-1),left:D[0]-D[2]*Number(z==="x"),top:D[1]-D[2]*Number(z==="y"),width:q+p,height:r+p}).each(function(b){var c=a(this);c[c.prop?"prop":"attr"]({coordsize:q+p+" "+(r+p),path:B,fillcolor:o.fill,filled:!!b,stroked:!b}).css({display:p||b?"block":"none"}),!b&&c.html()===""&&c.html('')})),f!==c&&i.position(e)},position:function(d){var e=k.tip,f={},g=Math.max(0,j.offset),h,l,m;if(j.corner===c||!e)return c;d=d||i.corner,h=d.precedance,l=w(d),m=[d.x,d.y],h==="x"&&m.reverse(),a.each(m,function(a,c){var e,i;c==="center"?(e=h==="y"?"left":"top",f[e]="50%",f["margin-"+e]=-Math.round(l[h==="y"?"width":"height"]/2)+g):(e=u(d,c,b),i=v(d),f[c]=a?p?u(d,c):0:g+(i>e?i:0))}),f[d[h]]-=l[h==="x"?"width":"height"],e.css({top:"",bottom:"",left:"",right:"",margin:""}).css(f);return f},destroy:function(){k.tip&&k.tip.remove(),l.unbind(r)}}),i.init()}function C(a,b,c){var d=Math.ceil(b/2),e=Math.ceil(c/2),f={bottomright:[[0,0],[b,c],[b,0]],bottomleft:[[0,0],[b,0],[0,c]],topright:[[0,c],[b,0],[b,c]],topleft:[[0,0],[0,c],[b,c]],topcenter:[[0,c],[d,0],[b,c]],bottomcenter:[[0,0],[b,0],[d,c]],rightcenter:[[0,0],[b,e],[0,c]],leftcenter:[[b,0],[b,c],[0,e]]};f.lefttop=f.bottomright,f.righttop=f.bottomleft,f.leftbottom=f.topright,f.rightbottom=f.topleft;return f[a.string()]}function B(d){var e=this,f=d.options.show.modal,h=d.elements,i=h.tooltip,j="#qtip-overlay",k=".qtipmodal",l=k+d.id,n="is-modal-qtip",p=a(document.body),q;d.checks.modal={"^show.modal.(on|blur)$":function(){e.init(),h.overlay.toggle(i.is(":visible"))}},a.extend(e,{init:function(){if(!f.on)return e;q=e.create(),i.attr(n,b).css("z-index",g.modal.zindex+a(m+"["+n+"]").length).unbind(k).unbind(l).bind("tooltipshow"+k+" tooltiphide"+k,function(b,c,d){var f=b.originalEvent;if(b.target===i[0])if(f&&b.type==="tooltiphide"&&/mouse(leave|enter)/.test(f.type)&&a(f.relatedTarget).closest(q[0]).length)try{b.preventDefault()}catch(g){}else(!f||f&&!f.solo)&&e[b.type.replace("tooltip","")](b,d)}).bind("tooltipfocus"+k,function(b){if(!b.isDefaultPrevented()&&b.target===i[0]){var c=a(m).filter("["+n+"]"),d=g.modal.zindex+c.length,e=parseInt(i[0].style.zIndex,10);q[0].style.zIndex=d-1,c.each(function(){this.style.zIndex>e&&(this.style.zIndex-=1)}),c.end().filter("."+o).qtip("blur",b.originalEvent),i.addClass(o)[0].style.zIndex=d;try{b.preventDefault()}catch(f){}}}).bind("tooltiphide"+k,function(b){b.target===i[0]&&a("["+n+"]").filter(":visible").not(i).last().qtip("focus",b)}),f.escape&&a(window).unbind(l).bind("keydown"+l,function(a){a.keyCode===27&&i.hasClass(o)&&d.hide(a)}),f.blur&&h.overlay.unbind(l).bind("click"+l,function(a){i.hasClass(o)&&d.hide(a)});return e},create:function(){function d(){q.css({height:a(window).height(),width:a(window).width()})}var b=a(j);if(b.length)return h.overlay=b.insertAfter(a(m).last());q=h.overlay=a("
",{id:j.substr(1),html:"
",mousedown:function(){return c}}).insertAfter(a(m).last()),a(window).unbind(k).bind("resize"+k,d),d();return q},toggle:function(d,g,h){if(d&&d.isDefaultPrevented())return e;var j=f.effect,k=g?"show":"hide",o=q.is(":visible"),r=a("["+n+"]").filter(":visible").not(i),s;q||(q=e.create());if(q.is(":animated")&&o===g||!g&&r.length)return e;g?(q.css({left:0,top:0}),q.toggleClass("blurs",f.blur),p.bind("focusin"+l,function(b){var d=a(b.target),e=d.closest(".qtip"),f=e.length<1?c:parseInt(e[0].style.zIndex,10)>parseInt(i[0].style.zIndex,10);!f&&a(b.target).closest(m)[0]!==i[0]&&i.find("input:visible").filter(":first").focus()})):p.undelegate("*","focusin"+l),q.stop(b,c),a.isFunction(j)?j.call(q,g):j===c?q[k]():q.fadeTo(parseInt(h,10)||90,g?1:0,function(){g||a(this).hide()}),g||q.queue(function(a){q.css({left:"",top:""}),a()});return e},show:function(a,c){return e.toggle(a,b,c)},hide:function(a,b){return e.toggle(a,c,b)},destroy:function(){var b=q;b&&(b=a("["+n+"]").not(i).length<1,b?(h.overlay.remove(),a(window).unbind(k)):h.overlay.unbind(k+d.id),p.undelegate("*","focusin"+l));return i.removeAttr(n).unbind(k)}}),e.init()}function A(b){var c=this,d=b.elements,e=d.tooltip,f=".bgiframe-"+b.id;a.extend(c,{init:function(){d.bgiframe=a(''),d.bgiframe.appendTo(e),e.bind("tooltipmove"+f,c.adjust)},adjust:function(){var a=b.get("dimensions"),c=b.plugins.tip,f=d.tip,g,h;h=parseInt(e.css("border-left-width"),10)||0,h={left:-h,top:-h},c&&f&&(g=c.corner.precedance==="x"?["width","left"]:["height","top"],h[g[1]]-=f[g[0]]()),d.bgiframe.css(h).css(a)},destroy:function(){d.bgiframe.remove(),e.unbind(f)}}),c.init()}function z(d){var e=this,f=d.elements.tooltip,g=d.options.content.ajax,h=".qtip-ajax",i=/)<[^<]*)*<\/script>/gi,j=b,k=c,l;d.checks.ajax={"^content.ajax":function(a,b,c){b==="ajax"&&(g=c),b==="once"?e.init():g&&g.url?e.load():f.unbind(h)}},a.extend(e,{init:function(){g&&g.url&&f.unbind(h)[g.once?"one":"bind"]("tooltipshow"+h,e.load);return e},load:function(b,f){function r(a,b,c){!k&&a.status!==0&&d.set("content.text",b+": "+c)}function q(b){k||(m&&(b=a("
").append(b.replace(i,"")).find(m)),d.set("content.text",b))}function p(){k||(n&&(d.show(b.originalEvent),f=c),a.isFunction(g.complete)&&g.complete.apply(this,arguments))}var h=g.url.indexOf(" "),j=g.url,m,n=g.once&&!g.loading&&f;if(n)try{b.preventDefault()}catch(o){}else if(b&&b.isDefaultPrevented())return e;l&&l.abort&&l.abort(),h>-1&&(m=j.substr(h),j=j.substr(0,h)),l=a.ajax(a.extend({success:q,error:r,context:d},g,{url:j,complete:p}))},destroy:function(){l&&l.abort&&l.abort(),k=b}}),e.init()}function y(e,h){var i,j,k,l,m,n=a(this),o=a(document.body),p=this===document?o:n,q=n.metadata?n.metadata(h.metadata):d,r=h.metadata.type==="html5"&&q?q[h.metadata.name]:d,s=n.data(h.metadata.name||"qtipopts");try{s=typeof s==="string"?(new Function("return "+s))():s}catch(u){v("Unable to parse HTML5 attribute data: "+s)}l=a.extend(b,{},f.defaults,h,typeof s==="object"?w(s):d,w(r||q)),j=l.position,l.id=e;if("boolean"===typeof l.content.text){k=n.attr(l.content.attr);if(l.content.attr!==c&&k)l.content.text=k;else{v("Unable to locate content for tooltip! Aborting render of tooltip on element: ",n);return c}}j.container.length||(j.container=o),j.target===c&&(j.target=p),l.show.target===c&&(l.show.target=p),l.show.solo===b&&(l.show.solo=j.container.closest("body")),l.hide.target===c&&(l.hide.target=p),l.position.viewport===b&&(l.position.viewport=j.container),j.at=new g.Corner(j.at),j.my=new g.Corner(j.my);if(a.data(this,"qtip"))if(l.overwrite)n.qtip("destroy");else if(l.overwrite===c)return c;l.suppress&&(m=a.attr(this,"title"))&&a(this).removeAttr("title").attr(t,m),i=new x(n,l,e,!!k),a.data(this,"qtip",i),n.bind("remove.qtip-"+e+" removeqtip.qtip-"+e,function(){i.destroy()});return i}function x(r,s,v,x){function Q(){var b=[s.show.target[0],s.hide.target[0],y.rendered&&F.tooltip[0],s.position.container[0],s.position.viewport[0],window,document];y.rendered?a([]).pushStack(a.grep(b,function(a){return typeof a==="object"})).unbind(E):s.show.target.unbind(E+"-create")}function P(){function o(a){D.is(":visible")&&y.reposition(a)}function n(a){if(D.hasClass(l))return c;clearTimeout(y.timers.inactive),y.timers.inactive=setTimeout(function(){y.hide(a)},s.hide.inactive)}function k(b){if(D.hasClass(l)||B||C)return c;var f=a(b.relatedTarget||b.target),g=f.closest(m)[0]===D[0],h=f[0]===e.show[0];clearTimeout(y.timers.show),clearTimeout(y.timers.hide);if(d.target==="mouse"&&g||s.hide.fixed&&(/mouse(out|leave|move)/.test(b.type)&&(g||h)))try{b.preventDefault(),b.stopImmediatePropagation()}catch(i){}else s.hide.delay>0?y.timers.hide=setTimeout(function(){y.hide(b)},s.hide.delay):y.hide(b)}function j(a){if(D.hasClass(l))return c;clearTimeout(y.timers.show),clearTimeout(y.timers.hide);var d=function(){y.toggle(b,a)};s.show.delay>0?y.timers.show=setTimeout(d,s.show.delay):d()}var d=s.position,e={show:s.show.target,hide:s.hide.target,viewport:a(d.viewport),document:a(document),body:a(document.body),window:a(window)},g={show:a.trim(""+s.show.event).split(" "),hide:a.trim(""+s.hide.event).split(" ")},i=a.browser.msie&&parseInt(a.browser.version,10)===6;D.bind("mouseenter"+E+" mouseleave"+E,function(a){var b=a.type==="mouseenter";b&&y.focus(a),D.toggleClass(p,b)}),s.hide.fixed&&(e.hide=e.hide.add(D),D.bind("mouseover"+E,function(){D.hasClass(l)||clearTimeout(y.timers.hide)})),/mouse(out|leave)/i.test(s.hide.event)?s.hide.leave==="window"&&e.window.bind("mouseout"+E+" blur"+E,function(a){/select|option/.test(a.target)&&!a.relatedTarget&&y.hide(a)}):/mouse(over|enter)/i.test(s.show.event)&&e.hide.bind("mouseleave"+E,function(a){clearTimeout(y.timers.show)}),(""+s.hide.event).indexOf("unfocus")>-1&&d.container.closest("html").bind("mousedown"+E,function(b){var c=a(b.target),d=!D.hasClass(l)&&D.is(":visible"),e=c.parents(m).filter(D[0]).length>0;c[0]!==r[0]&&c[0]!==D[0]&&!e&&!r.has(c[0]).length&&!c.attr("disabled")&&y.hide(b)}),"number"===typeof s.hide.inactive&&(e.show.bind("qtip-"+v+"-inactive",n),a.each(f.inactiveEvents,function(a,b){e.hide.add(F.tooltip).bind(b+E+"-inactive",n)})),a.each(g.hide,function(b,c){var d=a.inArray(c,g.show),f=a(e.hide);d>-1&&f.add(e.show).length===f.length||c==="unfocus"?(e.show.bind(c+E,function(a){D.is(":visible")?k(a):j(a)}),delete g.show[d]):e.hide.bind(c+E,k)}),a.each(g.show,function(a,b){e.show.bind(b+E,j)}),"number"===typeof s.hide.distance&&e.show.add(D).bind("mousemove"+E,function(a){var b=G.origin||{},c=s.hide.distance,d=Math.abs;(d(a.pageX-b.pageX)>=c||d(a.pageY-b.pageY)>=c)&&y.hide(a)}),d.target==="mouse"&&(e.show.bind("mousemove"+E,function(a){h={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}}),d.adjust.mouse&&(s.hide.event&&(D.bind("mouseleave"+E,function(a){(a.relatedTarget||a.target)!==e.show[0]&&y.hide(a)}),F.target.bind("mouseenter"+E+" mouseleave"+E,function(a){G.onTarget=a.type==="mouseenter"})),e.document.bind("mousemove"+E,function(a){G.onTarget&&!D.hasClass(l)&&D.is(":visible")&&y.reposition(a||h)}))),(d.adjust.resize||e.viewport.length)&&(a.event.special.resize?e.viewport:e.window).bind("resize"+E,o),(e.viewport.length||i&&D.css("position")==="fixed")&&e.viewport.bind("scroll"+E,o)}function O(b,d){function g(b){function i(e){e&&(delete h[e.src],clearTimeout(y.timers.img[e.src]),a(e).unbind(E)),a.isEmptyObject(h)&&(y.redraw(),d!==c&&y.reposition(G.event),b())}var g,h={};if((g=f.find("img[src]:not([height]):not([width])")).length===0)return i();g.each(function(b,c){if(h[c.src]===e){var d=0,f=3;(function g(){if(c.height||c.width||d>f)return i(c);d+=1,y.timers.img[c.src]=setTimeout(g,700)})(),a(c).bind("error"+E+" load"+E,function(){i(this)}),h[c.src]=c}})}var f=F.content;if(!y.rendered||!b)return c;a.isFunction(b)&&(b=b.call(r,G.event,y)||""),b.jquery&&b.length>0?f.empty().append(b.css({display:"block"})):f.html(b),y.rendered<0?D.queue("fx",g):(C=0,g(a.noop));return y}function N(b,d){var e=F.title;if(!y.rendered||!b)return c;a.isFunction(b)&&(b=b.call(r,G.event,y));if(b===c||!b&&b!=="")return J(c);b.jquery&&b.length>0?e.empty().append(b.css({display:"block"})):e.html(b),y.redraw(),d!==c&&y.rendered&&D.is(":visible")&&y.reposition(G.event)}function M(a){var b=F.button,d=F.title;if(!y.rendered)return c;a?(d||L(),K()):b.remove()}function L(){var c=A+"-title";F.titlebar&&J(),F.titlebar=a("
",{"class":j+"-titlebar "+(s.style.widget?"ui-widget-header":"")}).append(F.title=a("
",{id:c,"class":j+"-title","aria-atomic":b})).insertBefore(F.content).delegate(".ui-tooltip-close","mousedown keydown mouseup keyup mouseout",function(b){a(this).toggleClass("ui-state-active ui-state-focus",b.type.substr(-4)==="down")}).delegate(".ui-tooltip-close","mouseover mouseout",function(b){a(this).toggleClass("ui-state-hover",b.type==="mouseover")}),s.content.title.button?K():y.rendered&&y.redraw()}function K(){var b=s.content.title.button,d=typeof b==="string",e=d?b:"Close tooltip";F.button&&F.button.remove(),b.jquery?F.button=b:F.button=a("",{"class":"ui-state-default ui-tooltip-close "+(s.style.widget?"":j+"-icon"),title:e,"aria-label":e}).prepend(a("",{"class":"ui-icon ui-icon-close",html:"×"})),F.button.appendTo(F.titlebar).attr("role","button").click(function(a){D.hasClass(l)||y.hide(a);return c}),y.redraw()}function J(a){F.title&&(F.titlebar.remove(),F.titlebar=F.title=F.button=d,a!==c&&y.reposition())}function I(){var a=s.style.widget;D.toggleClass(k,a).toggleClass(n,s.style.def&&!a),F.content.toggleClass(k+"-content",a),F.titlebar&&F.titlebar.toggleClass(k+"-header",a),F.button&&F.button.toggleClass(j+"-icon",!a)}function H(a){var b=0,c,d=s,e=a.split(".");while(d=d[e[b++]])b0&&!a("#"+i).length&&(D[0].id=i,F.content[0].id=i+"-content",F.title[0].id=i+"-title")},"^content.text$":function(a,b,c){O(c)},"^content.title.text$":function(a,b,c){if(!c)return J();!F.title&&c&&L(),N(c)},"^content.title.button$":function(a,b,c){M(c)},"^position.(my|at)$":function(a,b,c){"string"===typeof c&&(a[b]=new g.Corner(c))},"^position.container$":function(a,b,c){y.rendered&&D.appendTo(c)},"^show.ready$":function(){y.rendered?y.toggle(b):y.render(1)},"^style.classes$":function(a,b,c){D.attr("class",j+" qtip ui-helper-reset "+c)},"^style.widget|content.title":I,"^events.(render|show|move|hide|focus|blur)$":function(b,c,d){D[(a.isFunction(d)?"":"un")+"bind"]("tooltip"+c,d)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){var a=s.position;D.attr("tracking",a.target==="mouse"&&a.adjust.mouse),Q(),P()}},a.extend(y,{render:function(d){if(y.rendered)return y;var e=s.content.text,f=s.content.title.text,h=s.position,i=a.Event("tooltiprender");a.attr(r[0],"aria-describedby",A),D=F.tooltip=a("
",{id:A,"class":j+" qtip ui-helper-reset "+n+" "+s.style.classes+" "+j+"-pos-"+s.position.my.abbrev(),width:s.style.width||"",height:s.style.height||"",tracking:h.target==="mouse"&&h.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":c,"aria-describedby":A+"-content","aria-hidden":b}).toggleClass(l,G.disabled).data("qtip",y).appendTo(s.position.container).append(F.content=a("
",{"class":j+"-content",id:A+"-content","aria-atomic":b})),y.rendered=-1,B=C=1,f&&(L(),a.isFunction(f)||N(f,c)),a.isFunction(e)||O(e,c),y.rendered=b,I(),a.each(s.events,function(b,c){a.isFunction(c)&&D.bind(b==="toggle"?"tooltipshow tooltiphide":"tooltip"+b,c)}),a.each(g,function(){this.initialize==="render"&&this(y)}),P(),D.queue("fx",function(a){i.originalEvent=G.event,D.trigger(i,[y]),B=C=0,y.redraw(),(s.show.ready||d)&&y.toggle(b,G.event,c),a()});return y},get:function(a){var b,c;switch(a.toLowerCase()){case"dimensions":b={height:D.outerHeight(),width:D.outerWidth()};break;case"offset":b=g.offset(D,s.position.container);break;default:c=H(a.toLowerCase()),b=c[0][c[1]],b=b.precedance?b.string():b}return b},set:function(e,f){function m(a,b){var c,d,e;for(c in k)for(d in k[c])if(e=(new RegExp(d,"i")).exec(a))b.push(e),k[c][d].apply(y,b)}var g=/^position\.(my|at|adjust|target|container)|style|content|show\.ready/i,h=/^content\.(title|attr)|style/i,i=c,j=c,k=y.checks,l;"string"===typeof e?(l=e,e={},e[l]=f):e=a.extend(b,{},e),a.each(e,function(b,c){var d=H(b.toLowerCase()),f;f=d[0][d[1]],d[0][d[1]]="object"===typeof c&&c.nodeType?a(c):c,e[b]=[d[0],d[1],c,f],i=g.test(b)||i,j=h.test(b)||j}),w(s),B=C=1,a.each(e,m),B=C=0,D.is(":visible")&&y.rendered&&(i&&y.reposition(s.position.target==="mouse"?d:G.event),j&&y.redraw());return y},toggle:function(e,f){function q(){e?(a.browser.msie&&D[0].style.removeAttribute("filter"),D.css("overflow",""),"string"===typeof i.autofocus&&a(i.autofocus,D).focus(),p=a.Event("tooltipvisible"),p.originalEvent=f?G.event:d,D.trigger(p,[y]),i.target.trigger("qtip-"+v+"-inactive")):D.css({display:"",visibility:"",opacity:"",left:"",top:""})}if(!y.rendered)return e?y.render(1):y;var g=e?"show":"hide",i=s[g],j=D.is(":visible"),k=!f||s[g].target.length<2||G.target[0]===f.target,l=s.position,n=s.content,o,p;(typeof e).search("boolean|number")&&(e=!j);if(!D.is(":animated")&&j===e&&k)return y;if(f){if(/over|enter/.test(f.type)&&/out|leave/.test(G.event.type)&&f.target===s.show.target[0]&&D.has(f.relatedTarget).length)return y;G.event=a.extend({},f)}p=a.Event("tooltip"+g),p.originalEvent=f?G.event:d,D.trigger(p,[y,90]);if(p.isDefaultPrevented())return y;a.attr(D[0],"aria-hidden",!e),e?(G.origin=a.extend({},h),y.focus(f),a.isFunction(n.text)&&O(n.text,c),a.isFunction(n.title.text)&&N(n.title.text,c),!u&&l.target==="mouse"&&l.adjust.mouse&&(a(document).bind("mousemove.qtip",function(a){h={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}}),u=b),y.reposition(f,arguments[2]),(p.solo=!!i.solo)&&a(m,i.solo).not(D).qtip("hide",p)):(clearTimeout(y.timers.show),delete G.origin,u&&!a(m+'[tracking="true"]:visible',i.solo).not(D).length&&(a(document).unbind("mousemove.qtip"),u=c),y.blur(f)),k&&D.stop(0,1),i.effect===c?(D[g](),q.call(D)):a.isFunction(i.effect)?(i.effect.call(D,y),D.queue("fx",function(a){q(),a()})):D.fadeTo(90,e?1:0,q),e&&i.target.trigger("qtip-"+v+"-inactive");return y},show:function(a){return y.toggle(b,a)},hide:function(a){return y.toggle(c,a)},focus:function(b){if(!y.rendered)return y;var c=a(m),d=parseInt(D[0].style.zIndex,10),e=f.zindex+c.length,g=a.extend({},b),h,i;D.hasClass(o)||(i=a.Event("tooltipfocus"),i.originalEvent=g,D.trigger(i,[y,e]),i.isDefaultPrevented()||(d!==e&&(c.each(function(){this.style.zIndex>d&&(this.style.zIndex=this.style.zIndex-1)}),c.filter("."+o).qtip("blur",g)),D.addClass(o)[0].style.zIndex=e));return y},blur:function(b){var c=a.extend({},b),d;D.removeClass(o),d=a.Event("tooltipblur"),d.originalEvent=c,D.trigger(d,[y]);return y},reposition:function(b,d){if(!y.rendered||B)return y;B=1;var e=s.position.target,f=s.position,i=f.my,k=f.at,l=f.adjust,m=l.method.split(" "),n=D.outerWidth(),o=D.outerHeight(),p=0,q=0,r=a.Event("tooltipmove"),t=D.css("position")==="fixed",u=f.viewport,v={left:0,top:0},w=f.container,x=c,A=y.plugins.tip,C={horizontal:m[0],vertical:m[1]=m[1]||m[0],enabled:u.jquery&&e[0]!==window&&e[0]!==z&&l.method!=="none",left:function(a){var b=C.horizontal==="shift",c=-w.offset.left+u.offset.left+u.scrollLeft,d=i.x==="left"?n:i.x==="right"?-n:-n/2,e=k.x==="left"?p:k.x==="right"?-p:-p/2,f=A&&A.size?A.size.width||0:0,g=A&&A.corner&&A.corner.precedance==="x"&&!b?f:0,h=c-a+g,j=a+n-u.width-c+g,m=d-(i.precedance==="x"||i.x===i.y?e:0)-(k.x==="center"?p/2:0),o=i.x==="center";b?(g=A&&A.corner&&A.corner.precedance==="y"?f:0,m=(i.x==="left"?1:-1)*d-g,v.left+=h>0?h:j>0?-j:0,v.left=Math.max(-w.offset.left+u.offset.left+(g&&A.corner.x==="center"?A.offset:0),a-m,Math.min(Math.max(-w.offset.left+u.offset.left+u.width,a+m),v.left))):(h>0&&(i.x!=="left"||j>0)?v.left-=m:j>0&&(i.x!=="right"||h>0)&&(v.left-=o?-m:m),v.left!==a&&o&&(v.left-=l.x),v.leftj&&(v.left=a));return v.left-a},top:function(a){var b=C.vertical==="shift",c=-w.offset.top+u.offset.top+u.scrollTop,d=i.y==="top"?o:i.y==="bottom"?-o:-o/2,e=k.y==="top"?q:k.y==="bottom"?-q:-q/2,f=A&&A.size?A.size.height||0:0,g=A&&A.corner&&A.corner.precedance==="y"&&!b?f:0,h=c-a+g,j=a+o-u.height-c+g,m=d-(i.precedance==="y"||i.x===i.y?e:0)-(k.y==="center"?q/2:0),n=i.y==="center";b?(g=A&&A.corner&&A.corner.precedance==="x"?f:0,m=(i.y==="top"?1:-1)*d-g,v.top+=h>0?h:j>0?-j:0,v.top=Math.max(-w.offset.top+u.offset.top+(g&&A.corner.x==="center"?A.offset:0),a-m,Math.min(Math.max(-w.offset.top+u.offset.top+u.height,a+m),v.top))):(h>0&&(i.y!=="top"||j>0)?v.top-=m:j>0&&(i.y!=="bottom"||h>0)&&(v.top-=n?-m:m),v.top!==a&&n&&(v.top-=l.y),v.top<0&&-v.top>j&&(v.top=a));return v.top-a}},E;if(a.isArray(e)&&e.length===2)k={x:"left",y:"top"},v={left:e[0],top:e[1]};else if(e==="mouse"&&(b&&b.pageX||G.event.pageX))k={x:"left",y:"top"},b=(b&&(b.type==="resize"||b.type==="scroll")?G.event:b&&b.pageX&&b.type==="mousemove"?b:h&&h.pageX&&(l.mouse||!b||!b.pageX)?{pageX:h.pageX,pageY:h.pageY}:!l.mouse&&G.origin&&G.origin.pageX&&s.show.distance?G.origin:b)||b||G.event||h||{},v={top:b.pageY,left:b.pageX};else{e==="event"?b&&b.target&&b.type!=="scroll"&&b.type!=="resize"?e=G.target=a(b.target):e=G.target:e=G.target=a(e.jquery?e:F.target),e=a(e).eq(0);if(e.length===0)return y;e[0]===document||e[0]===window?(p=g.iOS?window.innerWidth:e.width(),q=g.iOS?window.innerHeight:e.height(),e[0]===window&&(v={top:(u||e).scrollTop(),left:(u||e).scrollLeft()})):e.is("area")&&g.imagemap?v=g.imagemap(e,k,C.enabled?m:c):e[0].namespaceURI==="http://www.w3.org/2000/svg"&&g.svg?v=g.svg(e,k):(p=e.outerWidth(),q=e.outerHeight(),v=g.offset(e,w)),v.offset&&(p=v.width,q=v.height,x=v.flipoffset,v=v.offset);if(g.iOS<4.1&&g.iOS>3.1||g.iOS==4.3||!g.iOS&&t)E=a(window),v.left-=E.scrollLeft(),v.top-=E.scrollTop();v.left+=k.x==="right"?p:k.x==="center"?p/2:0,v.top+=k.y==="bottom"?q:k.y==="center"?q/2:0}v.left+=l.x+(i.x==="right"?-n:i.x==="center"?-n/2:0),v.top+=l.y+(i.y==="bottom"?-o:i.y==="center"?-o/2:0),C.enabled?(u={elem:u,height:u[(u[0]===window?"h":"outerH")+"eight"](),width:u[(u[0]===window?"w":"outerW")+"idth"](),scrollLeft:t?0:u.scrollLeft(),scrollTop:t?0:u.scrollTop(),offset:u.offset()||{left:0,top:0}},w={elem:w,scrollLeft:w.scrollLeft(),scrollTop:w.scrollTop(),offset:w.offset()||{left:0,top:0}},v.adjusted={left:C.horizontal!=="none"?C.left(v.left):0,top:C.vertical!=="none"?C.top(v.top):0},v.adjusted.left+v.adjusted.top&&D.attr("class",D[0].className.replace(/ui-tooltip-pos-\w+/i,j+"-pos-"+i.abbrev())),x&&v.adjusted.left&&(v.left+=x.left),x&&v.adjusted.top&&(v.top+=x.top)):v.adjusted={left:0,top:0},r.originalEvent=a.extend({},b),D.trigger(r,[y,v,u.elem||u]);if(r.isDefaultPrevented())return y;delete v.adjusted,d===c||isNaN(v.left)||isNaN(v.top)||e==="mouse"||!a.isFunction(f.effect)?D.css(v):a.isFunction(f.effect)&&(f.effect.call(D,y,a.extend({},v)),D.queue(function(b){a(this).css({opacity:"",height:""}),a.browser.msie&&this.style.removeAttribute("filter"),b()})),B=0;return y},redraw:function(){if(y.rendered<1||C)return y;var a=s.position.container,b,c,d,e;C=1,s.style.height&&D.css("height",s.style.height),s.style.width?D.css("width",s.style.width):(D.css("width","").addClass(q),c=D.width()+1,d=D.css("max-width")||"",e=D.css("min-width")||"",b=(d+e).indexOf("%")>-1?a.width()/100:0,d=(d.indexOf("%")>-1?b:1)*parseInt(d,10)||c,e=(e.indexOf("%")>-1?b:1)*parseInt(e,10)||0,c=d+e?Math.min(Math.max(c,e),d):c,D.css("width",Math.round(c)).removeClass(q)),C=0;return y},disable:function(b){"boolean"!==typeof b&&(b=!D.hasClass(l)&&!G.disabled),y.rendered?(D.toggleClass(l,b),a.attr(D[0],"aria-disabled",b)):G.disabled=!!b;return y},enable:function(){return y.disable(c)},destroy:function(){var b=r[0],c=a.attr(b,t),d=r.data("qtip");y.rendered&&(D.stop(1,0).remove(),a.each(y.plugins,function(){this.destroy&&this.destroy()})),clearTimeout(y.timers.show),clearTimeout(y.timers.hide),Q();if(!d||y===d)a.removeData(b,"qtip"),s.suppress&&c&&(a.attr(b,"title",c),r.removeAttr(t)),r.removeAttr("aria-describedby");r.unbind(".qtip-"+v),delete i[y.id];return r}})}function w(b){var e;if(!b||"object"!==typeof b)return c;if(b.metadata===d||"object"!==typeof b.metadata)b.metadata={type:b.metadata};if("content"in b){if(b.content===d||"object"!==typeof b.content||b.content.jquery)b.content={text:b.content};e=b.content.text||c,!a.isFunction(e)&&(!e&&!e.attr||e.length<1||"object"===typeof e&&!e.jquery)&&(b.content.text=c);if("title"in b.content){if(b.content.title===d||"object"!==typeof b.content.title)b.content.title={text:b.content.title};e=b.content.title.text||c,!a.isFunction(e)&&(!e&&!e.attr||e.length<1||"object"===typeof e&&!e.jquery)&&(b.content.title.text=c)}}if("position"in b)if(b.position===d||"object"!==typeof b.position)b.position={my:b.position,at:b.position};if("show"in b)if(b.show===d||"object"!==typeof b.show)b.show.jquery?b.show={target:b.show}:b.show={event:b.show};if("hide"in b)if(b.hide===d||"object"!==typeof b.hide)b.hide.jquery?b.hide={target:b.hide}:b.hide={event:b.hide};if("style"in b)if(b.style===d||"object"!==typeof b.style)b.style={classes:b.style};a.each(g,function(){this.sanitize&&this.sanitize(b)});return b}function v(){v.history=v.history||[],v.history.push(arguments);if("object"===typeof console){var a=console[console.warn?"warn":"log"],b=Array.prototype.slice.call(arguments),c;typeof arguments[0]==="string"&&(b[0]="qTip2: "+b[0]),c=a.apply?a.apply(console,b):a(b)}}"use strict";var b=!0,c=!1,d=null,e,f,g,h,i={},j="ui-tooltip",k="ui-widget",l="ui-state-disabled",m="div.qtip."+j,n=j+"-default",o=j+"-focus",p=j+"-hover",q=j+"-fluid",r="-31000px",s="_replacedByqTip",t="oldtitle",u;f=a.fn.qtip=function(g,h,i){var j=(""+g).toLowerCase(),k=d,l=a.makeArray(arguments).slice(1),m=l[l.length-1],n=this[0]?a.data(this[0],"qtip"):d;if(!arguments.length&&n||j==="api")return n;if("string"===typeof g){this.each(function(){var d=a.data(this,"qtip");if(!d)return b;m&&m.timeStamp&&(d.cache.event=m);if(j!=="option"&&j!=="options"||!h)d[j]&&d[j].apply(d[j],l);else if(a.isPlainObject(h)||i!==e)d.set(h,i);else{k=d.get(h);return c}});return k!==d?k:this}if("object"===typeof g||!arguments.length){n=w(a.extend(b,{},g));return f.bind.call(this,n,m)}},f.bind=function(d,j){return this.each(function(k){function r(b){function d(){p.render(typeof b==="object"||l.show.ready),m.show.add(m.hide).unbind(o)}if(p.cache.disabled)return c;p.cache.event=a.extend({},b),p.cache.target=b?a(b.target):[e],l.show.delay>0?(clearTimeout(p.timers.show),p.timers.show=setTimeout(d,l.show.delay),n.show!==n.hide&&m.hide.bind(n.hide,function(){clearTimeout(p.timers.show)})):d()}var l,m,n,o,p,q;q=a.isArray(d.id)?d.id[k]:d.id,q=!q||q===c||q.length<1||i[q]?f.nextid++:i[q]=q,o=".qtip-"+q+"-create",p=y.call(this,q,d);if(p===c)return b;l=p.options,a.each(g,function(){this.initialize==="initialize"&&this(p)}),m={show:l.show.target,hide:l.hide.target},n={show:a.trim(""+l.show.event).replace(/ /g,o+" ")+o,hide:a.trim(""+l.hide.event).replace(/ /g,o+" ")+o},/mouse(over|enter)/i.test(n.show)&&!/mouse(out|leave)/i.test(n.hide)&&(n.hide+=" mouseleave"+o),m.show.bind("mousemove"+o,function(a){h={pageX:a.pageX,pageY:a.pageY,type:"mousemove"},p.cache.onTarget=b}),m.show.bind(n.show,r),(l.show.ready||l.prerender)&&r(j)})},g=f.plugins={Corner:function(a){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,"center").toLowerCase(),this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase();var b=a.charAt(0);this.precedance=b==="t"||b==="b"?"y":"x",this.string=function(){return this.precedance==="y"?this.y+this.x:this.x+this.y},this.abbrev=function(){var a=this.x.substr(0,1),b=this.y.substr(0,1);return a===b?a:a==="c"||a!=="c"&&b!=="c"?b+a:a+b},this.clone=function(){return{x:this.x,y:this.y,precedance:this.precedance,string:this.string,abbrev:this.abbrev,clone:this.clone}}},offset:function(b,c){function j(a,b){d.left+=b*a.scrollLeft(),d.top+=b*a.scrollTop()}var d=b.offset(),e=b.closest("body")[0],f=c,g,h,i;if(f){do f.css("position")!=="static"&&(h=f.position(),d.left-=h.left+(parseInt(f.css("borderLeftWidth"),10)||0)+(parseInt(f.css("marginLeft"),10)||0),d.top-=h.top+(parseInt(f.css("borderTopWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0),!g&&(i=f.css("overflow"))!=="hidden"&&i!=="visible"&&(g=f));while((f=a(f[0].offsetParent)).length);g&&g[0]!==e&&j(g,1)}return d},iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,3})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_","."))||c,fn:{attr:function(b,c){if(this.length){var d=this[0],e="title",f=a.data(d,"qtip");if(b===e&&f&&"object"===typeof f&&f.options.suppress){if(arguments.length<2)return a.attr(d,t);f&&f.options.content.attr===e&&f.cache.attr&&f.set("content.text",c);return this.attr(t,c)}}return a.fn["attr"+s].apply(this,arguments)},clone:function(b){var c=a([]),d="title",e=a.fn["clone"+s].apply(this,arguments);b||e.filter("["+t+"]").attr("title",function(){return a.attr(this,t)}).removeAttr(t);return e}}},a.each(g.fn,function(c,d){if(!d||a.fn[c+s])return b;var e=a.fn[c+s]=a.fn[c];a.fn[c]=function(){return d.apply(this,arguments)||e.apply(this,arguments)}}),a.ui||(a["cleanData"+s]=a.cleanData,a.cleanData=function(b){for(var c=0,d;(d=b[c])!==e;c++)try{a(d).triggerHandler("removeqtip")}catch(f){}a["cleanData"+s](b)}),f.version="2.0.0pre",f.nextid=0,f.inactiveEvents="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),f.zindex=15e3,f.defaults={prerender:c,id:c,overwrite:b,suppress:b,content:{text:b,attr:"title",title:{text:c,button:c}},position:{my:"top left",at:"bottom right",target:c,container:c,viewport:c,adjust:{x:0,y:0,mouse:b,resize:b,method:"flip flip"},effect:function(b,d,e){a(this).animate(d,{duration:200,queue:c})}},show:{target:c,event:"mouseenter",effect:b,delay:90,solo:c,ready:c,autofocus:c},hide:{target:c,event:"mouseleave",effect:b,delay:0,fixed:c,inactive:c,leave:"window",distance:c},style:{classes:"",widget:c,width:c,height:c,def:b},events:{render:d,move:d,show:d,hide:d,toggle:d,visible:d,focus:d,blur:d}},g.ajax=function(a){var b=a.plugins.ajax;return"object"===typeof b?b:a.plugins.ajax=new z(a)},g.ajax.initialize="render",g.ajax.sanitize=function(a){var b=a.content,c;b&&"ajax"in b&&(c=b.ajax,typeof c!=="object"&&(c=a.content.ajax={url:c}),"boolean"!==typeof c.once&&c.once&&(c.once=!!c.once))},a.extend(b,f.defaults,{content:{ajax:{loading:b,once:b}}}),g.bgiframe=function(b){var d=a.browser,e=b.plugins.bgiframe;if(a("select, object").length<1||(!d.msie||(""+d.version).charAt(0)!=="6"))return c;return"object"===typeof e?e:b.plugins.bgiframe=new A(b)},g.bgiframe.initialize="render",g.imagemap=function(b,c,d){function n(a,b,c){var d=0,e=1,f=1,g=0,h=0,i=a.width,j=a.height;while(i>0&&j>0&&e>0&&f>0){i=Math.floor(i/2),j=Math.floor(j/2),c.x==="left"?e=i:c.x==="right"?e=a.width-i:e+=Math.floor(i/2),c.y==="top"?f=j:c.y==="bottom"?f=a.height-j:f+=Math.floor(j/2),d=b.length;while(d--){if(b.length<2)break;g=b[d][0]-a.offset.left,h=b[d][1]-a.offset.top,(c.x==="left"&&g>=e||c.x==="right"&&g<=e||c.x==="center"&&(ga.width-e)||c.y==="top"&&h>=f||c.y==="bottom"&&h<=f||c.y==="center"&&(ha.height-f))&&b.splice(d,1)}}return{left:b[0][0],top:b[0][1]}}b.jquery||(b=a(b));var e=(b[0].shape||b.attr("shape")).toLowerCase(),f=(b[0].coords||b.attr("coords")).split(","),g=[],h=a('img[usemap="#'+b.parent("map").attr("name")+'"]'),i=h.offset(),j={width:0,height:0,offset:{top:1e10,right:0,bottom:0,left:1e10}},k=0,l=0,m;i.left+=Math.ceil((h.outerWidth()-h.width())/2),i.top+=Math.ceil((h.outerHeight()-h.height())/2);if(e==="poly"){k=f.length;while(k--)l=[parseInt(f[--k],10),parseInt(f[k+1],10)],l[0]>j.offset.right&&(j.offset.right=l[0]),l[0]j.offset.bottom&&(j.offset.bottom=l[1]),l[1]",{"class":"ui-state-default ui-tooltip-close "+(s.style.widget?"":j+"-icon"),title:e,"aria-label":e}).prepend(a("",{"class":"ui-icon ui-icon-close",html:"×"})),F.button.appendTo(F.titlebar).attr("role","button").click(function(a){return D.hasClass(l)||y.hide(a),c}),y.redraw()}function L(){var c=A+"-title";F.titlebar&&J(),F.titlebar=a("
",{"class":j+"-titlebar "+(s.style.widget?"ui-widget-header":"")}).append(F.title=a("
",{id:c,"class":j+"-title","aria-atomic":b})).insertBefore(F.content).delegate(".ui-tooltip-close","mousedown keydown mouseup keyup mouseout",function(b){a(this).toggleClass("ui-state-active ui-state-focus",b.type.substr(-4)==="down")}).delegate(".ui-tooltip-close","mouseover mouseout",function(b){a(this).toggleClass("ui-state-hover",b.type==="mouseover")}),s.content.title.button?K():y.rendered&&y.redraw()}function M(a){var b=F.button,d=F.title;if(!y.rendered)return c;a?(d||L(),K()):b.remove()}function N(b,d){var e=F.title;if(!y.rendered||!b)return c;a.isFunction(b)&&(b=b.call(r,G.event,y));if(b===c||!b&&b!=="")return J(c);b.jquery&&b.length>0?e.empty().append(b.css({display:"block"})):e.html(b),y.redraw(),d!==c&&y.rendered&&D.is(":visible")&&y.reposition(G.event)}function O(b,d){function g(b){function i(e){e&&(delete h[e.src],clearTimeout(y.timers.img[e.src]),a(e).unbind(E)),a.isEmptyObject(h)&&(y.redraw(),d!==c&&y.reposition(G.event),b())}var g,h={};if((g=f.find("img[src]:not([height]):not([width])")).length===0)return i();g.each(function(b,c){if(h[c.src]!==e)return;var d=0,f=3;(function g(){if(c.height||c.width||d>f)return i(c);d+=1,y.timers.img[c.src]=setTimeout(g,700)})(),a(c).bind("error"+E+" load"+E,function(){i(this)}),h[c.src]=c})}var f=F.content;return!y.rendered||!b?c:(a.isFunction(b)&&(b=b.call(r,G.event,y)||""),b.jquery&&b.length>0?f.empty().append(b.css({display:"block"})):f.html(b),y.rendered<0?D.queue("fx",g):(C=0,g(a.noop)),y)}function P(){function j(a){if(D.hasClass(l))return c;clearTimeout(y.timers.show),clearTimeout(y.timers.hide);var d=function(){y.toggle(b,a)};s.show.delay>0?y.timers.show=setTimeout(d,s.show.delay):d()}function k(b){if(D.hasClass(l)||B||C)return c;var f=a(b.relatedTarget||b.target),g=f.closest(m)[0]===D[0],h=f[0]===e.show[0];clearTimeout(y.timers.show),clearTimeout(y.timers.hide);if(d.target==="mouse"&&g||s.hide.fixed&&/mouse(out|leave|move)/.test(b.type)&&(g||h)){try{b.preventDefault(),b.stopImmediatePropagation()}catch(i){}return}s.hide.delay>0?y.timers.hide=setTimeout(function(){y.hide(b)},s.hide.delay):y.hide(b)}function n(a){if(D.hasClass(l))return c;clearTimeout(y.timers.inactive),y.timers.inactive=setTimeout(function(){y.hide(a)},s.hide.inactive)}function o(a){D.is(":visible")&&y.reposition(a)}var d=s.position,e={show:s.show.target,hide:s.hide.target,viewport:a(d.viewport),document:a(document),body:a(document.body),window:a(window)},g={show:a.trim(""+s.show.event).split(" "),hide:a.trim(""+s.hide.event).split(" ")},i=a.browser.msie&&parseInt(a.browser.version,10)===6;D.bind("mouseenter"+E+" mouseleave"+E,function(a){var b=a.type==="mouseenter";b&&y.focus(a),D.toggleClass(p,b)}),s.hide.fixed&&(e.hide=e.hide.add(D),D.bind("mouseover"+E,function(){D.hasClass(l)||clearTimeout(y.timers.hide)})),/mouse(out|leave)/i.test(s.hide.event)?s.hide.leave==="window"&&e.window.bind("mouseout"+E+" blur"+E,function(a){/select|option/.test(a.target)&&!a.relatedTarget&&y.hide(a)}):/mouse(over|enter)/i.test(s.show.event)&&e.hide.bind("mouseleave"+E,function(a){clearTimeout(y.timers.show)}),(""+s.hide.event).indexOf("unfocus")>-1&&d.container.closest("html").bind("mousedown"+E,function(b){var c=a(b.target),d=!D.hasClass(l)&&D.is(":visible"),e=c.parents(m).filter(D[0]).length>0;c[0]!==r[0]&&c[0]!==D[0]&&!e&&!r.has(c[0]).length&&!c.attr("disabled")&&y.hide(b)}),"number"==typeof s.hide.inactive&&(e.show.bind("qtip-"+v+"-inactive",n),a.each(f.inactiveEvents,function(a,b){e.hide.add(F.tooltip).bind(b+E+"-inactive",n)})),a.each(g.hide,function(b,c){var d=a.inArray(c,g.show),f=a(e.hide);d>-1&&f.add(e.show).length===f.length||c==="unfocus"?(e.show.bind(c+E,function(a){D.is(":visible")?k(a):j(a)}),delete g.show[d]):e.hide.bind(c+E,k)}),a.each(g.show,function(a,b){e.show.bind(b+E,j)}),"number"==typeof s.hide.distance&&e.show.add(D).bind("mousemove"+E,function(a){var b=G.origin||{},c=s.hide.distance,d=Math.abs;(d(a.pageX-b.pageX)>=c||d(a.pageY-b.pageY)>=c)&&y.hide(a)}),d.target==="mouse"&&(e.show.bind("mousemove"+E,function(a){h={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}}),d.adjust.mouse&&(s.hide.event&&(D.bind("mouseleave"+E,function(a){(a.relatedTarget||a.target)!==e.show[0]&&y.hide(a)}),F.target.bind("mouseenter"+E+" mouseleave"+E,function(a){G.onTarget=a.type==="mouseenter"})),e.document.bind("mousemove"+E,function(a){G.onTarget&&!D.hasClass(l)&&D.is(":visible")&&y.reposition(a||h)}))),(d.adjust.resize||e.viewport.length)&&(a.event.special.resize?e.viewport:e.window).bind("resize"+E,o),(e.viewport.length||i&&D.css("position")==="fixed")&&e.viewport.bind("scroll"+E,o)}function Q(){var b=[s.show.target[0],s.hide.target[0],y.rendered&&F.tooltip[0],s.position.container[0],s.position.viewport[0],window,document];y.rendered?a([]).pushStack(a.grep(b,function(a){return typeof a=="object"})).unbind(E):s.show.target.unbind(E+"-create")}var y=this,z=document.body,A=j+"-"+v,B=0,C=0,D=a(),E=".qtip-"+v,F,G;y.id=v,y.rendered=c,y.elements=F={target:r},y.timers={img:{}},y.options=s,y.checks={},y.plugins={},y.cache=G={event:{},target:a(),disabled:c,attr:x,onTarget:c},y.checks.builtin={"^id$":function(d,e,g){var h=g===b?f.nextid:g,i=j+"-"+h;h!==c&&h.length>0&&!a("#"+i).length&&(D[0].id=i,F.content[0].id=i+"-content",F.title[0].id=i+"-title")},"^content.text$":function(a,b,c){O(c)},"^content.title.text$":function(a,b,c){if(!c)return J();!F.title&&c&&L(),N(c)},"^content.title.button$":function(a,b,c){M(c)},"^position.(my|at)$":function(a,b,c){"string"==typeof c&&(a[b]=new g.Corner(c))},"^position.container$":function(a,b,c){y.rendered&&D.appendTo(c)},"^show.ready$":function(){y.rendered?y.toggle(b):y.render(1)},"^style.classes$":function(a,b,c){D.attr("class",j+" qtip ui-helper-reset "+c)},"^style.widget|content.title":I,"^events.(render|show|move|hide|focus|blur)$":function(b,c,d){D[(a.isFunction(d)?"":"un")+"bind"]("tooltip"+c,d)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){var a=s.position;D.attr("tracking",a.target==="mouse"&&a.adjust.mouse),Q(),P()}},a.extend(y,{render:function(d){if(y.rendered)return y;var e=s.content.text,f=s.content.title.text,h=s.position,i=a.Event("tooltiprender");return a.attr(r[0],"aria-describedby",A),D=F.tooltip=a("
",{id:A,"class":j+" qtip ui-helper-reset "+n+" "+s.style.classes+" "+j+"-pos-"+s.position.my.abbrev(),width:s.style.width||"",height:s.style.height||"",tracking:h.target==="mouse"&&h.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":c,"aria-describedby":A+"-content","aria-hidden":b}).toggleClass(l,G.disabled).data("qtip",y).appendTo(s.position.container).append(F.content=a("
",{"class":j+"-content",id:A+"-content","aria-atomic":b})),y.rendered=-1,C=1,B=1,f&&(L(),a.isFunction(f)||N(f,c)),a.isFunction(e)||O(e,c),y.rendered=b,I(),a.each(s.events,function(b,c){a.isFunction(c)&&D.bind(b==="toggle"?"tooltipshow tooltiphide":"tooltip"+b,c)}),a.each(g,function(){this.initialize==="render"&&this(y)}),P(),D.queue("fx",function(a){i.originalEvent=G.event,D.trigger(i,[y]),C=0,B=0,y.redraw(),(s.show.ready||d)&&y.toggle(b,G.event,c),a()}),y},get:function(a){var b,c;switch(a.toLowerCase()){case"dimensions":b={height:D.outerHeight(),width:D.outerWidth()};break;case"offset":b=g.offset(D,s.position.container);break;default:c=H(a.toLowerCase()),b=c[0][c[1]],b=b.precedance?b.string():b}return b},set:function(e,f){function m(a,b){var c,d,e;for(c in k)for(d in k[c])if(e=(new RegExp(d,"i")).exec(a))b.push(e),k[c][d].apply(y,b)}var g=/^position\.(my|at|adjust|target|container)|style|content|show\.ready/i,h=/^content\.(title|attr)|style/i,i=c,j=c,k=y.checks,l;return"string"==typeof e?(l=e,e={},e[l]=f):e=a.extend(b,{},e),a.each(e,function(b,c){var d=H(b.toLowerCase()),f;f=d[0][d[1]],d[0][d[1]]="object"==typeof c&&c.nodeType?a(c):c,e[b]=[d[0],d[1],c,f],i=g.test(b)||i,j=h.test(b)||j}),w(s),B=C=1,a.each(e,m),B=C=0,D.is(":visible")&&y.rendered&&(i&&y.reposition(s.position.target==="mouse"?d:G.event),j&&y.redraw()),y},toggle:function(e,f){function q(){e?(a.browser.msie&&D[0].style.removeAttribute("filter"),D.css("overflow",""),"string"==typeof i.autofocus&&a(i.autofocus,D).focus(),p=a.Event("tooltipvisible"),p.originalEvent=f?G.event:d,D.trigger(p,[y]),i.target.trigger("qtip-"+v+"-inactive")):D.css({display:"",visibility:"",opacity:"",left:"",top:""})}if(!y.rendered)return e?y.render(1):y;var g=e?"show":"hide",i=s[g],j=D.is(":visible"),k=!f||s[g].target.length<2||G.target[0]===f.target,l=s.position,n=s.content,o,p;(typeof e).search("boolean|number")&&(e=!j);if(!D.is(":animated")&&j===e&&k)return y;if(f){if(/over|enter/.test(f.type)&&/out|leave/.test(G.event.type)&&f.target===s.show.target[0]&&D.has(f.relatedTarget).length)return y;G.event=a.extend({},f)}return p=a.Event("tooltip"+g),p.originalEvent=f?G.event:d,D.trigger(p,[y,90]),p.isDefaultPrevented()?y:(a.attr(D[0],"aria-hidden",!e),e?(G.origin=a.extend({},h),y.focus(f),a.isFunction(n.text)&&O(n.text,c),a.isFunction(n.title.text)&&N(n.title.text,c),!u&&l.target==="mouse"&&l.adjust.mouse&&(a(document).bind("mousemove.qtip",function(a){h={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}}),u=b),y.reposition(f,arguments[2]),(p.solo=!!i.solo)&&a(m,i.solo).not(D).qtip("hide",p)):(clearTimeout(y.timers.show),delete G.origin,u&&!a(m+'[tracking="true"]:visible',i.solo).not(D).length&&(a(document).unbind("mousemove.qtip"),u=c),y.blur(f)),k&&D.stop(1,0),i.effect===c?(D[g](),q.call(D)):a.isFunction(i.effect)?(i.effect.call(D,y),D.queue("fx",function(a){q(),a()})):D.fadeTo(90,e?1:0,q),e&&i.target.trigger("qtip-"+v+"-inactive"),y)},show:function(a){return y.toggle(b,a)},hide:function(a){return y.toggle(c,a)},focus:function(b){if(!y.rendered)return y;var c=a(m),d=parseInt(D[0].style.zIndex,10),e=f.zindex+c.length,g=a.extend({},b),h,i;return D.hasClass(o)||(i=a.Event("tooltipfocus"),i.originalEvent=g,D.trigger(i,[y,e]),i.isDefaultPrevented()||(d!==e&&(c.each(function(){this.style.zIndex>d&&(this.style.zIndex=this.style.zIndex-1)}),c.filter("."+o).qtip("blur",g)),D.addClass(o)[0].style.zIndex=e)),y},blur:function(b){var c=a.extend({},b),d;return D.removeClass(o),d=a.Event("tooltipblur"),d.originalEvent=c,D.trigger(d,[y]),y},reposition:function(b,d){if(!y.rendered||B)return y;B=1;var e=s.position.target,f=s.position,i=f.my,k=f.at,l=f.adjust,m=l.method.split(" "),n=D.outerWidth(),o=D.outerHeight(),p=0,q=0,r=a.Event("tooltipmove"),t=D.css("position")==="fixed",u=f.viewport,v={left:0,top:0},w=f.container,x=c,A=y.plugins.tip,C={horizontal:m[0],vertical:m[1]=m[1]||m[0],enabled:u.jquery&&e[0]!==window&&e[0]!==z&&l.method!=="none",left:function(a){var b=C.horizontal==="shift",c=-w.offset.left+u.offset.left+u.scrollLeft,d=i.x==="left"?n:i.x==="right"?-n:-n/2,e=k.x==="left"?p:k.x==="right"?-p:-p/2,f=A&&A.size?A.size.width||0:0,g=A&&A.corner&&A.corner.precedance==="x"&&!b?f:0,h=c-a+g,j=a+n-u.width-c+g,m=d-(i.precedance==="x"||i.x===i.y?e:0)-(k.x==="center"?p/2:0),o=i.x==="center";return b?(g=A&&A.corner&&A.corner.precedance==="y"?f:0,m=(i.x==="left"?1:-1)*d-g,v.left+=h>0?h:j>0?-j:0,v.left=Math.max(-w.offset.left+u.offset.left+(g&&A.corner.x==="center"?A.offset:0),a-m,Math.min(Math.max(-w.offset.left+u.offset.left+u.width,a+m),v.left))):(h>0&&(i.x!=="left"||j>0)?v.left-=m:j>0&&(i.x!=="right"||h>0)&&(v.left-=o?-m:m),v.left!==a&&o&&(v.left-=l.x),v.leftj&&(v.left=a)),v.left-a},top:function(a){var b=C.vertical==="shift",c=-w.offset.top+u.offset.top+u.scrollTop,d=i.y==="top"?o:i.y==="bottom"?-o:-o/2,e=k.y==="top"?q:k.y==="bottom"?-q:-q/2,f=A&&A.size?A.size.height||0:0,g=A&&A.corner&&A.corner.precedance==="y"&&!b?f:0,h=c-a+g,j=a+o-u.height-c+g,m=d-(i.precedance==="y"||i.x===i.y?e:0)-(k.y==="center"?q/2:0),n=i.y==="center";return b?(g=A&&A.corner&&A.corner.precedance==="x"?f:0,m=(i.y==="top"?1:-1)*d-g,v.top+=h>0?h:j>0?-j:0,v.top=Math.max(-w.offset.top+u.offset.top+(g&&A.corner.x==="center"?A.offset:0),a-m,Math.min(Math.max(-w.offset.top+u.offset.top+u.height,a+m),v.top))):(h>0&&(i.y!=="top"||j>0)?v.top-=m:j>0&&(i.y!=="bottom"||h>0)&&(v.top-=n?-m:m),v.top!==a&&n&&(v.top-=l.y),v.top<0&&-v.top>j&&(v.top=a)),v.top-a}},E;if(a.isArray(e)&&e.length===2)k={x:"left",y:"top"},v={left:e[0],top:e[1]};else if(e==="mouse"&&(b&&b.pageX||G.event.pageX))k={x:"left",y:"top"},b=(!b||b.type!=="resize"&&b.type!=="scroll"?b&&b.pageX&&b.type==="mousemove"?b:h&&h.pageX&&(l.mouse||!b||!b.pageX)?{pageX:h.pageX,pageY:h.pageY}:!l.mouse&&G.origin&&G.origin.pageX&&s.show.distance?G.origin:b:G.event)||b||G.event||h||{},v={top:b.pageY,left:b.pageX};else{e==="event"?b&&b.target&&b.type!=="scroll"&&b.type!=="resize"?e=G.target=a(b.target):e=G.target:e=G.target=a(e.jquery?e:F.target),e=a(e).eq(0);if(e.length===0)return y;e[0]===document||e[0]===window?(p=g.iOS?window.innerWidth:e.width(),q=g.iOS?window.innerHeight:e.height(),e[0]===window&&(v={top:(u||e).scrollTop(),left:(u||e).scrollLeft()})):e.is("area")&&g.imagemap?v=g.imagemap(e,k,C.enabled?m:c):e[0].namespaceURI==="http://www.w3.org/2000/svg"&&g.svg?v=g.svg(e,k):(p=e.outerWidth(),q=e.outerHeight(),v=g.offset(e,w)),v.offset&&(p=v.width,q=v.height,x=v.flipoffset,v=v.offset);if(g.iOS<4.1&&g.iOS>3.1||g.iOS==4.3||!g.iOS&&t)E=a(window),v.left-=E.scrollLeft(),v.top-=E.scrollTop();v.left+=k.x==="right"?p:k.x==="center"?p/2:0,v.top+=k.y==="bottom"?q:k.y==="center"?q/2:0}return v.left+=l.x+(i.x==="right"?-n:i.x==="center"?-n/2:0),v.top+=l.y+(i.y==="bottom"?-o:i.y==="center"?-o/2:0),C.enabled?(u={elem:u,height:u[(u[0]===window?"h":"outerH")+"eight"](),width:u[(u[0]===window?"w":"outerW")+"idth"](),scrollLeft:t?0:u.scrollLeft(),scrollTop:t?0:u.scrollTop(),offset:u.offset()||{left:0,top:0}},w={elem:w,scrollLeft:w.scrollLeft(),scrollTop:w.scrollTop(),offset:w.offset()||{left:0,top:0}},v.adjusted={left:C.horizontal!=="none"?C.left(v.left):0,top:C.vertical!=="none"?C.top(v.top):0},v.adjusted.left+v.adjusted.top&&D.attr("class",D[0].className.replace(/ui-tooltip-pos-\w+/i,j+"-pos-"+i.abbrev())),x&&v.adjusted.left&&(v.left+=x.left),x&&v.adjusted.top&&(v.top+=x.top)):v.adjusted={left:0,top:0},r.originalEvent=a.extend({},b),D.trigger(r,[y,v,u.elem||u]),r.isDefaultPrevented()?y:(delete v.adjusted,d===c||isNaN(v.left)||isNaN(v.top)||e==="mouse"||!a.isFunction(f.effect)?D.css(v):a.isFunction(f.effect)&&(f.effect.call(D,y,a.extend({},v)),D.queue(function(b){a(this).css({opacity:"",height:""}),a.browser.msie&&this.style.removeAttribute("filter"),b()})),B=0,y)},redraw:function(){if(y.rendered<1||C)return y;var a=s.position.container,b,c,d,e;return C=1,s.style.height&&D.css("height",s.style.height),s.style.width?D.css("width",s.style.width):(D.css("width","").addClass(q),c=D.width()+1,d=D.css("max-width")||"",e=D.css("min-width")||"",b=(d+e).indexOf("%")>-1?a.width()/100:0,d=(d.indexOf("%")>-1?b:1)*parseInt(d,10)||c,e=(e.indexOf("%")>-1?b:1)*parseInt(e,10)||0,c=d+e?Math.min(Math.max(c,e),d):c,D.css("width",Math.round(c)).removeClass(q)),C=0,y},disable:function(b){return"boolean"!=typeof b&&(b=!D.hasClass(l)&&!G.disabled),y.rendered?(D.toggleClass(l,b),a.attr(D[0],"aria-disabled",b)):G.disabled=!!b,y},enable:function(){return y.disable(c)},destroy:function(){var b=r[0],c=a.attr(b,t),d=r.data("qtip");y.rendered&&(D.stop(1,0).remove(),a.each(y.plugins,function(){this.destroy&&this.destroy()})),clearTimeout(y.timers.show),clearTimeout(y.timers.hide),Q();if(!d||y===d)a.removeData(b,"qtip"),s.suppress&&c&&(a.attr(b,"title",c),r.removeAttr(t)),r.removeAttr("aria-describedby");return r.unbind(".qtip-"+v),delete i[y.id],r}})}function y(e,h){var i,j,k,l,m,n=a(this),o=a(document.body),p=this===document?o:n,q=n.metadata?n.metadata(h.metadata):d,r=h.metadata.type==="html5"&&q?q[h.metadata.name]:d,s=n.data(h.metadata.name||"qtipopts");try{s=typeof s=="string"?(new Function("return "+s))():s}catch(u){v("Unable to parse HTML5 attribute data: "+s)}l=a.extend(b,{},f.defaults,h,typeof s=="object"?w(s):d,w(r||q)),j=l.position,l.id=e;if("boolean"==typeof l.content.text){k=n.attr(l.content.attr);if(l.content.attr===c||!k)return v("Unable to locate content for tooltip! Aborting render of tooltip on element: ",n),c;l.content.text=k}j.container.length||(j.container=o),j.target===c&&(j.target=p),l.show.target===c&&(l.show.target=p),l.show.solo===b&&(l.show.solo=j.container.closest("body")),l.hide.target===c&&(l.hide.target=p),l.position.viewport===b&&(l.position.viewport=j.container),j.at=new g.Corner(j.at),j.my=new g.Corner(j.my);if(a.data(this,"qtip"))if(l.overwrite)n.qtip("destroy");else if(l.overwrite===c)return c;return l.suppress&&(m=a.attr(this,"title"))&&a(this).removeAttr("title").attr(t,m),i=new x(n,l,e,!!k),a.data(this,"qtip",i),n.bind("remove.qtip-"+e+" removeqtip.qtip-"+e,function(){i.destroy()}),i}function z(d){var e=this,f=d.elements.tooltip,g=d.options.content.ajax,h=".qtip-ajax",i=/)<[^<]*)*<\/script>/gi,j=b,k=c,l;d.checks.ajax={"^content.ajax":function(a,b,c){b==="ajax"&&(g=c),b==="once"?e.init():g&&g.url?e.load():f.unbind(h)}},a.extend(e,{init:function(){return g&&g.url&&f.unbind(h)[g.once?"one":"bind"]("tooltipshow"+h,e.load),e},load:function(b,f){function p(){if(k)return;n&&(d.show(b.originalEvent),f=c),a.isFunction(g.complete)&&g.complete.apply(this,arguments)}function q(b){if(k)return;m&&(b=a("
").append(b.replace(i,"")).find(m)),d.set("content.text",b)}function r(a,b,c){if(k||a.status===0)return;d.set("content.text",b+": "+c)}var h=g.url.indexOf(" "),j=g.url,m,n=g.once&&!g.loading&&f;if(n)try{b.preventDefault()}catch(o){}else if(b&&b.isDefaultPrevented())return e;l&&l.abort&&l.abort(),h>-1&&(m=j.substr(h),j=j.substr(0,h)),l=a.ajax(a.extend({success:q,error:r,context:d},g,{url:j,complete:p}))},destroy:function(){l&&l.abort&&l.abort(),k=b}}),e.init()}function A(b){var c=this,d=b.elements,e=d.tooltip,f=".bgiframe-"+b.id;a.extend(c,{init:function(){d.bgiframe=a(''),d.bgiframe.appendTo(e),e.bind("tooltipmove"+f,c.adjust)},adjust:function(){var a=b.get("dimensions"),c=b.plugins.tip,f=d.tip,g,h;h=parseInt(e.css("border-left-width"),10)||0,h={left:-h,top:-h},c&&f&&(g=c.corner.precedance==="x"?["width","left"]:["height","top"],h[g[1]]-=f[g[0]]()),d.bgiframe.css(h).css(a)},destroy:function(){d.bgiframe.remove(),e.unbind(f)}}),c.init()}function B(d){var e=this,f=d.options.show.modal,h=d.elements,i=h.tooltip,j="#qtip-overlay",k=".qtipmodal",l=k+d.id,n="is-modal-qtip",p=a(document.body),q;d.checks.modal={"^show.modal.(on|blur)$":function(){e.init(),h.overlay.toggle(i.is(":visible"))}},a.extend(e,{init:function(){return f.on?(q=e.create(),i.attr(n,b).css("z-index",g.modal.zindex+a(m+"["+n+"]").length).unbind(k).unbind(l).bind("tooltipshow"+k+" tooltiphide"+k,function(b,c,d){var f=b.originalEvent;if(b.target===i[0])if(f&&b.type==="tooltiphide"&&/mouse(leave|enter)/.test(f.type)&&a(f.relatedTarget).closest(q[0]).length)try{b.preventDefault()}catch(g){}else(!f||f&&!f.solo)&&e[b.type.replace("tooltip","")](b,d)}).bind("tooltipfocus"+k,function(b){if(b.isDefaultPrevented()||b.target!==i[0])return;var c=a(m).filter("["+n+"]"),d=g.modal.zindex+c.length,e=parseInt(i[0].style.zIndex,10);q[0].style.zIndex=d-1,c.each(function(){this.style.zIndex>e&&(this.style.zIndex-=1)}),c.end().filter("."+o).qtip("blur",b.originalEvent),i.addClass(o)[0].style.zIndex=d;try{b.preventDefault()}catch(f){}}).bind("tooltiphide"+k,function(b){b.target===i[0]&&a("["+n+"]").filter(":visible").not(i).last().qtip("focus",b)}),f.escape&&a(window).unbind(l).bind("keydown"+l,function(a){a.keyCode===27&&i.hasClass(o)&&d.hide(a)}),f.blur&&h.overlay.unbind(l).bind("click"+l,function(a){i.hasClass(o)&&d.hide(a)}),e):e},create:function(){function d(){q.css({height:a(window).height(),width:a(window).width()})}var b=a(j);return b.length?h.overlay=b.insertAfter(a(m).last()):(q=h.overlay=a("
",{id:j.substr(1),html:"
",mousedown:function(){return c}}).insertAfter(a(m).last()),a(window).unbind(k).bind("resize"+k,d),d(),q)},toggle:function(d,g,h){if(d&&d.isDefaultPrevented())return e;var j=f.effect,k=g?"show":"hide",o=q.is(":visible"),r=a("["+n+"]").filter(":visible").not(i),s;return q||(q=e.create()),q.is(":animated")&&o===g||!g&&r.length?e:(g?(q.css({left:0,top:0}),q.toggleClass("blurs",f.blur),p.bind("focusin"+l,function(b){var d=a(b.target),e=d.closest(".qtip"),f=e.length<1?c:parseInt(e[0].style.zIndex,10)>parseInt(i[0].style.zIndex,10);!f&&a(b.target).closest(m)[0]!==i[0]&&i.find("input:visible").filter(":first").focus()})):p.undelegate("*","focusin"+l),q.stop(b,c),a.isFunction(j)?j.call(q,g):j===c?q[k]():q.fadeTo(parseInt(h,10)||90,g?1:0,function(){g||a(this).hide()}),g||q.queue(function(a){q.css({left:"",top:""}),a()}),e)},show:function(a,c){return e.toggle(a,b,c)},hide:function(a,b){return e.toggle(a,c,b)},destroy:function(){var b=q;return b&&(b=a("["+n+"]").not(i).length<1,b?(h.overlay.remove(),a(window).unbind(k)):h.overlay.unbind(k+d.id),p.undelegate("*","focusin"+l)),i.removeAttr(n).unbind(k)}}),e.init()}function C(a,b,c){var d=Math.ceil(b/2),e=Math.ceil(c/2),f={bottomright:[[0,0],[b,c],[b,0]],bottomleft:[[0,0],[b,0],[0,c]],topright:[[0,c],[b,0],[b,c]],topleft:[[0,0],[0,c],[b,c]],topcenter:[[0,c],[d,0],[b,c]],bottomcenter:[[0,0],[b,0],[d,c]],rightcenter:[[0,0],[b,e],[0,c]],leftcenter:[[b,0],[b,c],[0,e]]};return f.lefttop=f.bottomright,f.righttop=f.bottomleft,f.leftbottom=f.topright,f.rightbottom=f.topleft,f[a.string()]}function D(f,h){function t(a,d,g,h){if(!k.tip)return;var l=i.corner.clone(),n=g.adjusted,o=f.options.position.adjust.method.split(" "),p=o[0],q=o[1]||o[0],r={left:c,top:c,x:0,y:0},s,t={},u;i.corner.fixed!==b&&(p==="shift"&&l.precedance==="x"&&n.left&&l.y!=="center"?l.precedance=l.precedance==="x"?"y":"x":p==="flip"&&n.left&&(l.x=l.x==="center"?n.left>0?"left":"right":l.x==="left"?"right":"left"),q==="shift"&&l.precedance==="y"&&n.top&&l.x!=="center"?l.precedance=l.precedance==="y"?"x":"y":q==="flip"&&n.top&&(l.y=l.y==="center"?n.top>0?"top":"bottom":l.y==="top"?"bottom":"top"),l.string()!==m.corner.string()&&(m.top!==n.top||m.left!==n.left)&&i.update(l,c)),s=i.position(l,n),s.right!==e&&(s.left=-s.right),s.bottom!==e&&(s.top=-s.bottom),s.user=Math.max(0,j.offset);if(r.left=p==="shift"&&!!n.left)l.x==="center"?t["margin-left"]=r.x=s["margin-left"]-n.left:(u=s.right!==e?[n.left,-s.left]:[-n.left,s.left],(r.x=Math.max(u[0],u[1]))>u[0]&&(g.left-=n.left,r.left=c),t[s.right!==e?"right":"left"]=r.x);if(r.top=q==="shift"&&!!n.top)l.y==="center"?t["margin-top"]=r.y=s["margin-top"]-n.top:(u=s.bottom!==e?[n.top,-s.top]:[-n.top,s.top],(r.y=Math.max(u[0],u[1]))>u[0]&&(g.top-=n.top,r.top=c),t[s.bottom!==e?"bottom":"top"]=r.y);k.tip.css(t).toggle(!(r.x&&r.y||l.x==="center"&&r.y||l.y==="center"&&r.x)),g.left-=s.left.charAt?s.user:p!=="shift"||r.top||!r.left&&!r.top?s.left:0,g.top-=s.top.charAt?s.user:q!=="shift"||r.left||!r.left&&!r.top?s.top:0,m.left=n.left,m.top=n.top,m.corner=l.clone()}function u(a,b,c){b=b?b:a[a.precedance];var d=l.hasClass(q),e=k.titlebar&&a.y==="top",f=e?k.titlebar:k.content,g="border-"+b+"-width",h;return l.addClass(q),h=parseInt(f.css(g),10),h=(c?h||parseInt(l.css(g),10):h)||0,l.toggleClass(q,d),h}function v(b){var c=k.titlebar&&b.y==="top",d=c?k.titlebar:k.content,e=a.browser.mozilla,f=e?"-moz-":a.browser.webkit?"-webkit-":"",g=b.y+(e?"":"-")+b.x,h=f+(e?"border-radius-"+g:"border-"+g+"-radius");return parseInt(d.css(h),10)||parseInt(l.css(h),10)||0}function w(a){var b=a.precedance==="y",c=n[b?"width":"height"],d=n[b?"height":"width"],e=a.string().indexOf("center")>-1,f=c*(e?.5:1),g=Math.pow,h=Math.round,i,j,k,l=Math.sqrt(g(f,2)+g(d,2)),m=[p/f*l,p/d*l];return m[2]=Math.sqrt(g(m[0],2)-g(p,2)),m[3]=Math.sqrt(g(m[1],2)-g(p,2)),i=l+m[2]+m[3]+(e?0:m[0]),j=i/l,k=[h(j*d),h(j*c)],{height:k[b?0:1],width:k[b?1:0]}}var i=this,j=f.options.style.tip,k=f.elements,l=k.tooltip,m={top:0,left:0},n={width:j.width,height:j.height},o={},p=j.border||0,r=".qtip-tip",s=!!(a("")[0]||{}).getContext;i.corner=d,i.mimic=d,i.border=p,i.offset=j.offset,i.size=n,f.checks.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){i.init()||i.destroy(),f.reposition()},"^style.tip.(height|width)$":function(){n={width:j.width,height:j.height},i.create(),i.update(),f.reposition()},"^content.title.text|style.(classes|widget)$":function(){k.tip&&i.update()}},a.extend(i,{init:function(){var b=i.detectCorner()&&(s||a.browser.msie);return b&&(i.create(),i.update(),l.unbind(r).bind("tooltipmove"+r,t)),b},detectCorner:function(){var a=j.corner,d=f.options.position,e=d.at,h=d.my.string?d.my.string():d.my;return a===c||h===c&&e===c?c:(a===b?i.corner=new g.Corner(h):a.string||(i.corner=new g.Corner(a),i.corner.fixed=b),m.corner=new g.Corner(i.corner.string()),i.corner.string()!=="centercenter")},detectColours:function(b){var c,d,e,g=k.tip.css("cssText",""),h=b||i.corner,m=h[h.precedance],p="border-"+m+"-color",r="border"+m.charAt(0)+m.substr(1)+"Color",s=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,t="background-color",u="transparent",v=" !important",w=a(document.body).css("color"),x=f.elements.content.css("color"),y=k.titlebar&&(h.y==="top"||h.y==="center"&&g.position().top+n.height/2+j.offset",{"class":"ui-tooltip-tip"}).css({width:b,height:c}).prependTo(l),s?a("").appendTo(k.tip)[0].getContext("2d").save():(d='',k.tip.html(d+d),a("*",k.tip).bind("click mousedown",function(a){a.stopPropagation()}))},update:function(e,f){var h=k.tip,l=h.children(),q=n.width,r=n.height,t="px solid ",v="px dashed transparent",x=j.mimic,y=Math.round,z,A,B,D,E;e||(e=m.corner||i.corner),x===c?x=e:(x=new g.Corner(x),x.precedance=e.precedance,x.x==="inherit"?x.x=e.x:x.y==="inherit"?x.y=e.y:x.x===x.y&&(x[e.precedance]=e[e.precedance])),z=x.precedance,i.detectColours(e),o.border!=="transparent"&&o.border!=="#123456"?(p=u(e,d,b),j.border===0&&p>0&&(o.fill=o.border),i.border=p=j.border!==b?j.border:p):i.border=p=0,B=C(x,q,r),i.size=E=w(e),h.css(E),e.precedance==="y"?D=[y(x.x==="left"?p:x.x==="right"?E.width-q-p:(E.width-q)/2),y(x.y==="top"?E.height-r:0)]:D=[y(x.x==="left"?E.width-q:0),y(x.y==="top"?p:x.y==="bottom"?E.height-r-p:(E.height-r)/2)],s?(l.attr(E),A=l[0].getContext("2d"),A.restore(),A.save(),A.clearRect(0,0,3e3,3e3),A.translate(D[0],D[1]),A.beginPath(),A.moveTo(B[0][0],B[0][1]),A.lineTo(B[1][0],B[1][1]),A.lineTo(B[2][0],B[2][1]),A.closePath(),A.fillStyle=o.fill,A.strokeStyle=o.border,A.lineWidth=p*2,A.lineJoin="miter",A.miterLimit=100,p&&A.stroke(),A.fill()):(B="m"+B[0][0]+","+B[0][1]+" l"+B[1][0]+","+B[1][1]+" "+B[2][0]+","+B[2][1]+" xe",D[2]=p&&/^(r|b)/i.test(e.string())?parseFloat(a.browser.version,10)===8?2:1:0,l.css({antialias:""+(x.string().indexOf("center")>-1),left:D[0]-D[2]*Number(z==="x"),top:D[1]-D[2]*Number(z==="y"),width:q+p,height:r+p}).each(function(b){var c=a(this);c[c.prop?"prop":"attr"]({coordsize:q+p+" "+(r+p),path:B,fillcolor:o.fill,filled:!!b,stroked:!b}).css({display:p||b?"block":"none"}),!b&&c.html()===""&&c.html('')})),f!==c&&i.position(e)},position:function(d){var e=k.tip,f={},g=Math.max(0,j.offset),h,l,m;return j.corner===c||!e?c:(d=d||i.corner,h=d.precedance,l=w(d),m=[d.x,d.y],h==="x"&&m.reverse(),a.each(m,function(a,c){var e,i;c==="center"?(e=h==="y"?"left":"top",f[e]="50%",f["margin-"+e]=-Math.round(l[h==="y"?"width":"height"]/2)+g):(e=u(d,c,b),i=v(d),f[c]=a?p?u(d,c):0:g+(i>e?i:0))}),f[d[h]]-=l[h==="x"?"width":"height"],e.css({top:"",bottom:"",left:"",right:"",margin:""}).css(f),f)},destroy:function(){k.tip&&k.tip.remove(),l.unbind(r)}}),i.init()}var b=!0,c=!1,d=null,e,f,g,h,i={},j="ui-tooltip",k="ui-widget",l="ui-state-disabled",m="div.qtip."+j,n=j+"-default",o=j+"-focus",p=j+"-hover",q=j+"-fluid",r="-31000px",s="_replacedByqTip",t="oldtitle",u;f=a.fn.qtip=function(g,h,i){var j=(""+g).toLowerCase(),k=d,l=a.makeArray(arguments).slice(1),m=l[l.length-1],n=this[0]?a.data(this[0],"qtip"):d;if(!arguments.length&&n||j==="api")return n;if("string"==typeof g)return this.each(function(){var d=a.data(this,"qtip");if(!d)return b;m&&m.timeStamp&&(d.cache.event=m);if(j!=="option"&&j!=="options"||!h)d[j]&&d[j].apply(d[j],l);else{if(!a.isPlainObject(h)&&i===e)return k=d.get(h),c;d.set(h,i)}}),k!==d?k:this;if("object"==typeof g||!arguments.length)return n=w(a.extend(b,{},g)),f.bind.call(this,n,m)},f.bind=function(d,j){return this.each(function(k){function r(b){function d(){p.render(typeof b=="object"||l.show.ready),m.show.add(m.hide).unbind(o)}if(p.cache.disabled)return c;p.cache.event=a.extend({},b),p.cache.target=b?a(b.target):[e],l.show.delay>0?(clearTimeout(p.timers.show),p.timers.show=setTimeout(d,l.show.delay),n.show!==n.hide&&m.hide.bind(n.hide,function(){clearTimeout(p.timers.show)})):d()}var l,m,n,o,p,q;q=a.isArray(d.id)?d.id[k]:d.id,q=!q||q===c||q.length<1||i[q]?f.nextid++:i[q]=q,o=".qtip-"+q+"-create",p=y.call(this,q,d);if(p===c)return b;l=p.options,a.each(g,function(){this.initialize==="initialize"&&this(p)}),m={show:l.show.target,hide: +l.hide.target},n={show:a.trim(""+l.show.event).replace(/ /g,o+" ")+o,hide:a.trim(""+l.hide.event).replace(/ /g,o+" ")+o},/mouse(over|enter)/i.test(n.show)&&!/mouse(out|leave)/i.test(n.hide)&&(n.hide+=" mouseleave"+o),m.show.bind("mousemove"+o,function(a){h={pageX:a.pageX,pageY:a.pageY,type:"mousemove"},p.cache.onTarget=b}),m.show.bind(n.show,r),(l.show.ready||l.prerender)&&r(j)})},g=f.plugins={Corner:function(a){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,"center").toLowerCase(),this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase();var b=a.charAt(0);this.precedance=b==="t"||b==="b"?"y":"x",this.string=function(){return this.precedance==="y"?this.y+this.x:this.x+this.y},this.abbrev=function(){var a=this.x.substr(0,1),b=this.y.substr(0,1);return a===b?a:a==="c"||a!=="c"&&b!=="c"?b+a:a+b},this.clone=function(){return{x:this.x,y:this.y,precedance:this.precedance,string:this.string,abbrev:this.abbrev,clone:this.clone}}},offset:function(b,c){function j(a,b){d.left+=b*a.scrollLeft(),d.top+=b*a.scrollTop()}var d=b.offset(),e=b.closest("body")[0],f=c,g,h,i;if(f){do f.css("position")!=="static"&&(h=f.position(),d.left-=h.left+(parseInt(f.css("borderLeftWidth"),10)||0)+(parseInt(f.css("marginLeft"),10)||0),d.top-=h.top+(parseInt(f.css("borderTopWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0),!g&&(i=f.css("overflow"))!=="hidden"&&i!=="visible"&&(g=f));while((f=a(f[0].offsetParent)).length);g&&g[0]!==e&&j(g,1)}return d},iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,3})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_","."))||c,fn:{attr:function(b,c){if(this.length){var d=this[0],e="title",f=a.data(d,"qtip");if(b===e&&f&&"object"==typeof f&&f.options.suppress)return arguments.length<2?a.attr(d,t):(f&&f.options.content.attr===e&&f.cache.attr&&f.set("content.text",c),this.attr(t,c))}return a.fn["attr"+s].apply(this,arguments)},clone:function(b){var c=a([]),d="title",e=a.fn["clone"+s].apply(this,arguments);return b||e.filter("["+t+"]").attr("title",function(){return a.attr(this,t)}).removeAttr(t),e}}},a.each(g.fn,function(c,d){if(!d||a.fn[c+s])return b;var e=a.fn[c+s]=a.fn[c];a.fn[c]=function(){return d.apply(this,arguments)||e.apply(this,arguments)}}),a.ui||(a["cleanData"+s]=a.cleanData,a.cleanData=function(b){for(var c=0,d;(d=b[c])!==e;c++)try{a(d).triggerHandler("removeqtip")}catch(f){}a["cleanData"+s](b)}),f.version="2.0.0pre",f.nextid=0,f.inactiveEvents="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),f.zindex=15e3,f.defaults={prerender:c,id:c,overwrite:b,suppress:b,content:{text:b,attr:"title",title:{text:c,button:c}},position:{my:"top left",at:"bottom right",target:c,container:c,viewport:c,adjust:{x:0,y:0,mouse:b,resize:b,method:"flip flip"},effect:function(b,d,e){a(this).animate(d,{duration:200,queue:c})}},show:{target:c,event:"mouseenter",effect:b,delay:90,solo:c,ready:c,autofocus:c},hide:{target:c,event:"mouseleave",effect:b,delay:0,fixed:c,inactive:c,leave:"window",distance:c},style:{classes:"",widget:c,width:c,height:c,def:b},events:{render:d,move:d,show:d,hide:d,toggle:d,visible:d,focus:d,blur:d}},g.ajax=function(a){var b=a.plugins.ajax;return"object"==typeof b?b:a.plugins.ajax=new z(a)},g.ajax.initialize="render",g.ajax.sanitize=function(a){var b=a.content,c;b&&"ajax"in b&&(c=b.ajax,typeof c!="object"&&(c=a.content.ajax={url:c}),"boolean"!=typeof c.once&&c.once&&(c.once=!!c.once))},a.extend(b,f.defaults,{content:{ajax:{loading:b,once:b}}}),g.bgiframe=function(b){var d=a.browser,e=b.plugins.bgiframe;return a("select, object").length<1||!d.msie||(""+d.version).charAt(0)!=="6"?c:"object"==typeof e?e:b.plugins.bgiframe=new A(b)},g.bgiframe.initialize="render",g.imagemap=function(b,c,d){function n(a,b,c){var d=0,e=1,f=1,g=0,h=0,i=a.width,j=a.height;while(i>0&&j>0&&e>0&&f>0){i=Math.floor(i/2),j=Math.floor(j/2),c.x==="left"?e=i:c.x==="right"?e=a.width-i:e+=Math.floor(i/2),c.y==="top"?f=j:c.y==="bottom"?f=a.height-j:f+=Math.floor(j/2),d=b.length;while(d--){if(b.length<2)break;g=b[d][0]-a.offset.left,h=b[d][1]-a.offset.top,(c.x==="left"&&g>=e||c.x==="right"&&g<=e||c.x==="center"&&(ga.width-e)||c.y==="top"&&h>=f||c.y==="bottom"&&h<=f||c.y==="center"&&(ha.height-f))&&b.splice(d,1)}}return{left:b[0][0],top:b[0][1]}}b.jquery||(b=a(b));var e=(b[0].shape||b.attr("shape")).toLowerCase(),f=(b[0].coords||b.attr("coords")).split(","),g=[],h=a('img[usemap="#'+b.parent("map").attr("name")+'"]'),i=h.offset(),j={width:0,height:0,offset:{top:1e10,right:0,bottom:0,left:1e10}},k=0,l=0,m;i.left+=Math.ceil((h.outerWidth()-h.width())/2),i.top+=Math.ceil((h.outerHeight()-h.height())/2);if(e==="poly"){k=f.length;while(k--)l=[parseInt(f[--k],10),parseInt(f[k+1],10)],l[0]>j.offset.right&&(j.offset.right=l[0]),l[0]j.offset.bottom&&(j.offset.bottom=l[1]),l[1]