aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorNik Nyby <nikolas@gnu.org>2015-01-17 17:12:36 -0500
committerNik Nyby <nikolas@gnu.org>2015-01-17 17:12:36 -0500
commitada88090ead2c3b9d0804794c5f20f9b24d1c2b1 (patch)
tree2838a7eee6c5d74094216acebd86915e0ea1de42 /test
downloadlibrejsxul-ada88090ead2c3b9d0804794c5f20f9b24d1c2b1.tar.lz
librejsxul-ada88090ead2c3b9d0804794c5f20f9b24d1c2b1.tar.xz
librejsxul-ada88090ead2c3b9d0804794c5f20f9b24d1c2b1.zip
Import to new git repository
The old repository was using almost 100mb of space because of all the unnecessary files in the history. So I've imported the code to a new git repository. Unfortunately the history isn't viewable from this repository anymore. To see what happened with LibreJS before 2015, see the old Bazaar repo here: http://bzr.savannah.gnu.org/lh/librejs/
Diffstat (limited to 'test')
-rw-r--r--test/mock/long_string.js22
-rw-r--r--test/mock/mock_dom.js87
-rw-r--r--test/mock/mock_licenses.js26
-rw-r--r--test/mock/mock_nodes.js814
-rw-r--r--test/mock/mock_nodes_with_comments.js187
-rw-r--r--test/mock/realHtml.html226
-rw-r--r--test/test-accepted_scripts.js64
-rw-r--r--test/test-all_scripts.js39
-rw-r--r--test/test-allowed_referrers.js54
-rw-r--r--test/test-bug-frozen.js44
-rw-r--r--test/test-contact_finder.js214
-rw-r--r--test/test-contact_finder2.js88
-rw-r--r--test/test-cors-bug.js60
-rw-r--r--test/test-crypto-a.js43
-rw-r--r--test/test-crypto-b.js357
-rw-r--r--test/test-domHandler.js71
-rw-r--r--test/test-domParser.js36
-rw-r--r--test/test-free_libraries.js56
-rw-r--r--test/test-html_parser.js43
-rw-r--r--test/test-js_checker.js119
-rw-r--r--test/test-js_load_observer_1.js75
-rw-r--r--test/test-js_load_observer_3.js146
-rw-r--r--test/test-license_definitions.js46
-rw-r--r--test/test-narcissus_worker.js73
-rw-r--r--test/test-nonfree_checker.js101
-rw-r--r--test/test-nontrivial_checker.js180
-rw-r--r--test/test-privacy_checker.js55
-rw-r--r--test/test-relation_checker.js68
-rw-r--r--test/test-removed_scripts.js67
-rw-r--r--test/test-request.js102
-rw-r--r--test/test-script_detector.js49
-rw-r--r--test/test-script_object.js50
-rw-r--r--test/test-script_properties.js29
-rw-r--r--test/test-stream_loader.js35
-rw-r--r--test/test-ui_info.js42
-rw-r--r--test/test-url_handler.js78
-rw-r--r--test/test-web-label-finder.js195
-rw-r--r--test/test-web-labels.js42
-rw-r--r--test/test-windowProperty.js34
-rw-r--r--test/webpages/test-labels/index.html36
-rw-r--r--test/webpages/test-labels/js-licenses.html45
41 files changed, 4198 insertions, 0 deletions
diff --git a/test/mock/long_string.js b/test/mock/long_string.js
new file mode 100644
index 0000000..4d224fc
--- /dev/null
+++ b/test/mock/long_string.js
@@ -0,0 +1,22 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+exports.longString = "\n\n LibreJS Information\n\n Current Version: 2.4.2 -- 12/08/2011\n \n Copyright (C) 2011 Loic J. Duros.\n Permission is granted to copy, distribute and/or modify this document\n under the terms of the GNU Free Documentation License, Version 1.3\n or any later version published by the Free Software Foundation;\n with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.\n A copy of the license is included in the section entitled \"GNU\n Free Documentation License\".\n \n\nPlain text copy\nA plain text copy of this documentation is available here.\n\nOverview\nLibreJS is an add-on for GNU IceCat (Mozilla Firefox, Abrowser, Iceweasel, …) that\nprevents the execution of nonfree nontrivial JavaScript as described\nin \"The Javascript Trap\":\nhttp://www.gnu.org/philosophy/javascript-trap.html\nIt has been tested for Firefox 7. Please see the Known issues section\nin this document before using LibreJS.\n\nDisclaimer\n\nLibreJS is not a security tool and while its goal is to detect nonfree\n nontrivial JavaScript, it does not detect whether free or trivial\n code is malicious or not. You can use NoScript (or YesScript) in\n conjunction with LibreJS to ensure security of the JavaScript being\n loaded.\nBecause LibreJS intercepts http responses to analyze and remove\n JavaScript from a page, it will not analyze and block JavaScript if\n it is loaded locally as a file within the user's filesystem, for\n instance with file:///home/someone/test.html -- a request\n http://localhost, however, would be caught and analyzed by the\n add-on.\nLibreJS is always a work in progress. If you find a bug, please\n report it to lduros@gnu.org\n\n\nChanges from version 2.4.1 to version 2.4.2\nSee changelog.\n\nChanges from version 1.x to version 2\n1) The @licstart @licend stylized comments are now obligatory rather\nthan optional. We want to make sure an entire page is explicitely free\nbefore considering it as free.\n2) In version 1, all scripts that defined a function or method were\nflagged as nontrivial. In version 2, as described in The JavaScript\nTrap, it will only consider the JavaScript program as nontrivial if\nthe scripts define a function or a method and load external scripts\nusing the html <script> tag, or if an external script defines a method\nor a function. \n3) In the version 1, scripts on page and remote were analyzed individually.\n In version 2 (current version):\n \n all scripts that are directly embedded in an html page are\n analyzed as one to see whether they are trivial or free.\n If the on-page JavaScript is nonfree and nontrivial, all\n JavaScript is removed and none of the external files are\n analyzed.\n If the on-page JavaScript is free or trivial, the external\n scripts are then fetched and analyzed to find whether they are\n free or trivial individually.\n If any script, on-page or external, is found to be nontrivial,\n all JavaScript is removed from the page (inline scripts,\n intrinsec events in html attributes, external scripts, ...)\n If any free script is found to perform an AJAX request or embed\n another script dynamically, or any construct that is flagged as\n \"suspicious\", then any trivial code becomes \"nontrivial\", and\n all JavaScript is then removed.\n When all the code is free but loads JavaScript dynamically, all\n http responses of mime type javascript are checked to see\n whether they are free/trivial at request time, and rejected if\n they are nonfree nontrivial.\n\n4) In version 1, a pure JavaScript HTML partial parser was used to\n find <script> tags and other JavaScript elements on page. In\n version 2, we are using a heavily modified third-party script to\n load the http response intercepted into a hidden iframe with a data\n uri (the hidden iframe has JavaScript off, as well as plugins off,\n following the instructions in\n https://developer.mozilla.org/En/Displaying_web_content_in_an_extension_without_security_issues). \n We are then using JavaScript DOM methods to fetch and remove\n scripts. This new method is a lot more secure and less prone to\n forgetting some of the JavaScript or not finding weird\n constructs. It also removes parts of the issue with the freezing\n UI.\n5) We are now using the url module from the Node.js project\n (http://nodejs.org/) to convert relative path into absolute urls\n when the DOM is loaded with a data uri.\n\nScreenshots\n\n\n\nThe panel that shows the blocked JavaScript:\n http://lduros.net/assets/librejs/v1/screenshots/librejs-v1-blockedscript-panel.jpg\n\nThe preferences panel:\n http://lduros.net/assets/librejs/v1/screenshots/librejs-v1-preferences.jpg\n\n\n\nLicense\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program. If not, see http://www.gnu.org/licenses/.\n\nHow to use\n\nAfter installing the add-on, you will see the LibreJS widget in the\nadd-on bar at the bottom of the browser window. After loading a page,\nleft-click on the widget to view the list of JavaScript removed from\nthe page (both on page and external). Up to 1000 characters are\ndisplayed per Javascript piece, since some files are so large it\nbecomes impractical to display them in their entirety. See screenshot\nhere: \nhttp://lduros.net/assets/librejs/v1/screenshots/librejs-v1-blockedscript-panel.jpg\nYou can also take a look at the JS removed by looking at the\npage source: CTRL + U.\n\nLibreJS intercepts http responses and rewrites them after analyzing\nJavaScript within them. While it uses mime types to a certain extent,\nit does not rely only on them and attempts to analyze any file for\njavascript content (a content sniffer of some sort is on the way for a\nfuture release).\n\nThe add-on offers a few options (and more to come). You can access\nthese options by right-clicking the widget. Please ignore the add-on\ncontext menu that will appear (this is a bug with Firefox and the\nadd-on sdk).\n\nA panel should appear in the middle of the page, with two checkboxes\navailable: \nhttp://lduros.net/assets/librejs/v1/screenshots/librejs-v1-preferences.jpg\nCurrently, LibreJS searches for license mentions in two\nways, a short and a lazy way (the latter is optional). One uses\nexcerpts from the short notices usually provided by many licenses for\ninclusion within source files, e.g. for the GPLv2: \n <THISPROGRAM> is free software; you can redistribute it\n and/or modify it under the terms of the GNU General Public\n License as published by the Free Software Foundation; either\n version 2 of the License, or (at your option) any later\n version.\nWhen it finds a match, it flags the piece of JS as free. This is\ncalled short definition. Another type of notice we call \"lazy\", here\nis a popular example: \n Dual licensed under the MIT or GPL Version 3 licenses \nWhen the \"Do not tolerate lazy license mentions\" checkbox is checked,\nthe latter type of license mention is not used.\n\nTests\nIn order to better understand how LibreJS works, you can try to visit\nthese pages with LibreJS installed and enabled and see how they are\nbeing processed:\n\n1) http://lduros.net/assets/librejs/tests/trivial-inline-trivial-external/\n This page contains trivial on-page JavaScript code, and an external\n script that contains trivial JavaScript code.\n Therefore, all JavaScript is being executed.\n\n2) http://lduros.net/assets/librejs/tests/trivial-inline-nontrivial-external/\n This page contains trivial on-page JavaScript code, but loads an\n external script that defines a function (nontrivial) and is not\n free.\n Therefore, all JavaScript is REMOVED from the page.\n\n3) http://lduros.net/assets/librejs/tests/nontrivial-inline-trivial-external/\n This page contains nontrivial code on page, and trivial code in its\n external page.\n All JavaScript is REMOVED from the page.\n\n4) http://lduros.net/assets/librejs/tests/free-inline-free-external/\n This page contains free on-page (GPL 3) JavaScript, and free\n external Javascript. Therefore all JavaScript is being executed.\n\n5) http://lduros.net/assets/librejs/tests/free-inline-nonfree-nontrivial-external/\n This page contains free on-page JavaScript, but contains nonfree\n nontrivial JavaScript in its external file (ajax request).\n All JavaScript is REMOVED from the page.\n\n6) http://lduros.net/assets/librejs/tests/intrinsec-event/\n This page contains trivial on-page code, with an intrinsec event in\n an html attribute (onload).\n All JavaScript is being executed.\n\n7) http://lduros.net/assets/librejs/tests/trivial-inline-free-external-defines-function/\n This page contains on-page trivial JavaScript (only makes a window\n alert and loads an external script using the html <script> tag with the\n src attribute. The external script is free (GPL v3), and since it\n is only nontrivial because it defines a function, the on-page\n trivial code is allowed to use it.\n All JavaScript is being executed.\n\n8) http://lduros.net/assets/librejs/tests/trivial-inline-free-external-writes-script/\n This page contains trivial on-page JavaScript code, and loads an\n external script that is free.\n HOWEVER, this free external script loads a script\n dynamically. Therefore, since trivial code might be using it, no\n trivial code is allowed.\n Since the on-page trivial code is now nontrivial,\n all Javascript is REMOVED from the page.\n\n9) http://lduros.net/assets/librejs/tests/shelltypist/demo/real-life-example-with-jquery-free.html\n This is a real-life example of a small jQuery plugin. The on-page\n JavaScript code has a free license. The jQuery external file has a\n free (but lazily defined) licensed. The shelltypist.js file has a\n free license as well. All licenses are defined between @licstart\n and @licend. If the \"Do not consider lazy license mentions as free\"\n option is not checked (default), the JavaScript is executed,\n despite the fact that the jQuery license mentions is: \n Dual licensed under the MIT or GPL Version 2 licenses.\n If you check the \"Do not consider lazy license mentions as free\"\n option, then ALL JavaScript will be removed from the page after\n reload.\n\n10) http://lduros.net/assets/librejs/tests/shelltypist/demo/same-page-without-free-license.html\n This is the same page than 9) but does not have a free license for\n the main HTML page on-page script. While the actual code there is\n trivial, since jQuery defines methods that make use of AJAX,\n trivial code is not allowed, and no JavaScript is executed.\n\nOptions\n\n\nDo not tolerate lazy license mentions (e.g.: dual-licensed under\n ...)\n When checked, this option disallows the use of very brief\n mentions of a license. (\"Released under the MIT license\", ...)\n\n\nHow LibreJS detects nontrivial JavaScript\n\nLibreJS uses Narcissus lexer/parser\n(https://github.com/mozilla/narcissus) to perform a static check for a\nfew criteria: \n\nIf the program defines a method or a function and loads external\nscripts (using the <script> element and src attribute).\nIf the program has an external script and defines a function or a\nmethod.\nIf it makes an AJAX request using XMLHttpRequest or ActiveXObject.\nIf it loads an external script (creates a script tag somewhere in the\ndom).\n\nBecause the code isn't interpreted (static analysis only) and we don't\nkeep track of scope and what variables contain, we have to discard a\nfew constructs:\n- if eval() is used.\n- if methods are invoked using the bracket suffix, such as:\nt['meth'+'od'](arg);\n- if it using document.write() with a concatenation or a function\ncall.\nFree Licenses\nCurrently LibreJS checks for the following licenses:\n\n GNU General Public License version 2\n GNU General Public License version 3\n GNU All-Permissive License\nLesser GNU Public License version 2.1\nLesser GNU Public License version 3\n Apache License, Version 2.0\n GNU Affero General Public License version 3\n Boost Software License\n BSD 2-Clause License\n BSD 3-Clause License\n Mozilla Public License Version 1.1\n Expat License\n\n\nMore licenses are on the way for the upcoming versions.\nKnown issues of LibreJS version 2\n\nLibreJS currently analyzes the JavaScript on page and in the\n Javascript file using the same thread as the Mozilla Firefox\n browser. Depending on hardware, this causes the UI to freeze for a\n second or two when a large javascript file is being analyzed. I am\n planning on using a chrome worker for Narcissus in the near future\n (version 2), so that it can run in its own thread. This way large\n complex files won't freeze the UI. 11/14/2011 UPDATE: This has been\n partly addressed with the replacement of the recursive walkTree\n function with the iterative one.\nIt does not make good use of the caching system. Instead it dooms\n the cache entry when the response is of type text/html or\n javascript.\n\n\nFixed in version 2.2:\n- FIXED: Currently there is no option to interpret javascript in the current\n page or javascript file. In order to enable all Javascript back, you\n must disable the add-on, but it does not require a Firefox\n restart. A button is planned for the future release.\n\nFIXED: Clicking on an anchor link in the page currently loaded in the tab,\n or appending a #[anything] to the location bar will prevent the\n widget panel from displaying the removed Javascript. This is due to\n the fact that it tracks JS according to the url, and so the # is\n considered a new entry. However, the JavaScript is still being\n blocked properly. (Check source for that.)\n\nGNU Free Documentation Licence\nA verbatim copy of the GNU Free Documentation license is available here\n "; \ No newline at end of file
diff --git a/test/mock/mock_dom.js b/test/mock/mock_dom.js
new file mode 100644
index 0000000..a843889
--- /dev/null
+++ b/test/mock/mock_dom.js
@@ -0,0 +1,87 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var {Cc, Ci, Cu, Cm, Cr} = require("chrome");
+
+var parser = Cc["@mozilla.org/xmlextras/domparser;1"]
+ .createInstance(Ci.nsIDOMParser);
+
+exports.emptyDocument = function () {
+ return parser.parseFromString('<!doctype html><html></html>', 'text/html');
+};
+
+exports.rejectedScriptsDocument = function () {
+
+ var htmlWithRejectedScripts = "<!doctype html>" +
+ "<html>" +
+ "<head>" +
+ "<title>Fake Page</title>" +
+ "<script>var i = 0;</script>" +
+ "<script>var xhr = new XMLHttpRequest();</script>" +
+ "</head>" +
+ "<body>" +
+ "\n" +
+ "<h1></h1>" +
+ "<p></p>" +
+ "</body>" +
+ "</html>";
+ return parser.parseFromString(htmlWithRejectedScripts, "text/html");
+};
+
+exports.acceptedScriptsDocument = function () {
+
+ var htmlWithAcceptedScripts = "<!doctype html>" +
+ "<html>" +
+ "<head>" +
+ "<title>Fake Page</title>" +
+ "<script>var i = 0;" +
+ "var length = document.length;</script>" +
+ "<script>for (; i < length; i++) {" +
+ "console.log(i);" +
+ "} </script>" +
+ "</head>" +
+ "\n" +
+ "<body>" +
+ "<h1></h1>" +
+ "<p></p>" +
+ "</body>" +
+ "</html>";
+
+ return parser.parseFromString(htmlWithAcceptedScripts, "text/html");
+
+};
+
+exports.domWithOnAttrib = function () {
+
+ var html = "<!doctype html>" +
+ "<html>" +
+ "<head>" +
+ "<title>Fake Page</title>" +
+ "</head>" +
+ "\n" +
+ "<body onLoad=\"blah();\">" +
+ "<h1></h1>" +
+ "<p></p>" +
+ "</body>" +
+ "</html>";
+
+ return parser.parseFromString(html, "text/html");
+
+};
diff --git a/test/mock/mock_licenses.js b/test/mock/mock_licenses.js
new file mode 100644
index 0000000..c70f1b7
--- /dev/null
+++ b/test/mock/mock_licenses.js
@@ -0,0 +1,26 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+exports.mockLicenses = {
+ gplv2: {
+ 'name': 'GPLv2',
+ 'substrings': [{text: "This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.", type: licenses.types.SHORT}]
+ }
+};
diff --git a/test/mock/mock_nodes.js b/test/mock/mock_nodes.js
new file mode 100644
index 0000000..26eae70
--- /dev/null
+++ b/test/mock/mock_nodes.js
@@ -0,0 +1,814 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+const types = require("js_checker/constant_types").token;
+
+
+exports.mockNodes = {
+ "alert('this is completely trivial');": {type:types.SCRIPT, lineno:1, children:[{type:types.SEMICOLON, value:"alert", lineno:1, start:0, end:34, children:[], blockComments:[], expression:{type:types.CALL, value:"(", lineno:1, start:0, end:34, children:[{type:types.IDENTIFIER, value:"alert", lineno:1, start:0, end:5, children:[], generatingSource:true}, {type:types.LIST, value:"(", lineno:1, start:5, end:34, children:[{type:types.STRING, value:"this is completely trivial", lineno:1, start:6, end:34, children:[], generatingSource:true}], generatingSource:true}], generatingSource:true}, generatingSource:true}], funDecls:[], varDecls:[], modDefns:{table:null, size:0}, modAssns:{table:null, size:0}, modDecls:{table:null, size:0}, modLoads:{table:null, size:0}, impDecls:[], expDecls:[], exports:{table:null, size:0}, hasEmptyReturn:false, hasReturnWithValue:false, hasYield:false, generatingSource:true},
+ "var myObj = { 'myMethod': function (arg) { alert(arg); } }":
+ {type:types.SCRIPT, lineno:1, children:[{type:types.VAR, value:"var", lineno:1, start:0, end:9, children:[{type:types.IDENTIFIER, value:"myObj", lineno:1, start:4, end:9, children:[], name:"myObj", readOnly:false, initializer:{type:types.OBJECT_INIT, value:"{", lineno:1, start:12, end:56, children:[{type:types.PROPERTY_INIT, value:":", lineno:1, start:14, end:56, children:[{type:types.IDENTIFIER, value:"myMethod", lineno:1, start:14, end:24, children:[], generatingSource:true}, {type:types.FUNCTION, value:"function", lineno:1, start:26, end:56, children:[], params:["arg"], paramComments:[null], blockComments:null, body:{type:types.SCRIPT, value:"{", lineno:1, start:41, end:52, children:[{type:types.SEMICOLON, value:"alert", lineno:1, start:43, end:52, children:[], blockComments:[], expression:{type:types.CALL, value:"(", lineno:1, start:43, end:52, children:[{type:types.IDENTIFIER, value:"alert", lineno:1, start:43, end:48, children:[], generatingSource:true}, {type:types.LIST, value:"(", lineno:1, start:48, end:52, children:[{type:types.IDENTIFIER, value:"arg", lineno:1, start:49, end:52, children:[], generatingSource:true}], generatingSource:true}], generatingSource:true}, generatingSource:true}], funDecls:[], varDecls:[], modDefns:{table:null, size:0}, modAssns:{table:null, size:0}, modDecls:{table:null, size:0}, modLoads:{table:null, size:0}, impDecls:[], expDecls:[], exports:{table:null, size:0}, hasEmptyReturn:false, hasReturnWithValue:false, hasYield:false, generatingSource:true}, functionForm:1, generatingSource:true}], blockComments:[], generatingSource:true}], generatingSource:true}, blockComment:null, generatingSource:true}], destructurings:[], blockComments:[], generatingSource:true}], funDecls:[], varDecls:[{type:types.IDENTIFIER, value:"myObj", lineno:1, start:4, end:9, children:[], name:"myObj", readOnly:false, initializer:{type:types.OBJECT_INIT, value:"{", lineno:1, start:12, end:56, children:[{type:types.PROPERTY_INIT, value:":", lineno:1, start:14, end:56, children:[{type:types.IDENTIFIER, value:"myMethod", lineno:1, start:14, end:24, children:[], generatingSource:true}, {type:types.FUNCTION, value:"function", lineno:1, start:26, end:56, children:[], params:["arg"], paramComments:[null], blockComments:null, body:{type:types.SCRIPT, value:"{", lineno:1, start:41, end:52, children:[{type:types.SEMICOLON, value:"alert", lineno:1, start:43, end:52, children:[], blockComments:[], expression:{type:types.CALL, value:"(", lineno:1, start:43, end:52, children:[{type:types.IDENTIFIER, value:"alert", lineno:1, start:43, end:48, children:[], generatingSource:true}, {type:types.LIST, value:"(", lineno:1, start:48, end:52, children:[{type:types.IDENTIFIER, value:"arg", lineno:1, start:49, end:52, children:[], generatingSource:true}], generatingSource:true}], generatingSource:true}, generatingSource:true}], funDecls:[], varDecls:[], modDefns:{table:null, size:0}, modAssns:{table:null, size:0}, modDecls:{table:null, size:0}, modLoads:{table:null, size:0}, impDecls:[], expDecls:[], exports:{table:null, size:0}, hasEmptyReturn:false, hasReturnWithValue:false, hasYield:false, generatingSource:true}, functionForm:1, generatingSource:true}], blockComments:[], generatingSource:true}], generatingSource:true}, blockComment:null, generatingSource:true}], modDefns:{table:null, size:0}, modAssns:{table:null, size:0}, modDecls:{table:null, size:0}, modLoads:{table:null, size:0}, impDecls:[], expDecls:[], exports:{table:null, size:0}, hasEmptyReturn:false, hasReturnWithValue:false, hasYield:false, generatingSource:true},
+ "function test (myArgument) { doSomething(); }":
+ {type:types.SCRIPT, lineno:1, children:[{type:types.FUNCTION,
+ value:"function", lineno:1, start:0, end:45, children:[],
+ params:["myArgument"], paramComments:[null], blockComments:[],
+ name:"test", body:{type:types.SCRIPT, value:"{", lineno:1, start:27,
+ end:41, children:[{type:types.SEMICOLON, value:"doSomething", lineno:1,
+ start:29, end:41, children:[], blockComments:[],
+ expression:{type:types.CALL, value:"(", lineno:1, start:29, end:41,
+ children:[{type:types.IDENTIFIER, value:"doSomething", lineno:1,
+ start:29, end:40, children:[], generatingSource:true}, {type:types.LIST,
+ value:"(", lineno:1, start:40, end:41, children:[],
+ generatingSource:true}], generatingSource:true},
+ generatingSource:true}], funDecls:[], varDecls:[],
+ modDefns:{table:null, size:0}, modAssns:{table:null, size:0},
+ modDecls:{table:null, size:0}, modLoads:{table:null, size:0},
+ impDecls:[], expDecls:[], exports:{table:null, size:0},
+ hasEmptyReturn:false, hasReturnWithValue:false, hasYield:false,
+ generatingSource:true}, functionForm:0, generatingSource:true}],
+ funDecls:[{type:types.FUNCTION, value:"function", lineno:1, start:0,
+ end:45, children:[], params:["myArgument"], paramComments:[null],
+ blockComments:[], name:"test", body:{type:types.SCRIPT, value:"{",
+ lineno:1, start:27, end:41, children:[{type:types.SEMICOLON,
+ value:"doSomething", lineno:1, start:29, end:41, children:[],
+ blockComments:[], expression:{type:types.CALL, value:"(", lineno:1,
+ start:29, end:41, children:[{type:types.IDENTIFIER, value:"doSomething",
+ lineno:1, start:29, end:40, children:[], generatingSource:true},
+ {type:types.LIST, value:"(", lineno:1, start:40, end:41, children:[],
+ generatingSource:true}], generatingSource:true},
+ generatingSource:true}], funDecls:[], varDecls:[],
+ modDefns:{table:null, size:0}, modAssns:{table:null, size:0},
+ modDecls:{table:null, size:0}, modLoads:{table:null, size:0},
+ impDecls:[], expDecls:[], exports:{table:null, size:0},
+ hasEmptyReturn:false, hasReturnWithValue:false, hasYield:false,
+ generatingSource:true}, functionForm:0, generatingSource:true}],
+ varDecls:[], modDefns:{table:null, size:0}, modAssns:{table:null,
+ size:0}, modDecls:{table:null, size:0}, modLoads:{table:null,
+ size:0}, impDecls:[], expDecls:[], exports:{table:null, size:0},
+ hasEmptyReturn:false, hasReturnWithValue:false, hasYield:false,
+ generatingSource:true},
+
+ "var def = 'blah';var i = 0;\n\n def = 'something else';": {type:types.SCRIPT,
+ lineno:1, children:[{type:types.VAR, value:"var", lineno:1, start:0,
+ end:7, children:[{type:types.IDENTIFIER, value:"def", lineno:1, start:4,
+ end:7, children:[], name:"def", readOnly:false,
+ initializer:{type:types.STRING, value:"blah", lineno:1, start:10,
+ end:16, children:[], generatingSource:true}, blockComment:null,
+ generatingSource:true}], destructurings:[], blockComments:[],
+ generatingSource:true}, {type:types.VAR, value:"var", lineno:1,
+ start:17, end:22, children:[{type:types.IDENTIFIER, value:"i", lineno:1,
+ start:21, end:22, children:[], name:"i", readOnly:false,
+ initializer:{type:types.NUMBER, value:0, lineno:1, start:25, end:26,
+ children:[], generatingSource:true}, blockComment:null,
+ generatingSource:true}], destructurings:[], blockComments:[],
+ generatingSource:true}, {type:types.SEMICOLON, value:"def", lineno:3,
+ start:30, end:52, children:[], blockComments:[],
+ expression:{type:types.ASSIGN, value:";", lineno:1, start:26, end:52,
+ children:[{type:types.IDENTIFIER, value:"def", lineno:3, start:30,
+ end:33, children:[], generatingSource:true}, {type:types.STRING,
+ value:"something else", lineno:3, start:36, end:52, children:[],
+ generatingSource:true}], blockComment:null,
+ generatingSource:true}, generatingSource:true}], funDecls:[],
+ varDecls:[{type:types.IDENTIFIER, value:"def", lineno:1, start:4, end:7,
+ children:[], name:"def", readOnly:false, initializer:{type:types.STRING,
+ value:"blah", lineno:1, start:10, end:16, children:[],
+ generatingSource:true}, blockComment:null, generatingSource:true},
+ {type:types.IDENTIFIER, value:"i", lineno:1, start:21, end:22,
+ children:[], name:"i", readOnly:false, initializer:{type:types.NUMBER,
+ value:0, lineno:1, start:25, end:26, children:[],
+ generatingSource:true}, blockComment:null,
+ generatingSource:true}], modDefns:{table:null, size:0},
+ modAssns:{table:null, size:0}, modDecls:{table:null, size:0},
+ modLoads:{table:null, size:0}, impDecls:[], expDecls:[],
+ exports:{table:null, size:0}, hasEmptyReturn:false,
+ hasReturnWithValue:false, hasYield:false, generatingSource:true},
+
+'function example(param1) {}': {
+ type: 78,
+ body: {
+ type: 0,
+ end: 27,
+ hasEmptyReturn: false,
+ hasReturnWithValue: false,
+ isGenerator: false,
+ lineno: 1,
+ start: 26,
+ value: "{",
+ },
+ end: 29,
+ functionForm: 0,
+ lineno: 1,
+ name: "example",
+ params: "param1",
+ start: 0,
+ value: "function"
+},
+'eval': {
+ type: 60,
+ end: 31,
+ lineno: 1,
+ start: 27,
+ value: 'eval'
+},
+'evaluate': {
+ type: 60,
+ end: 31,
+ lineno: 1,
+ start: 27,
+ value: 'evaluate'
+},
+"window['eval']('var i;');": {
+ "type": 46,
+ "value": "(",
+ "lineno": 1,
+ "start": 8,
+ "end": 31,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 48,
+ "value": "[",
+ "lineno": 1,
+ "start": 8,
+ "end": 21,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "window",
+ "lineno": 1,
+ "start": 8,
+ "end": 14,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 62,
+ "value": "eval",
+ "lineno": 1,
+ "start": 15,
+ "end": 21,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": 55,
+ "value": "(",
+ "lineno": 1,
+ "start": 22,
+ "end": 31,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 62,
+ "value": "var i;",
+ "lineno": 1,
+ "start": 23,
+ "end": 31,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ }
+ ]
+},
+"array[num] = 'some text';": {
+ "type": 4,
+ "value": ";",
+ "lineno": 1,
+ "start": 11,
+ "end": 37,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 48,
+ "value": "[",
+ "lineno": 2,
+ "start": 13,
+ "end": 22,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "array",
+ "lineno": 2,
+ "start": 13,
+ "end": 18,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "num",
+ "lineno": 2,
+ "start": 19,
+ "end": 22,
+ "tokenizer": "",
+ "children": []
+ }
+ ],
+ "assignOp": null
+ },
+ {
+ "type": 62,
+ "value": "some text",
+ "lineno": 2,
+ "start": 26,
+ "end": 37,
+ "tokenizer": "",
+ "children": []
+ }
+ ],
+ "blockComment": null,
+ "assignOp": null
+},
+'XMLHttpRequest': {
+ "type": 60,
+ "value": "XMLHttpRequest",
+ "lineno": 3,
+ "start": 16,
+ "end": 30,
+ "tokenizer": "",
+ "children": []
+},
+'ActiveXObject': {
+ "type": 60,
+ "value": "ActiveXObject",
+ "lineno": 3,
+ "start": 16,
+ "end": 30,
+ "tokenizer": "",
+ "children": []
+},
+"oReq.open('GET', 'http://localhost/test.xml', true;)": {
+ "type": 46,
+ "value": "(",
+ "lineno": 3,
+ "start": 2,
+ "end": 52,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 3,
+ "start": 2,
+ "end": 11,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "oReq",
+ "lineno": 3,
+ "start": 2,
+ "end": 6,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "open",
+ "lineno": 3,
+ "start": 7,
+ "end": 11,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": 55,
+ "value": "(",
+ "lineno": 3,
+ "start": 11,
+ "end": 52,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 62,
+ "value": "GET",
+ "lineno": 3,
+ "start": 12,
+ "end": 17,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 62,
+ "value": "http://localhost/test.xml",
+ "lineno": 3,
+ "start": 19,
+ "end": 46,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 91,
+ "value": "true",
+ "lineno": 3,
+ "start": 48,
+ "end": 52,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ }
+ ]
+},
+"oReq.open('a random string');": {
+ "type": 46,
+ "value": "(",
+ "lineno": 3,
+ "start": 2,
+ "end": 52,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 3,
+ "start": 2,
+ "end": 11,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "oReq",
+ "lineno": 3,
+ "start": 2,
+ "end": 6,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "open",
+ "lineno": 3,
+ "start": 7,
+ "end": 11,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": 55,
+ "value": "(",
+ "lineno": 3,
+ "start": 11,
+ "end": 52,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 62,
+ "value": "a random string",
+ "lineno": 3,
+ "start": 12,
+ "end": 17,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ }
+ ]
+},
+"document.createElement('script');": {
+ "type": 46,
+ "value": "(",
+ "lineno": 1,
+ "start": 0,
+ "end": 31,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 1,
+ "start": 0,
+ "end": 22,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "document",
+ "lineno": 1,
+ "start": 0,
+ "end": 8,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "createElement",
+ "lineno": 1,
+ "start": 9,
+ "end": 22,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": 55,
+ "value": "(",
+ "lineno": 1,
+ "start": 22,
+ "end": 31,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 62,
+ "value": "script",
+ "lineno": 1,
+ "start": 23,
+ "end": 31,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ }
+ ]
+},
+'document.write("script src="evil-js.js"type="text/javascript></script>")': {
+ "type": 46,
+ "value": "(",
+ "lineno": 2,
+ "start": 1,
+ "end": 36,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 2,
+ "start": 1,
+ "end": 15,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "document",
+ "lineno": 2,
+ "start": 1,
+ "end": 9,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "write",
+ "lineno": 2,
+ "start": 10,
+ "end": 15,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": 55,
+ "value": "(",
+ "lineno": 2,
+ "start": 15,
+ "end": 36,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 62,
+ "value": "\n\n<script src=\"evil-js.js\"type=\"text/javascript></script>\n\n",
+ "lineno": 2,
+ "start": 16,
+ "end": 36,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ }
+ ]
+},
+"document.write('a ' + ' text');": {
+ "type": 46,
+ "value": "(",
+ "lineno": 2,
+ "start": 1,
+ "end": 36,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 2,
+ "start": 1,
+ "end": 15,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "document",
+ "lineno": 2,
+ "start": 1,
+ "end": 9,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "write",
+ "lineno": 2,
+ "start": 10,
+ "end": 15,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": 55,
+ "value": "(",
+ "lineno": 2,
+ "start": 15,
+ "end": 36,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 24,
+ "value": "+",
+ "lineno": 2,
+ "start": 16,
+ "end": 29,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 62,
+ "value": "scri",
+ "lineno": 2,
+ "start": 16,
+ "end": 22,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 62,
+ "value": "pt",
+ "lineno": 2,
+ "start": 25,
+ "end": 29,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+},
+"document.write('<h1>some text</h1>')": {
+ "lineno": 1,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 2,
+ "value": "document",
+ "lineno": 2,
+ "start": 1,
+ "end": 36,
+ "tokenizer": "",
+ "children": [],
+ "blockComments": [],
+ "expression": {
+ "type": 46,
+ "value": "(",
+ "lineno": 2,
+ "start": 1,
+ "end": 36,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 2,
+ "start": 1,
+ "end": 15,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "document",
+ "lineno": 2,
+ "start": 1,
+ "end": 9,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "write",
+ "lineno": 2,
+ "start": 10,
+ "end": 15,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": 55,
+ "value": "(",
+ "lineno": 2,
+ "start": 15,
+ "end": 36,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 62,
+ "value": "\n\n<h1>some text</h1>\n\n",
+ "lineno": 2,
+ "start": 16,
+ "end": 36,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ],
+},
+'element.innerHTML = "<script src=\'externalscript.js\'></script>";': {
+ "lineno": 1,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 1,
+ "start": 0,
+ "end": 17,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "element",
+ "lineno": 1,
+ "start": 0,
+ "end": 7,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "innerHTML",
+ "lineno": 1,
+ "start": 8,
+ "end": 17,
+ "tokenizer": "",
+ "children": []
+ }
+ ],
+ "assignOp": null
+ },
+ {
+ "type": 62,
+ "value": '<script src=\'externalscript.js\'></script>',
+ "lineno": 1,
+ "start": 20,
+ "end": 63,
+ "tokenizer": "",
+ "children": []
+ }
+ ],
+ "type": 4,
+ "assignOp": null
+},
+'element.innerHTML = "<h1>A headline!</h1>";': {
+ "lineno": 1,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 1,
+ "start": 0,
+ "end": 17,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "element",
+ "lineno": 1,
+ "start": 0,
+ "end": 7,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "innerHTML",
+ "lineno": 1,
+ "start": 8,
+ "end": 17,
+ "tokenizer": "",
+ "children": []
+ }
+ ],
+ "assignOp": null
+ },
+ {
+ "type": 62,
+ "value": '<h1>A Headline!</h1>',
+ "lineno": 1,
+ "start": 20,
+ "end": 63,
+ "tokenizer": "",
+ "children": []
+ }
+ ],
+ "type": 4,
+ "assignOp": null
+},
+'element.innerHTML = "script src" + "=\'eviljs.js\'";': {
+ "lineno": 1,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 1,
+ "start": 0,
+ "end": 17,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 60,
+ "value": "element",
+ "lineno": 1,
+ "start": 0,
+ "end": 7,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "innerHTML",
+ "lineno": 1,
+ "start": 8,
+ "end": 17,
+ "tokenizer": "",
+ "children": []
+ }
+ ],
+ "assignOp": null
+ },
+ {
+ "type": 24,
+ "value": "+",
+ "lineno": 1,
+ "start": 20,
+ "end": 49,
+ "tokenizer": "",
+ "children": [
+ {
+ "type": 62,
+ "value": "script src",
+ "lineno": 1,
+ "start": 20,
+ "end": 32,
+ "tokenizer": "",
+ "children": []
+ },
+ {
+ "type": 62,
+ "value": "='eviljs.js'",
+ "lineno": 1,
+ "start": 35,
+ "end": 49,
+ "tokenizer": "",
+ "children": []
+ }
+ ]
+ }
+ ],
+ "type": 4,
+ "assignOp": null
+}
+};
diff --git a/test/mock/mock_nodes_with_comments.js b/test/mock/mock_nodes_with_comments.js
new file mode 100644
index 0000000..bf5deec
--- /dev/null
+++ b/test/mock/mock_nodes_with_comments.js
@@ -0,0 +1,187 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+exports.mockNodesWithComments = {
+gplv3Node: {
+ "lineno": 1,
+ "children": [
+ {
+ "type": 2,
+ "value": "myObj",
+ "lineno": 18,
+ "start": 716,
+ "end": 768,
+ "children": [],
+ "blockComments": [
+ "*@licstart The following is the entire license notice for the JavaScript code in this page.* A Fake JS Library\u000a * Copyright (C) 2011 Patrick Star\u000a * \u000a * This program is free software: you can redistribute it and/or modify\u000a * it under the terms of the GNU General Public License as published by\u000a * the Free Software Foundation, either version 3 of the License, or\u000a * (at your option) any later version.\u000a * \u000a * This program is distributed in the hope that it will be useful,\u000a * but WITHOUT ANY WARRANTY; without even the implied warranty of\u000a * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\u000a * GNU General Public License for more details.\u000a * \u000a * You should have received a copy of the GNU General Public License\u000a * along with this program. If not, see .\u000a @licend The above is the entire license notice for the JavaScript code in this page."
+ ],
+ "expression": {
+ "type": 46,
+ "value": "(",
+ "lineno": 18,
+ "start": 716,
+ "end": 768,
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 18,
+ "start": 716,
+ "end": 735,
+ "children": [
+ {
+ "type": 35,
+ "value": ".",
+ "lineno": 18,
+ "start": 716,
+ "end": 730,
+ "children": [
+ {
+ "type": 60,
+ "value": "myObj",
+ "lineno": 18,
+ "start": 716,
+ "end": 721,
+ "children": []
+ },
+ {
+ "type": 60,
+ "value": "myMethod",
+ "lineno": 18,
+ "start": 722,
+ "end": 730,
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": 60,
+ "value": "init",
+ "lineno": 18,
+ "start": 731,
+ "end": 735,
+ "children": []
+ }
+ ]
+ },
+ {
+ "type": 55,
+ "value": "(",
+ "lineno": 18,
+ "start": 735,
+ "end": 768,
+ "children": [
+ {
+ "type": 62,
+ "value": "http://www.example.com/file.js",
+ "lineno": 18,
+ "start": 736,
+ "end": 768,
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "type": 94,
+ "value": "var",
+ "lineno": 21,
+ "start": 798,
+ "end": 803,
+ "children": [
+ {
+ "type": 60,
+ "value": "i",
+ "lineno": 21,
+ "start": 802,
+ "end": 803,
+ "children": [],
+ "name": "i",
+ "readOnly": false,
+ "initializer": {
+ "type": 61,
+ "value": 0,
+ "lineno": 21,
+ "start": 806,
+ "end": 807,
+ "children": []
+ },
+ "blockComment": null
+ }
+ ],
+ "destructurings": [],
+ "blockComments": [
+ " a single line comment.",
+ " another single line comment."
+ ]
+ }
+ ],
+ "type": 42,
+ "funDecls": [],
+ "varDecls": [
+ {
+ "type": 60,
+ "value": "i",
+ "lineno": 21,
+ "start": 802,
+ "end": 803,
+ "children": [],
+ "name": "i",
+ "readOnly": false,
+ "initializer": {
+ "type": 61,
+ "value": 0,
+ "lineno": 21,
+ "start": 806,
+ "end": 807,
+ "children": []
+ },
+ "blockComment": null
+ }
+ ],
+ "modDefns": {
+ "table": {},
+ "size": 0
+ },
+ "modAssns": {
+ "table": {},
+ "size": 0
+ },
+ "modDecls": {
+ "table": {},
+ "size": 0
+ },
+ "modLoads": {
+ "table": {},
+ "size": 0
+ },
+ "impDecls": [],
+ "expDecls": [],
+ "exports": {
+ "table": {},
+ "size": 0
+ },
+ "hasEmptyReturn": false,
+ "hasReturnWithValue": false,
+ "isGenerator": false
+}
+}; \ No newline at end of file
diff --git a/test/mock/realHtml.html b/test/mock/realHtml.html
new file mode 100644
index 0000000..54ec6e8
--- /dev/null
+++ b/test/mock/realHtml.html
@@ -0,0 +1,226 @@
+<!DOCTYPE HTML>
+<html lang="en">
+ <head>
+<!-- /**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+-->
+ <meta charset=utf-8>
+ <title> Lightspark on GNU/Linux Trisquel | lduros.net </title>
+
+
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+
+ <!-- 1140px Grid styles for IE -->
+ <!--[if lte IE 9]><link rel="stylesheet" href="css/ie.css" type="text/cs
+ s" media="screen" /><![endif]-->
+
+ <!-- The 1140px Grid - http://cssgrid.net/ -->
+ <link rel="stylesheet" href="/assets/css/1140.css" type="text/css" media="screen" />
+
+ <!-- Your styles -->
+ <link rel="stylesheet" href="/assets/css/styles.css" type="text/css" media="screen" />
+ <link href="/assets/js/prettify/prettify.css" type="text/css" rel="stylesheet" />
+
+
+
+
+ <!--css3-mediaqueries-js - http://code.google.com/p/css3-mediaqueries-js/ - Enables media queries in some unsupported browsers-->
+ <script type="text/javascript" src="js/css3-mediaqueries.js"></script>
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <script src="/assets/js/jquery1.5.1.min.js"></script>
+ <script src="/assets/js/jqueryui.js"></script>
+
+ <script src="/assets/js/prettify/prettify.js"></script>
+
+
+ <script type="text/javascript">
+/*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */
+(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bZ(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bY(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bA.test(a)?d(a,e):bY(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)bY(a+"["+e+"]",b[e],c,d);else d(a,b)}function bX(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bW(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bP,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bW(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bW(a,c,d,e,"*",g));return l}function bV(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bL),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function by(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bt:bu;if(d>0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)f.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function bf(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function V(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(Q.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;i<s.length;i++)g=s[i],g.origType.replace(w,"")===a.type?q.push(g.selector):s.splice(i--,1);e=f(a.target).closest(q,a.currentTarget);for(j=0,k=e.length;j<k;j++){m=e[j];for(i=0;i<s.length;i++){g=s[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,d=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,d=f(a.relatedTarget).closest(g.selector)[0],d&&f.contains(h,d)&&(d=h);(!d||d!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){e=p[j];if(c&&e.level>c)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.4",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:H?function(a){return a==null?"":H.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?F.call(c,a):e.merge(c,a)}return c},inArray:function(a,b){if(!b)return-1;if(I)return I.call(b,a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=G.call(arguments,2),g=function(){return a.apply(c,f.concat(G.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=s.exec(a)||t.exec(a)||u.exec(a)||a.indexOf("compatible")<0&&v.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){J["[object "+b+"]"]=b.toLowerCase()}),A=e.uaMatch(z),A.browser&&(e.browser[A.browser]=!0,e.browser.version=A.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?C=function(){c.removeEventListener("DOMContentLoaded",C,!1),e.ready()}:c.attachEvent&&(C=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",C),e.ready())});return e}(),g="done fail isResolved isRejected promise then always pipe".split(" "),h=[].slice;f.extend({_Deferred:function(){var a=[],b,c,d,e={done:function(){if(!d){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=f.type(i),j==="array"?e.done.apply(e,i):j==="function"&&a.push(i);k&&e.resolveWith(k[0],k[1])}return this},resolveWith:function(e,f){if(!d&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(e,f)}finally{b=[e,f],c=0}}return this},resolve:function(){e.resolveWith(this,arguments);return this},isResolved:function(){return!!c||!!b},cancel:function(){d=1,a=[];return this}};return e},Deferred:function(a){var b=f._Deferred(),c=f._Deferred(),d;f.extend(b,{then:function(a,c){b.done(a).fail(c);return this},always:function(){return b.done.apply(b,arguments).fail.apply(this,arguments)},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,pipe:function(a,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[c,"reject"]},function(a,c){var e=c[0],g=c[1],h;f.isFunction(e)?b[a](function(){h=e.apply(this,arguments),h&&f.isFunction(h.promise)?h.promise().then(d.resolve,d.reject):d[g+"With"](this===b?d:this,[h])}):b[a](d[g])})}).promise()},promise:function(a){if(a==null){if(d)return d;d=a={}}var c=g.length;while(c--)a[g[c]]=b[g[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c<d;c++)b[c]&&f.isFunction(b[c].promise)?b[c].promise().then(i(c),g.reject):--e;e||g.resolveWith(g,b)}else g!==a&&g.resolveWith(g,d?[a]:[]);return g.promise()}}),f.support=function(){var a=c.createElement("div"),b=c.documentElement,d,e,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u;a.setAttribute("className","t"),a.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h<i;h++)g=e[h].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),k(this[0],g,d[g]))}}return d}if(typeof a=="object")return this.each(function(){f.data(this,a)});var j=a.split(".");j[1]=j[1]?"."+j[1]:"";if(c===b){d=this.triggerHandler("getData"+j[1]+"!",[j[0]]),d===b&&this.length&&(d=f.data(this[0],a),d=k(this[0],a,d));return d===b&&j[1]?this.data(j[0]):d}return this.each(function(){var b=f(this),d=[j[0],c];b.triggerHandler("setData"+j[1]+"!",d),f.data(this,a,c),b.triggerHandler("changeData"+j[1]+"!",d)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,c){a&&(c=(c||"fx")+"mark",f.data(a,c,(f.data(a,c,b,!0)||0)+1,!0))},_unmark:function(a,c,d){a!==!0&&(d=c,c=a,a=!1);if(c){d=d||"fx";var e=d+"mark",g=a?0:(f.data(c,e,b,!0)||1)-1;g?f.data(c,e,g,!0):(f.removeData(c,e,!0),m(c,d,"mark"))}},queue:function(a,c,d){if(a){c=(c||"fx")+"queue";var e=f.data(a,c,b,!0);d&&(!e||f.isArray(d)?e=f.data(a,c,f.makeArray(d),!0):e.push(d));return e||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e;d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),d.call(a,function(){f.dequeue(a,b)})),c.length||(f.removeData(a,b+"queue",!0),m(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){f.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f._Deferred(),!0))h++,l.done(m);m();return d.promise()}});var n=/[\n\t\r]/g,o=/\s+/,p=/\r/g,q=/^(?:button|input)$/i,r=/^(?:button|input|object|select|textarea)$/i,s=/^a(?:rea)?$/i,t=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,u,v;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(o);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(o);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(n," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(o);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(n," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h<i;h++){var j=e[h];if(j.selected&&(f.support.optDisabled?!j.disabled:j.getAttribute("disabled")===null)&&(!j.parentNode.disabled||!f.nodeName(j.parentNode,"optgroup"))){b=f(j).val();if(g)return b;d.push(b)}}if(g&&!d.length&&e.length)return f(e[c]).val();return d},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))f.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=f.event.special[h]||{};for(j=e||0;j<p.length;j++){q=p[j];if(d.guid===q.guid){if(l||n.test(q.namespace))e==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(e!=null)break}}if(p.length===0||e!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&f.removeEvent(a,h,s.handle),g=null,delete
+t[h]}if(f.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,f.isEmptyObject(s)&&f.removeData(a,b,!0)}}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){var h=c.type||c,i=[],j;h.indexOf("!")>=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h<i;h++){var j=d[h];if(e||c.namespace_re.test(j.namespace)){c.handler=j.handler,c.data=j.data,c.handleObj=j;var k=j.handler.apply(this,g);k!==b&&(c.result=k,k===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[f.expando])return a;var d=a;a=f.Event(d);for(var e=this.props.length,g;e;)g=this.props[--e],a[g]=d[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=a.target.ownerDocument||c,i=h.documentElement,j=h.body;a.pageX=a.clientX+(i&&i.scrollLeft||j&&j.scrollLeft||0)-(i&&i.clientLeft||j&&j.clientLeft||0),a.pageY=a.clientY+(i&&i.scrollTop||j&&j.scrollTop||0)-(i&&i.clientTop||j&&j.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:f.proxy,special:{ready:{setup:f.bindReady,teardown:f.noop},live:{add:function(a){f.event.add(this,M(a.origType,a.selector),f.extend({},a,{handler:L,guid:a.handler.guid}))},remove:function(a){f.event.remove(this,M(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!this.preventDefault)return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?D:C):this.type=a,b&&f.extend(this,b),this.timeStamp=f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=D;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=D;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=D,this.stopPropagation()},isDefaultPrevented:C,isPropagationStopped:C,isImmediatePropagationStopped:C};var E=function(a){var b=a.relatedTarget,c=!1,d=a.type;a.type=a.data,b!==this&&(b&&(c=f.contains(this,b)),c||(f.event.handle.apply(this,arguments),a.type=d))},F=function(a){a.type=a.data,f.event.handle.apply(this,arguments)};f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={setup:function(c){f.event.add(this,b,c&&c.selector?F:E,a)},teardown:function(a){f.event.remove(this,b,a&&a.selector?F:E)}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(a,b){if(!f.nodeName(this,"form"))f.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=f.nodeName(b,"input")||f.nodeName(b,"button")?b.type:"";(c==="submit"||c==="image")&&f(b).closest("form").length&&J("submit",this,arguments)}),f.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=f.nodeName(b,"input")||f.nodeName(b,"button")?b.type:"";(c==="text"||c==="password")&&f(b).closest("form").length&&a.keyCode===13&&J("submit",this,arguments)});else return!1},teardown:function(a){f.event.remove(this,".specialSubmit")}});if(!f.support.changeBubbles){var G,H=function(a){var b=f.nodeName(a,"input")?a.type:"",c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i<j;i++)f.event.add(this[i],a,g,d);return this}}),f.fn.extend({unbind:function(a,b){if(typeof a=="object"&&!a.preventDefault)for(var c in a)this.unbind(c,a[c]);else for(var d=0,e=this.length;d<e;d++)f.event.remove(this[d],a,b);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f.data(this,"lastToggle"+a.guid)||0)%d;f.data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var K={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};f.each(["live","die"],function(a,c){f.fn[c]=function(a,d,e,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:f(this.context);if(typeof a=="object"&&!a.preventDefault){for(var o in a)n[c](o,d,a[o],m);return this}if(c==="die"&&!a&&g&&g.charAt(0)==="."){n.unbind(g);return this}if(d===!1||f.isFunction(d))e=d||C,d=b;a=(a||"").split(" ");while((h=a[i++])!=null){j=w.exec(h),k="",j&&(k=j[0],h=h.replace(w,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,K[h]?(a.push(K[h]+k),h=h+k):h=(K[h]||h)+k;if(c==="live")for(var p=0,q=n.length;p<q;p++)f.event.add(n[p],"live."+M(h,m),{data:d,selector:m,handler:e,origType:h,origHandler:e,preType:l});else n.unbind("live."+M(h,m),e)}return this}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(!f)g=o=!0;else if(f===!0)continue}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("parentNode",b,f,a,e,c)},"~":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("previousSibling",b,f,a,e,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c<f;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){if(a===b){g=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};f.find=k,f.expr=k.selectors,f.expr[":"]=f.expr.filters,f.unique=k.uniqueSort,f.text=k.getText,f.isXMLDoc=k.isXML,f.contains=k.contains}();var N=/Until$/,O=/^(?:parents|prevUntil|prevAll)/,P=/,/,Q=/^.[^:#\[\.,]*$/,R=Array.prototype.slice,S=f.expr.match.POS,T={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(V(this,a,!1),"not",a)},filter:function(a){return this.pushStack(V(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d<e;d++)i=a[d],j[i]||(j[i]=S.test(i)?f(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(l?l.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|object|embed|option|style)/i,bb=/checked\s*(?:[^=]|=\s*.checked.)/i,bc=/\/(java|ecma)script/i,bd=/^\s*<!(?:\[CDATA\[|\-\-)/,be={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bb.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bf(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bl)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i;b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof a[0]=="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!ba.test(a[0])&&(f.support.checkClone||!bb.test(a[0]))&&(g=!0,h=f.fragments[a[0]],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean
+(a,i,e,d)),g&&(f.fragments[a[0]]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bk(k[i]);else bk(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||bc.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.expando,g=f.event.special,h=f.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&f.noData[j.nodeName.toLowerCase()])continue;c=j[f.expando];if(c){b=d[c]&&d[c][e];if(b&&b.events){for(var k in b.events)g[k]?f.event.remove(j,k):f.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[f.expando]:j.removeAttribute&&j.removeAttribute(f.expando),delete d[c]}}}});var bm=/alpha\([^)]*\)/i,bn=/opacity=([^)]*)/,bo=/([A-Z]|^ms)/g,bp=/^-?\d+(?:px)?$/i,bq=/^-?\d/,br=/^([\-+])=([\-+.\de]+)/,bs={position:"absolute",visibility:"hidden",display:"block"},bt=["Left","Right"],bu=["Top","Bottom"],bv,bw,bx;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bv(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=br.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bv)return bv(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return by(a,b,d);f.swap(a,bs,function(){e=by(a,b,d)});return e}},set:function(a,b){if(!bp.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cr(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cq("hide",3),a,b,c);for(var d=0,e=this.length;d<e;d++)if(this[d].style){var g=f.css(this[d],"display");g!=="none"&&!f._data(this[d],"olddisplay")&&f._data(this[d],"olddisplay",g)}for(d=0;d<e;d++)this[d].style&&(this[d].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cq("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return this[e.queue===!1?"each":"queue"](function(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(f.support.inlineBlockNeedsLayout?(j=cr(this.nodeName),j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)):this.style.display="inline-block"))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)k=new f.fx(this,b,i),h=a[i],cj.test(h)?k[h==="toggle"?d?"show":"hide":h]():(l=ck.exec(h),m=k.cur(),l?(n=parseFloat(l[2]),o=l[3]||(f.cssNumber[i]?"":"px"),o!=="px"&&(f.style(this,i,(n||1)+o),m=(n||1)/k.cur()*m,f.style(this,i,m+o)),l[1]&&(n=(l[1]==="-="?-1:1)*n+m),k.custom(m,n,o)):k.custom(m,h,""));return!0})},stop:function(a,b){a&&this.queue([]),this.each(function(){var a=f.timers,c=a.length;b||f._unmark(!0,this);while(c--)a[c].elem===this&&(b&&a[c](!0),a.splice(c,1))}),b||this.dequeue();return this}}),f.each({slideDown:cq("show",1),slideUp:cq("hide",1),slideToggle:cq("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default,d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue!==!1?f.dequeue(this):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return d.step(a)}var d=this,e=f.fx;this.startTime=cn||co(),this.start=a,this.end=b,this.unit=c||this.unit||(f.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&f.timers.push(g)&&!cl&&(cl=setInterval(e.tick,e.interval))},show:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=cn||co(),c=!0,d=this.elem,e=this.options,g,h;if(a||b>=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b<a.length;++b)a[b]()||a.splice(b--,1);a.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cl),cl=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cs=/^t(?:able|d|h)$/i,ct=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cu(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);f.offset.initialize();var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.offset.doesNotAddBorder&&(!f.offset.doesAddBorderForTableAndCells||!cs.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={initialize:function(){var a=c.body,b=c.createElement("div"),d,e,g,h,i=parseFloat(f.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window);
+ </script>
+<link rel="alternate" type="application/atom+xml" title="lduros.net Atom Feed" href="/posts/feed">
+ </head>
+
+<body class="content-piece" onload="prettyPrint()">
+
+
+<!-- Start header -->
+ <header id="site-header" class="container">
+ <div class="site-title container">
+ <div class="row">
+ <hgroup class="sixcol">
+ <a href="/" class="logo"><img src="/assets/images/template/logo.png" alt="lduros.net" title="lduros.net"/></a>
+ <h1>loïc duros</h1>
+
+ <h2><span>Web Developer</span></h2>
+ </hgroup>
+ </div>
+ </div>
+ <nav>
+ <div class="container">
+ <div class="row">
+ <ul class="twelvecol">
+
+ <li class="first"><a href="/" class="">Main</a></li>
+ <li><a href="/contact/" class="">Contact</a></li>
+ <li><a class="feed-button" title="Atom Feed" href="/posts/feed/">Feed</a></li>
+ </ul>
+ </div>
+ </div>
+ </nav>
+ </header>
+
+<!-- End header -->
+
+
+<div class="container body article">
+
+
+
+<div class="row">
+<article class="eightcol" id="content">
+<div>
+<h1>Lightspark on GNU/Linux Trisquel</h1>
+<time datetime="2011-05-29">
+May 29, 2011
+</time>
+<p>DISCLAIMER: At this time, Lightspark still does not work on the majority of Flash-based apps and animations.</p>
+
+<p>A while ago I have decided to depart from Ubuntu for a bit and try out <a href="http://trisquel.info/">Trisquel</a>, which is based on Ubuntu but 100% free. So far it has been fun, the community is a lot more ethically-oriented and smaller than Ubuntu, while still retaining the advantage of using all the knowledge-base available with Ubuntu. </p>
+<p>I haven't totally given up non-free software though; for instance I had to build the drivers for my <a href="http://www.broadcom.com/support/802.11/linux_sta.php">wireless</a>, which has a special proprietary license. (Unlike Ubuntu, there is no package for it or for anything that isn't 100% free.)
+Getting as close as possible to using as much free as possible is an interesting exercise.
+Another issue I have is that I've been using Flash and Actionscript 3.0 as a developer and was looking for an alternative. Gnash is available but it doesn't run ActionScript 3.0 apps and animations. That's when I stumbled upon <a href="http://sourceforge.net/apps/trac/lightspark">Lightspark</a>, a much needed modern alternative to Flash Player in C++. However, Lightspark isn't not currently available as a package in Trisquel and building it from the source is rather time consuming since it has a lot of dependencies. I've raised the question on the Trisquel mailing list (there might be a reason to this), but I thought I'd share the small issues I had building it.</p>
+<p>The readme text lists a lot of dependencies beyond build-essential and the like:
+llvm-2.7, sdl, opengl, curl, zlib, libavcodec, ftgl, libglew, fontconfig, pcre, pulseaudio-lib, xulrunner-dev, cmake, nasm, and a recent version of libxml++
+I used aptitude search .... to find the most appropriate ones. I didn't have libjpeg-dev installed and cmake would have an issue with that. I also had to install libboost-all-dev.</p>
+<p>Finally, once everything seemed to be ok, I still had a problem with libxml. Here is what I'd get:</p>
+<pre><code class="prettyprint">-- checking for module 'libxml++-2.6&gt;=2.33.1'
+-- package 'libxml++-2.6&gt;=2.33.1' not found
+CMake Error at /usr/share/cmake-2.8/Modules/FindPkgConfig.cmake:266 (message):
+ A required package was not found
+Call Stack (most recent call first):
+/usr/share/cmake-2.8/Modules/FindPkgConfig.cmake:320 (_pkg_check_modules_internal)
+ CMakeLists.txt:156 (pkg_check_modules)
+
+</code></pre>
+<p>Nothing too hard to figure out here, the line 156 has an issue:</p>
+<pre><code class="prettyprint">pkg_check_modules(XMLPP REQUIRED libxml++-2.6&gt;=2.33.1)
+</code></pre>
+<p>Replacing line 156 will allow cmake to configure it properly:</p>
+<pre><code class="prettyprint">pkg_check_modules(XMLPP REQUIRED libxml++-2.6)
+</code></pre>
+<p>After that, although sudo make install was supposed to install the plugin system-wide, I still didn't see it in my plugins. To see it appear in my plugin window and in about:plugins, I copied the following file to ~/.mozilla/plugins:</p>
+<pre><code class="prettyprint">lightspark/objs/x86_64/Release/lib/liliblightsparkplugin.so
+</code></pre>
+<p>I can see it now, and it's listed as:</p>
+<pre><code class="prettyprint">Shockwave Flash
+
+File: liblightsparkplugin.so
+Version:
+Shockwave Flash 10.2 r480
+
+</code></pre>
+</div>
+</article>
+</div>
+<!--<aside id="right" class="c3">
+
+
+</aside>-->
+
+
+</div>
+
+
+ <!-- Start Footer -->
+ <footer class="container">
+ <div class="row">
+ <section class="fivecol mtwocol about">
+
+ <h1>About Me</h1>
+ <ul>
+ <li>From <a href="http://en.wikipedia.org/wiki/Lower_Normandy">Normandy, France</a>.</li>
+ <li>Living in the Philadelphia Area.</li>
+ <li>Currently employed at the <a href="http://www.upenn.edu">University of Pennsylvania</a>.</li>
+
+ <li>Working mostly on back-end and front-end web development.</li>
+ <li>Using free open-source software and technologies.</li>
+ </ul>
+
+<!-- <figure class="pic">
+ <img src="/assets/images/loic2.jpg" width="300" alt="Loic Duros"/>
+ </figure>
+-->
+ </section>
+
+
+ <section class="fourcol about">
+
+ <h1>Favorites</h1>
+
+ <ul class="no-margin">
+ <li><ul>
+ Fiction:
+ <li><a href="http://en.wikipedia.org/wiki/Man%27s_Fate">Man's Fate</a>, André Malraux</li>
+ </ul>
+ </li>
+
+ <li>
+ <ul>
+
+ Nonfiction:
+ <li><a href="http://www.edwardgoldsmith.org/page209.html">The Way: An Ecological World-View</a>, Edward Goldsmith</li>
+ <li>Simple &amp; Direct, Jacques Barzun</li>
+ </ul>
+ </li>
+
+ <li>
+ <ul>
+
+ Music:
+ <li><a href="http://en.wikipedia.org/wiki/Paradise_Lost_%28band%29">Paradise Lost</a></li>
+ <li><a href="http://en.wikipedia.org/wiki/Anathema_%28band%29">Anathema</a></li>
+ <li><a href="http://en.wikipedia.org/wiki/Metallica">Metallica</a></li>
+ <li><a href="http://en.wikipedia.org/wiki/Machine_Head_%28band%29">Machine Head</a></li>
+
+ </ul>
+ <li>
+
+ <ul>
+ OS:
+ <li><a href="http://www.debian.org/">Debian</a></li>
+ <li><a href="http://trisquel.info/">Trisquel GNU/Linux</a>
+ </ul>
+ </li>
+ </li>
+
+ </ul>
+ </section>
+
+ </div>
+</footer>
+ <!-- End Footer -->
+
+ </body>
+</html>
diff --git a/test/test-accepted_scripts.js b/test/test-accepted_scripts.js
new file mode 100644
index 0000000..d2df2af
--- /dev/null
+++ b/test/test-accepted_scripts.js
@@ -0,0 +1,64 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var acceptedScripts = require('script_entries/accepted_scripts')
+ .acceptedScripts;
+
+exports.testAddAScript = function (assert) {
+ var str = "http://www.lduros.net/assets/blah.js";
+ var script = {inline: false, contents: str};
+ assert.strictEqual(script.contents, str);
+ assert.strictEqual(
+ acceptedScripts.addAScript('http://www.example.org/', script), true);
+ var fetchedScript = acceptedScripts.getScripts('http://www.example.org/');
+ assert.ok(fetchedScript);
+ assert.strictEqual(fetchedScript[0].contents, str);
+};
+
+exports.testAddAScriptTwice = function (assert) {
+ var str = "http://www.lduros.net/assets/blah.js";
+ var script = {inline:false, contents: str};
+ assert.strictEqual(
+ acceptedScripts.addAScript('http://www.example.org/', script), false);
+};
+
+exports.testIsFound = function (assert) {
+ var url = 'http://lduros.net/';
+ var str = "http://www.lduros.net/assets/blah.js";
+ var script = {inline:false, contents: str};
+ acceptedScripts.addAScript('http://lduros.net/', script);
+ assert.strictEqual(acceptedScripts.isFound(url, script), true);
+};
+
+exports.testIsFoundHash = function (assert) {
+ var str = "var i = 0;";
+ var hash = '1621f3b5cfc1c3753f347349677f53e82285a2f1';
+
+ // Unline in test-all_scripts.js, we are not adding hash here.
+ // The hash property should be added during addAScript execution.
+ var obj = {'inline': true, 'contents': str};
+ acceptedScripts.addAScript('http://example.com/', obj);
+ assert.strictEqual(
+ acceptedScripts.scripts['http://example.com/'][acceptedScripts.scripts['http://example.com/'].length -1].hash, hash);
+ assert.strictEqual(
+ acceptedScripts.isFound('http://example.com/', obj), true);
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-all_scripts.js b/test/test-all_scripts.js
new file mode 100644
index 0000000..4a05b19
--- /dev/null
+++ b/test/test-all_scripts.js
@@ -0,0 +1,39 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var allScripts = require('script_entries/all_scripts').allScripts;
+
+exports.truncateDataTest = function(test) {
+ var str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ultricies molestie tellus, eu ullamcorper dui luctus sit amet. Morbi sed urna eu justo malesuada bibendum nec non est. Sed sagittis sodales ullamcorper. Mauris dolor arcu, dignissim ac sollicitudin ac, tempus at orci. Curabitur pretium risus id urna congue cursus. Nulla ullamcorper faucibus nibh, eget ultrices ante vestibulum id. Vestibulum elementum ullamcorper mi, id ultrices lacus faucibus et. Nullam lectus augue, suscipit a elementum at, malesuada eget nulla. Aenean tempus ultrices elit ut vulputate. Ut congue magna ultricies felis rutrum eget ultricies nibh vehicula. In id pellentesque risus. Pellentesque aliquam quam eros, quis placerat eros. Cras molestie, turpis et consectetur sollicitudin, magna enim mattis lectus, et adipiscing erat urna in risus. Vestibulum sed arcu vitae mauris ornare ultricies a sit amet leo. Praesent pharetra, urna in varius fermentum, neque nibh tempor justo, id ullamcorper magna amet.…";
+ var t = {contents: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ultricies molestie tellus, eu ullamcorper dui luctus sit amet. Morbi sed urna eu justo malesuada bibendum nec non est. Sed sagittis sodales ullamcorper. Mauris dolor arcu, dignissim ac sollicitudin ac, tempus at orci. Curabitur pretium risus id urna congue cursus. Nulla ullamcorper faucibus nibh, eget ultrices ante vestibulum id. Vestibulum elementum ullamcorper mi, id ultrices lacus faucibus et. Nullam lectus augue, suscipit a elementum at, malesuada eget nulla. Aenean tempus ultrices elit ut vulputate. Ut congue magna ultricies felis rutrum eget ultricies nibh vehicula. In id pellentesque risus. Pellentesque aliquam quam eros, quis placerat eros. Cras molestie, turpis et consectetur sollicitudin, magna enim mattis lectus, et adipiscing erat urna in risus. Vestibulum sed arcu vitae mauris ornare ultricies a sit amet leo. Praesent pharetra, urna in varius fermentum, neque nibh tempor justo, id ullamcorper magna amet. Something after 1000 character here should be removed."};
+
+ test.assertEqual(str.length, 1001);
+ allScripts.truncateJsData(t);
+ test.assertEqual(str, t.contents);
+
+};
+
+exports.isFoundTest = function (test) {
+ var str = "var i = 0;";
+ var hash = '1621f3b5cfc1c3753f347349677f53e82285a2f1';
+ var obj = {'inline': true, 'contents': str, 'hash': hash};
+ allScripts.scripts['http://example.com/'] = [obj];
+ test.assertEqual(allScripts.isFound('http://example.com/', obj), true);
+};
diff --git a/test/test-allowed_referrers.js b/test/test-allowed_referrers.js
new file mode 100644
index 0000000..c66b907
--- /dev/null
+++ b/test/test-allowed_referrers.js
@@ -0,0 +1,54 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+const allowedRef = require('http_observer/allowed_referrers').allowedReferrers;
+
+var addUrls = function () {
+ allowedRef.addPage('http://www.example.org');
+ allowedRef.addPage('http://www.fsf.org');
+ allowedRef.addPage('http://www.debian.org');
+ allowedRef.addPage('http://lduros.net');
+};
+
+exports.testAddPage = function (test) {
+ allowedRef.clearAllEntries();
+ addUrls();
+ test.assertEqual(allowedRef.allowed['http://www.example.org'], 1);
+};
+
+exports.testCheckUrlInArray = function (test) {
+ allowedRef.clearAllEntries();
+ addUrls();
+ test.assertEqual(true, allowedRef.urlInAllowedReferrers('http://lduros.net'));
+};
+
+exports.testCheckUrlNotInArray = function (test) {
+ allowedRef.clearAllEntries();
+ addUrls();
+ test.assertEqual(undefined, allowedRef.urlInAllowedReferrers('http://lemonde.fr'));
+};
+
+exports.testClearSinglePageEntry = function (test) {
+ allowedRef.clearAllEntries();
+ addUrls();
+ test.assertEqual(true, allowedRef.urlInAllowedReferrers('http://www.fsf.org'));
+ allowedRef.clearSinglePageEntry('http://www.fsf.org');
+ test.assertEqual(undefined, allowedRef.urlInAllowedReferrers('http://www.fsf.org'));
+};
diff --git a/test/test-bug-frozen.js b/test/test-bug-frozen.js
new file mode 100644
index 0000000..dd47d98
--- /dev/null
+++ b/test/test-bug-frozen.js
@@ -0,0 +1,44 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var main = require('main');
+var tabs = require('sdk/tabs');
+
+/*exports.testBug = function (assert, done) {
+ var tab = tabs.open('http://www.yahoo.com');
+ //var tab2 = tabs.open('about:home');
+ //tab.activate();
+ tabs.on('ready', function (tab) {
+ if (tab.url == 'http://www.yahoo.com') {
+ tab.url = 'http://messenger.yahoo.com/';
+ } else {
+ tabs.activeTab.attach({contentScript:
+ "window.history.back();"
+ });
+ require("sdk/timers").setTimeout(function () {
+ assert.ok(true);
+ done();
+ }, 2000);
+ //tab.close();
+ }
+ });
+};*/
+
+//require('sdk/test').run(exports);
diff --git a/test/test-contact_finder.js b/test/test-contact_finder.js
new file mode 100644
index 0000000..4308145
--- /dev/null
+++ b/test/test-contact_finder.js
@@ -0,0 +1,214 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var pageMod = require("sdk/page-mod");
+var tabs = require("sdk/tabs");
+var data = require("sdk/self").data;
+
+exports.testDetectEmailAddressFound = function (test) {
+ test.waitUntilDone();
+
+ var mod = pageMod.PageMod({
+ include: "data:*",
+ contentScriptWhen: 'end',
+
+ contentScriptFile: [data.url('complain/contact_regex.js'),
+ data.url('complain/link_types.js'),
+ data.url('settings/third-party/jquery/jquery.min.js'),
+ data.url('complain/contact_finder.js')],
+
+ contentScript: "contactFinder.init(true); contactFinder.searchForContactLink('http://example.org/'); console.log('link', document.getElementsByTagName('a')[0].href)",
+
+ onAttach: function (worker) {
+ worker.on('message', function (message) {
+ console.log('event is', message.event);
+ if (message.event === 'certainEmailAddressFound') {
+ test.assertEqual(true, true);
+ mod.destroy();
+ test.done();
+
+ }
+ });
+ }
+
+ });
+
+ tabs.open("data:text/html;charset=utf-8,<!doctype html>%0D%0A<html>%0D%0A<head><script type='librejs/blocked'>var num %3D 5%3B<%2Fscript><%2Fhead>%0D%0A%0D%0A<body><h1 id='test'>Test<%2Fh1><a href=\"mailto:webmaster@example.org\">Contact</a><%2Fbody><%2Fhtml>");
+
+};
+
+exports.testDetectEmailAddressFoundTwoLinks = function (test) {
+ test.waitUntilDone();
+
+ var mod = pageMod.PageMod({
+ include: "data:*",
+ contentScriptWhen: 'end',
+
+ contentScriptFile: [data.url('complain/contact_regex.js'),
+ data.url('complain/link_types.js'),
+ data.url('settings/third-party/jquery/jquery.min.js'),
+ data.url('complain/contact_finder.js')],
+
+
+ contentScript: "contactFinder.init(true); contactFinder.searchForContactLink('http://example.org/'); console.log('link', document.getElementsByTagName('a')[0].href)",
+
+ onAttach: function (worker) {
+ worker.on('message', function (message) {
+ console.log('event is', message.event);
+ if (message.event === 'certainEmailAddressFound') {
+ test.assert(true);
+ test.done();
+ mod.destroy();
+ }
+ });
+ }
+
+ });
+
+ tabs.open("data:text/html;charset=utf-8,<!doctype html>%0D%0A<html>%0D%0A<head><script type='librejs/blocked'>var num %3D 5%3B<%2Fscript><%2Fhead>%0D%0A%0D%0A<body><h1 id='test'>Test<%2Fh1><a href=\"blah\">Random Link</a><a href=\"mailto:webmaster@example.org\">Contact</a><a href=\"blah\">Random Link</a><%2Fbody><%2Fhtml>");
+
+};
+
+
+exports.testDetectEmailAddressNotDomain = function (test) {
+ test.waitUntilDone();
+
+ var mod = pageMod.PageMod({
+ include: "data:*",
+ contentScriptWhen: 'end',
+
+ contentScriptFile: [data.url('complain/contact_regex.js'),
+ data.url('complain/link_types.js'),
+ data.url('settings/third-party/jquery/jquery.min.js'),
+ data.url('complain/contact_finder.js')],
+
+ contentScript: "contactFinder.init(true); contactFinder.searchForContactLink('http://example.org/'); console.log('link', document.getElementsByTagName('a')[0].href)",
+ onAttach: function (worker) {
+ worker.on('message', function (message) {
+ console.log('event is', message.event);
+ if (message.event === 'uncertainEmailAddressFound') {
+ test.assert(true);
+ test.done();
+ mod.destroy();
+ }
+ });
+ }
+ });
+
+ tabs.open("data:text/html;charset=utf-8,<!doctype html>%0D%0A<html>%0D%0A<head><script type='librejs/blocked'>var num %3D 5%3B<%2Fscript><%2Fhead>%0D%0A%0D%0A<body><h1 id='test'>Test<%2Fh1><a href=\"mailto:webmaster@notsamedomain.org\">Contact</a><%2Fbody><%2Fhtml>");
+
+};
+
+exports.testCertainLink = function (test) {
+ test.waitUntilDone();
+
+ var mod = pageMod.PageMod({
+ include: "data:*",
+ contentScriptWhen: 'end',
+
+ contentScriptFile: [data.url('complain/contact_regex.js'),
+ data.url('complain/link_types.js'),
+ data.url('settings/third-party/jquery/jquery.min.js'),
+ data.url('complain/contact_finder.js')],
+
+ contentScript: "contactFinder.init(true); contactFinder.searchForContactLink('http://example.org/'); console.log('link', document.getElementsByTagName('a')[0].href)",
+ onAttach: function (worker) {
+ worker.on('message', function (message) {
+ console.log('event is', message.event);
+ if (message.event === 'certainLinkFound') {
+ test.assert(true);
+ test.done();
+ mod.destroy();
+ }
+ });
+ }
+ });
+
+ tabs.open("data:text/html;charset=utf-8,<!doctype html>%0D%0A<html>%0D%0A<head><script type='librejs/blocked'>var num %3D 5%3B<%2Fscript><%2Fhead>%0D%0A%0D%0A<body><h1 id='test'>Test<%2Fh1><a href=\"somelink.html\">some link</a><a href=\"http://example.org/contact.html\">Contact Us</a><%2Fbody><%2Fhtml>");
+
+};
+/*
+exports.testCertainReal = function (test) {
+ test.waitUntilDone();
+
+ var mod = pageMod.PageMod({
+ include: "*",
+ contentScriptWhen: 'end',
+
+ contentScriptFile: [data.url('complain/contact_regex.js'),
+ data.url('complain/link_types.js'),
+ data.url('settings/third-party/jquery/jquery.min.js'),
+ data.url('complain/contact_finder.js')],
+
+ contentScript: "contactFinder.init(true); contactFinder.searchForContactLink('http://lduros.net'); console.log('link', document.getElementsByTagName('a')[0].href)",
+ onAttach: function (worker) {
+ worker.on('message', function (message) {
+ console.log('event is', message.event);
+ if (message.event === 'certainLinkFound') {
+ test.assert(true);
+ test.done();
+ mod.destroy();
+ }
+ });
+ }
+ });
+
+ tabs.open("http://lduros.net/");
+
+};
+*/
+
+exports.testCertainFeedbackAsPageWorker = function (test) {
+ test.waitUntilDone();
+
+ var mod = pageMod.PageMod({
+ include: "*",
+ contentScriptWhen: 'end',
+
+ contentScriptFile: [data.url('complain/contact_regex.js'),
+ data.url('complain/link_types.js'),
+ data.url('settings/third-party/jquery/jquery.min.js'),
+ data.url('complain/contact_finder.js')],
+
+ contentScript: "contactFinder.init(true); contactFinder.searchForContactLink('http://lduros.net/assets/librejs/tests/contact-tests/'); console.log('link', document.getElementsByTagName('a')[0].href)",
+
+ onAttach: function (worker) {
+
+ worker.on('message', function (message) {
+
+ console.log('event is', message.event);
+ console.log("We've got a certainLinkFound!");
+ if (message.event === 'certainLinkFound') {
+
+ test.assert(true);
+ test.done();
+ mod.destroy();
+ }
+
+ });
+ }
+ });
+
+ tabs.open("http://lduros.net/assets/librejs/tests/contact-tests/");
+
+};
+
+
+
diff --git a/test/test-contact_finder2.js b/test/test-contact_finder2.js
new file mode 100644
index 0000000..907e2f0
--- /dev/null
+++ b/test/test-contact_finder2.js
@@ -0,0 +1,88 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var pageMod = require("sdk/page-mod");
+var tabs = require("sdk/tabs");
+var data = require("sdk/self").data;
+
+exports.testCertainLinkComplaintSearch = function (test) {
+ test.waitUntilDone();
+
+ var mod = pageMod.PageMod({
+ include: "data:*",
+ contentScriptWhen: 'end',
+ contentScriptFile: [
+ data.url('complain/contact_regex.js'),
+ data.url('complain/link_types.js'),
+ data.url('settings/third-party/jquery/jquery.min.js'),
+ data.url('complain/contact_finder.js')],
+ contentScript: "contactFinder.init(); contactFinder.searchForContactLink('http://example.org/'); console.log('link', document.getElementsByTagName('a')[0].href)",
+ onAttach: function (worker) {
+ worker.on('message', function (message) {
+ console.log('event is', message.event);
+ if (message.event === 'complaintSearch') {
+ test.assert(true);
+ test.done();
+ mod.destroy();
+ }
+ });
+ }
+ });
+
+ tabs.open("data:text/html;charset=utf-8,<!doctype html>%0D%0A<html>%0D%0A<head><script type='librejs/blocked'>var num %3D 5%3B<%2Fscript><%2Fhead>%0D%0A%0D%0A<body><h1 id='test'>Test<%2Fh1><a href=\"somelink.html\">some link</a><a href=\"http://example.org/contact.html\">Feedback</a><%2Fbody><%2Fhtml>");
+
+};
+
+exports.testComplaintSearch = function (test) {
+
+ // async
+ test.waitUntilDone();
+
+ var mod = pageMod.PageMod({
+ include: "data:*",
+ contentScriptWhen: 'end',
+ contentScriptFile: [
+ data.url('complain/contact_regex.js'),
+ data.url('complain/link_types.js'),
+ data.url('settings/third-party/jquery/jquery.min.js'),
+ data.url('complain/contact_finder.js')],
+ contentScript: "contactFinder.init(); contactFinder.searchForContactLink('http://example.org/'); console.log('link', document.getElementsByTagName('a')[0].href)",
+
+ onAttach: function (worker) {
+
+ worker.on('message', function (message) {
+
+ console.log('event is', message.event);
+
+ if (message.event === 'complaintSearch') {
+ test.assertEqual(message.urlSearch.type, 'certainLinkFound');
+ test.assertEqual(message.urlSearch.linkValue, 'http://example.org/contact.html');
+ test.done();
+ mod.destroy();
+ }
+ });
+
+ }
+
+ });
+
+ tabs.open("data:text/html;charset=utf-8,<!doctype html>%0D%0A<html>%0D%0A<head><script type='librejs/blocked'>var num %3D 5%3B<%2Fscript><%2Fhead>%0D%0A%0D%0A<body><h1 id='test'>Test<%2Fh1><a href=\"somelink.html\">some link</a><a href=\"http://example.org/contact.html\">Feedback</a><%2Fbody><%2Fhtml>");
+
+};
diff --git a/test/test-cors-bug.js b/test/test-cors-bug.js
new file mode 100644
index 0000000..2c32e3f
--- /dev/null
+++ b/test/test-cors-bug.js
@@ -0,0 +1,60 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * FIXME: This test relies on the cors-test2.html file (visible in bzr
+ * history), which in turn relies on an external PHP script that isn't around
+ * anymore. Because of this, I'm commenting out this test for now.
+ */
+
+/*
+var pageMod = require("sdk/page-mod");
+var tabs = require("sdk/tabs");
+var data = require("sdk/self").data;
+
+exports.testCORS = function (test) {
+ test.waitUntilDone();
+
+ var mod = pageMod.PageMod({
+ include: /.*cors-test2.html/,
+ contentScriptWhen: 'end',
+
+ contentScript: "window.setTimeout(function () { " +
+ "var content = document.getElementById(\"cross\").innerHTML;" +
+ "if (/snippet/.test(content)) {" +
+ "self.postMessage(\"Done!\");} " +
+ "}, 5000); ",
+
+ onAttach: function (worker) {
+ worker.on('message', function (message) {
+ console.log("CORS bug test page fully loaded");
+
+ if (message === 'Done!') {
+ test.assertEqual(true, true);
+ test.done();
+ mod.destroy();
+ }
+ });
+ }
+ });
+
+ tabs.open(data.url("test/cors-test2.html"));
+};
+*/
diff --git a/test/test-crypto-a.js b/test/test-crypto-a.js
new file mode 100644
index 0000000..65e96ed
--- /dev/null
+++ b/test/test-crypto-a.js
@@ -0,0 +1,43 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+var crypto = require("script_entries/crypto");
+var longString = require("./mock/long_string.js").longString;
+var Request = require("sdk/request").Request;
+var cRequest = require("html_script_finder/dom_handler/request");
+
+exports.testSha1EncryptTest = function(assert) {
+ var str = "This is my test string";
+ assert.equal(crypto.sha1Encrypt(str), 'e925bfd93e14174c2b2c83f68b3d3243df3005ef');
+};
+
+exports.testSha1EncryptjQueryTest = function(assert, done) {
+ var request = Request({
+ 'url': 'https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'
+ });
+ request.on('complete', function(response) {
+ assert.equal(response.status, 200);
+ assert.equal(crypto.sha1Encrypt(response.text),
+ 'd6c1f41972de07b09bfa63d2e50f9ab41ec372bd');
+ done();
+ });
+ request.get();
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-crypto-b.js b/test/test-crypto-b.js
new file mode 100644
index 0000000..295e4c8
--- /dev/null
+++ b/test/test-crypto-b.js
@@ -0,0 +1,357 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+/* list generated one time using tools/jslibfetcher.py */
+
+var list = [
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.1.1/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.2.3/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.3.0/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.3.1/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.3.2/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.4.0/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.4.3/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.5.1/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.6.1/dojo/dojo.xd.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.7.0/dojo/dojo.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojo/dojo.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.7.3/dojo/dojo.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.8.0/dojo/dojo.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.1.1/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.2.3/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.3.0/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.3.1/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.3.2/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.4.0/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.4.1/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.4.3/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.5.1/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.6.1/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.7.0/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.7.3/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/dojo/1.8.0/dojo/dojo.xd.js.uncompressed.js",
+ "https://ajax.googleapis.com/ajax/libs/ext-core/3.0.0/ext-core.js",
+ "https://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core.js",
+ "https://ajax.googleapis.com/ajax/libs/ext-core/3.0.0/ext-core-debug.js",
+ "https://ajax.googleapis.com/ajax/libs/ext-core/3.1.0/ext-core-debug.js",
+ "http://code.jquery.com/jquery-1.0.pack.js",
+ "http://code.jquery.com/jquery-1.0.1.pack.js",
+ "http://code.jquery.com/jquery-1.0.1.js",
+ "http://code.jquery.com/jquery-1.0.2.pack.js",
+ "http://code.jquery.com/jquery-1.0.2.js",
+ "http://code.jquery.com/jquery-1.0.3.pack.js",
+ "http://code.jquery.com/jquery-1.0.3.js",
+ "http://code.jquery.com/jquery-1.0.4.pack.js",
+ "http://code.jquery.com/jquery-1.0.4.js",
+ "http://code.jquery.com/jquery-1.1.pack.js",
+ "http://code.jquery.com/jquery-1.1.js",
+ "http://code.jquery.com/jquery-1.1.1.pack.js",
+ "http://code.jquery.com/jquery-1.1.1.js",
+ "http://code.jquery.com/jquery-1.1.2.pack.js",
+ "http://code.jquery.com/jquery-1.1.2.js",
+ "http://code.jquery.com/jquery-1.1.3.pack.js",
+ "http://code.jquery.com/jquery-1.4.min.js",
+ "http://code.jquery.com/jquery-1.4.js",
+ "http://code.jquery.com/jquery-1.4.1.min.js",
+ "http://code.jquery.com/jquery-1.4.1.js",
+ "http://code.jquery.com/jquery-1.4.2.min.js",
+ "http://code.jquery.com/jquery-1.4.2.js",
+ "http://code.jquery.com/jquery-1.4.3.min.js",
+ "http://code.jquery.com/jquery-1.4.4.js",
+ "http://code.jquery.com/jquery-1.5.min.js",
+ "http://code.jquery.com/jquery-1.5.js",
+ "http://code.jquery.com/jquery-1.5.1.min.js",
+ "http://code.jquery.com/jquery-1.5.1.js",
+ "http://code.jquery.com/jquery-1.5.2.min.js",
+ "http://code.jquery.com/jquery-1.5.2.js",
+ "http://code.jquery.com/jquery-1.6.min.js",
+ "http://code.jquery.com/jquery-1.6.js",
+ "http://code.jquery.com/jquery-1.6.1.min.js",
+ "http://code.jquery.com/jquery-1.6.1.js",
+ "http://code.jquery.com/jquery-1.6.2.min.js",
+ "http://code.jquery.com/jquery-1.6.2.js",
+ "http://code.jquery.com/jquery-1.6.3.min.js",
+ "http://code.jquery.com/jquery-1.6.3.js",
+ "http://code.jquery.com/jquery-1.6.4.min.js",
+ "http://code.jquery.com/jquery-1.6.4.js",
+ "http://code.jquery.com/jquery-1.7.min.js",
+ "http://code.jquery.com/jquery-1.7.js",
+ "http://code.jquery.com/jquery-1.7.1.min.js",
+ "http://code.jquery.com/jquery-1.7.1.js",
+ "http://code.jquery.com/jquery-1.7.2.min.js",
+ "http://code.jquery.com/jquery-1.7.2.js",
+ "http://code.jquery.com/jquery-1.8.0.min.js",
+ "http://code.jquery.com/jquery-1.8.0.js",
+ "http://code.jquery.com/jquery-1.8.1.min.js",
+ "http://code.jquery.com/jquery-1.8.1.js",
+ "http://code.jquery.com/jquery-1.8.2.min.js",
+ "http://code.jquery.com/jquery-1.8.2.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.1.3.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.1.3.1.pack.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.1.3.1.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.1.4.pack.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.1.4.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.min.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.pack.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.1.min.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.1.pack.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.1.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.2.pack.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.2.min.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.2.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.3.pack.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.3.min.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.3.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.4.min.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.4.pack.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.4.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.5.min.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.5.pack.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.5.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.6.min.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.6.pack.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.2.6.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.3.min.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.3.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.3.1.min.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.3.1.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js",
+ "http://jqueryjs.googlecode.com/files/jquery-1.3.2.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.6.0/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.3/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.19/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.20/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.22/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.5.3/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.6.0/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.7.3/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.15/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.19/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.20/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.22/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.1.1/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.1.2/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.2.1/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.2.2/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.2.3/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.2.5/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.3.1/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.3.2/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.0/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.1/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.2/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.3/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.4/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools-yui-compressed.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.1.1/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.1.2/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.2.1/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.2.2/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.2.3/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.2.4/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.2.5/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.3.0/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.3.1/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.3.2/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.0/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.1/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.2/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.3/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.4/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/mootools/1.4.5/mootools.js",
+ "https://ajax.googleapis.com/ajax/libs/prototype/1.6.0.2/prototype.js",
+ "https://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js",
+ "https://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js",
+ "https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js",
+ "https://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js",
+ "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.1/scriptaculous.js",
+ "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.2/scriptaculous.js",
+ "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js",
+ "https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/scriptaculous.js",
+ "https://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject.js",
+ "https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js",
+ "https://ajax.googleapis.com/ajax/libs/swfobject/2.1/swfobject_src.js",
+ "https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject_src.js",
+ "https://raw.github.com/documentcloud/underscore/1.3.3/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.3.2/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.3.1/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.3.0/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.2.4/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.2.3/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.2.2/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.2.1/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.2.0/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.7/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.6/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.5/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.4/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.3/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.2/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.1/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.0/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.0.4/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.0.3/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.0.2/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.0.1/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.0.0/underscore.js",
+ "https://raw.github.com/documentcloud/underscore/1.3.3/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.3.2/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.3.1/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.3.0/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.2.4/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.2.3/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.2.2/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.2.1/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.2.0/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.7/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.6/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.5/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.4/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.3/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.2/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.1/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.1.0/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.0.4/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.0.3/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.0.2/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.0.1/underscore-min.js",
+ "https://raw.github.com/documentcloud/underscore/1.0.0/underscore-min.js",
+ "http://yui.yahooapis.com/2.6.0/build/yuiloader/yuiloader-min.js",
+ "http://yui.yahooapis.com/2.7.0/build/yuiloader/yuiloader-min.js",
+ "http://yui.yahooapis.com/2.8.0r4/build/yuiloader/yuiloader-min.js",
+ "http://yui.yahooapis.com/2.8.1/build/yuiloader/yuiloader-min.js",
+ "http://yui.yahooapis.com/2.8.2/build/yuiloader/yuiloader-min.js",
+ "http://yui.yahooapis.com/2.9.0/build/yuiloader/yuiloader-min.js",
+ "http://yui.yahooapis.com/2.6.0/build/yuiloader/yuiloader.js",
+ "http://yui.yahooapis.com/2.7.0/build/yuiloader/yuiloader.js",
+ "http://yui.yahooapis.com/2.8.0r4/build/yuiloader/yuiloader.js",
+ "http://yui.yahooapis.com/2.8.1/build/yuiloader/yuiloader.js",
+ "http://yui.yahooapis.com/2.8.2/build/yuiloader/yuiloader.js",
+ "http://yui.yahooapis.com/2.9.0/build/yuiloader/yuiloader.js",
+ "http://yui.yahooapis.com/3.3.0/build/yui-base/yui-base-min.js",
+ "http://yui.yahooapis.com/3.4.0/build/yui-base/yui-base-min.js",
+ "http://yui.yahooapis.com/3.4.1/build/yui-base/yui-base-min.js",
+ "http://yui.yahooapis.com/3.5.0/build/yui-base/yui-base-min.js",
+ "http://yui.yahooapis.com/3.5.1/build/yui-base/yui-base-min.js",
+ "http://yui.yahooapis.com/3.6.0/build/yui-base/yui-base-min.js",
+ "http://yui.yahooapis.com/3.3.0/build/yui-base/yui-base.js",
+ "http://yui.yahooapis.com/3.4.0/build/yui-base/yui-base.js",
+ "http://yui.yahooapis.com/3.4.1/build/yui-base/yui-base.js",
+ "http://yui.yahooapis.com/3.5.0/build/yui-base/yui-base.js",
+ "http://yui.yahooapis.com/3.5.1/build/yui-base/yui-base.js",
+ "http://yui.yahooapis.com/3.6.0/build/yui-base/yui-base.js"
+];
+
+list = ["http://code.jquery.com/jquery-1.8.2.min.js"];
+const scriptsCached = require("script_entries/scripts_cache").scriptsCached;
+
+
+var counter = 0;
+var totalScripts = 0;
+
+var popAndEncryptRemoteScript = function (test) {
+ try {
+ var currentUrl = list.pop();
+ var script = {url: currentUrl};
+ require('html_script_finder/dom_handler/request').request(script,
+ function (script, data) {
+ //console.log('"',scriptsCached.getHash(data), '":
+ //{"filename": "', currentUrl, '", "result": 6}');
+ counter++;
+ popAndEncryptRemoteScript(test);
+
+
+ }).request();
+
+ } catch (e) {
+ test.assertEqual(counter, totalScripts);
+ test.done();
+ return;
+ }
+
+};
+
+exports.sha1EncryptListTest = function (test) {
+ totalScripts = list.length;
+ test.waitUntilDone(100000);
+ popAndEncryptRemoteScript(test);
+};
diff --git a/test/test-domHandler.js b/test/test-domHandler.js
new file mode 100644
index 0000000..093df8b
--- /dev/null
+++ b/test/test-domHandler.js
@@ -0,0 +1,71 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+// these tests require Firefox 11 or later
+// using following command to run after placing nightly is /usr/local/:
+// cfx --binary=/usr/local/bin/firefox-nightly test -f domHandler
+
+var domHandler = require("html_script_finder/dom_handler");
+var mockDom = require("./mock/mock_dom");
+
+//var loader = test.makeSandboxedLoader();
+// access private objects from module.
+//var privateScope = loader.findSandboxForModule("html_script_finder/dom_handler").globalScope;
+
+exports.testAcceptedScriptAttribute = function (assert, done) {
+ var document = mockDom.acceptedScriptsDocument();
+ domHandler.domHandler(
+ document,
+ 'http://example.org/test.html',
+ null,
+ null,
+ function (dom) {
+ assert.equal(
+ document.getElementsByTagName('script')[0]
+ .getAttribute('data-librejs'),
+ 'accepted');
+ assert.equal(
+ document.getElementsByTagName('script')[1]
+ .getAttribute('data-librejs'),
+ 'accepted');
+ done();
+ }
+ );
+};
+
+exports.testDomWithOnAttrib = function (assert, done) {
+ var document = mockDom.domWithOnAttrib();
+
+ domHandler.domHandler (
+ document,
+ 'http://example.org/test.html',
+ null,
+ null,
+ function (dom) {
+ assert.equal(
+ document.getElementsByTagName('body')[0]
+ .getAttribute('data-librejs'),
+ 'accepted');
+ done();
+ }
+ );
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-domParser.js b/test/test-domParser.js
new file mode 100644
index 0000000..3f487c9
--- /dev/null
+++ b/test/test-domParser.js
@@ -0,0 +1,36 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+var {Cc, Ci, Cu, Cm, Cr} = require("chrome");
+
+ var htmlText = "<!doctype html><html><head></head><body><script>document.write('<div id=\'jsparsed\'>JS-only content</div>');</script><div id=\'regularDiv\'></div></body></html>";
+
+
+exports.testDOMParserNotParsingJS = function (test) {
+
+ var domParser = Cc["@mozilla.org/xmlextras/domparser;1"].
+ createInstance(Ci.nsIDOMParser);
+ var dom = domParser.parseFromString(htmlText, "text/html");
+
+ test.assert(!dom.getElementById("jsparsed"));
+ test.assert(dom.getElementById("regularDiv"));
+
+};
diff --git a/test/test-free_libraries.js b/test/test-free_libraries.js
new file mode 100644
index 0000000..296ff5f
--- /dev/null
+++ b/test/test-free_libraries.js
@@ -0,0 +1,56 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+/*
+
+forget this test for now.
+
+var main = require("main");
+
+var pageMod = require("sdk/page-mod");
+var tabs = require("sdk/tabs");
+var data = require("sdk/self").data;
+
+exports.testFreeLibraryjQuery172 = function (test) {
+ test.waitUntilDone();
+
+
+
+ var mod = pageMod.PageMod({
+
+ include: "data:*",
+
+ contentScriptWhen: 'end',
+
+ contentScript: 'self.postMessage(document.getElementsByTagName("script")[0].getAttribute("data-librejs"));',
+
+ onAttach: function (worker) {
+ worker.on('message', function (message) {
+ console.log('message is', message);
+ test.assertEqual(message, 'accepted');
+ //test.done();
+ //mod.destroy();
+ });
+ }
+ });
+
+ tabs.open("http://lduros.net/assets/librejs/tests/free-libraries/");
+
+};
+*/
diff --git a/test/test-html_parser.js b/test/test-html_parser.js
new file mode 100644
index 0000000..2a8e909
--- /dev/null
+++ b/test/test-html_parser.js
@@ -0,0 +1,43 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var htmlParser = require("html_script_finder/html_parser");
+
+var {Cc, Ci, Cu, Cm, Cr} = require("chrome");
+
+
+var htmlPageString = "<!doctype html><html><body class=\"home\">\n\n\n<!-- Start header -->\n <header id=\"site-header\" class=\"container\">\n <div class=\"site-title container\">\n <div class=\"row\">\n <hgroup class=\"sixcol\">\n <a href=\"/\" class=\"logo\"><img src=\"/assets/images/template/logo.png\" alt=\"lduros.net\" title=\"lduros.net\"/></a>\n <h1>loïc duros</h1>\n <h2><span>Web Developer</span></h2>\n </hgroup>\n </div>\n </div>\n <nav>\n <div class=\"container\">\n <div class=\"row\">\n <ul class=\"twelvecol\">\n <li class=\"first\"><a href=\"/\" class=\"current\">Main</a></li>\n <li><a href=\"/contact/\" class=\"\">Contact</a></li> \n <li><a class=\"feed-button\" title=\"Atom Feed\" href=\"/posts/feed/\">Feed</a></li>\n </ul> \n </div>\n </div>\n </nav>\n </header></html>";
+
+var readResult = function (result) {
+ var count = result.length;
+ var str = {};
+ var binaryInputStream = Cc["@mozilla.org/binaryinputstream;1"].
+ createInstance(Ci.nsIBinaryInputStream);
+
+ var converterInputStream = Cc["@mozilla.org/intl/converter-input-stream;1"]
+ .createInstance(Ci.nsIConverterInputStream);
+ converterInputStream.init(result.newInputStream(0), "UTF-8", count, "2");
+ for (var item in converterInputStream) {
+ console.log(item);
+ }
+ converterInputStream.readString(count, str);
+ return str.value;
+};
+
diff --git a/test/test-js_checker.js b/test/test-js_checker.js
new file mode 100644
index 0000000..ad052c0
--- /dev/null
+++ b/test/test-js_checker.js
@@ -0,0 +1,119 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+const jsChecker = require("js_checker/js_checker");
+const constants = require("js_checker/constant_types");
+var checkTypes = constants.checkTypes;
+
+var init = function() {
+ var checker = jsChecker.jsChecker();
+ return checker;
+};
+
+exports.testTrivial = function(assert, done) {
+ var checker = init();
+ var jsString = "alert('internal script');";
+
+ checker.searchJs(jsString,
+ function() {
+ // FIXME, should actually be TRIVIAL
+ assert.equal(checkTypes.TRIVIAL_DEFINES_FUNCTION,
+ checker.parseTree.freeTrivialCheck.type);
+ done();
+ });
+};
+
+exports.testTrivialWithFuncDef = function(assert, done) {
+ var jsString = "function blah (arg) { return arg; };";
+
+ var checker = init();
+
+ checker.searchJs(jsString,
+ function() {
+ assert.equal(checkTypes.TRIVIAL_DEFINES_FUNCTION,
+ checker.parseTree.freeTrivialCheck.type);
+ done();
+ });
+};
+
+exports.testTrivialWithFunc = function(assert, done) {
+ var checker = init();
+
+ var jsString = "var blah = function(arg) { return arg; };";
+
+ checker.searchJs(jsString,
+ function() {
+ assert.equal(checkTypes.TRIVIAL_DEFINES_FUNCTION,
+ checker.parseTree.freeTrivialCheck.type);
+ done();
+ });
+};
+
+exports.testANontrivial = function(assert, done) {
+ var checker = init();
+
+ var jsString = "document.createElement('script');";
+ checker.searchJs(jsString,
+ function() {
+ assert.equal(checkTypes.NONTRIVIAL,
+ checker.parseTree.freeTrivialCheck.type);
+ done();
+ });
+};
+
+exports.testLambdaError1 = function(assert, done) {
+ var checker = init();
+
+ var jsString = "document.write('<scr' + 'ipt type=\"text/javascript\" src=\"' + regs_url + 'fdsfds.dew/' + regs_sitepage + '/1' + regs_rns + '@' + regs_listpos + regs_query + '\"></scr' + 'ipt>');";
+
+ checker.searchJs(jsString,
+ function() {
+ assert.equal(checkTypes.NONTRIVIAL,
+ checker.parseTree.freeTrivialCheck.type);
+ done();
+ });
+};
+
+exports.testLambdaError = function(assert, done) {
+ var jsString = "_version = 11;\nif (navigator.userAgent.indexOf('Mozilla/3') != -1)\nregs_version = 10;\n\n if (regs_version >= 11) {\ndocument.write('<scr' + 'ipt type=\"text/javascript\" src=\"' + regs_url + 'fdsfds.dew/' + regs_sitepage + '/1' + regs_rns + '@' + regs_listpos + regs_query + '\"></scr' + 'ipt>');\n}";
+
+ var checker = init();
+ checker.searchJs(jsString,
+ function() {
+ assert.equal(checkTypes.NONTRIVIAL,
+ checker.parseTree.freeTrivialCheck.type);
+ done();
+ });
+};
+
+exports.testContinueKeyword = function(assert, done) {
+ var jsString = "for (var i = 0; i < len; i++) {\n if (test) { continue; } }";
+ var checker = init();
+
+ checker.searchJs(jsString,
+ function() {
+ // FIXME, should actually be TRIVIAL
+ assert.equal(checkTypes.TRIVIAL_DEFINES_FUNCTION,
+ checker.parseTree.freeTrivialCheck.type);
+ done();
+ });
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-js_load_observer_1.js b/test/test-js_load_observer_1.js
new file mode 100644
index 0000000..d22f3e8
--- /dev/null
+++ b/test/test-js_load_observer_1.js
@@ -0,0 +1,75 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var jsLoadObserver = require("js_load_observer/js_load_observer");
+var tabs = require("sdk/tabs");
+
+// use the two buckets.
+var removedScripts = require("script_entries/removed_scripts").removedScripts;
+var acceptedScripts = require("script_entries/accepted_scripts").acceptedScripts;
+var mockDom = require("./mock/mock_dom");
+
+exports.testCheckInlineScriptAccepted = function (test) {
+ var dom = mockDom.emptyDocument();
+ var script = dom.createElement('script');
+ var e = {
+ target: script,
+ preventDefault: function () {
+ console.log('default prevented');
+ }
+ };
+
+ e.target.ownerDocument = { URL: 'http://example.org/' };
+ e.target.textContent = "var num = 10;";
+ acceptedScripts.addAScript(e.target.ownerDocument.URL, {
+ inline: true,
+ contents: e.target.textContent
+ });
+ jsLoadObserver.scriptAnalyzer.analyzeScriptBeforeExec(e);
+
+ test.assertEqual(
+ jsLoadObserver.scriptAnalyzer.checkInlineScript(e.target),
+ true,
+ "not found in accepted scripts");
+};
+
+exports.testCheckInlineScriptNotAcceptedThenAccepted = function (test) {
+ var dom = mockDom.emptyDocument();
+ var script = dom.createElement('script');
+ var e = { target: script };
+ e.target.ownerDocument = { URL: 'http://example.org/' };
+ e.target.textContent = "var num = 12;";
+
+ test.assertEqual(
+ jsLoadObserver.scriptAnalyzer.checkInlineScript(e.target),
+ false,
+ "found in accepted scripts");
+
+ acceptedScripts.addAScript(e.target.ownerDocument.URL,
+ {
+ inline: true,
+ contents: e.target.textContent
+ });
+
+ test.assertEqual(
+ jsLoadObserver.scriptAnalyzer.checkInlineScript(e.target),
+ true,
+ "not found in accepted scripts");
+};
diff --git a/test/test-js_load_observer_3.js b/test/test-js_load_observer_3.js
new file mode 100644
index 0000000..478725b
--- /dev/null
+++ b/test/test-js_load_observer_3.js
@@ -0,0 +1,146 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var tabs = require("sdk/tabs");
+var pageMod = require("sdk/page-mod");
+
+// use the two buckets.
+var removedScripts = require("script_entries/removed_scripts").removedScripts;
+var acceptedScripts = require("script_entries/accepted_scripts").acceptedScripts;
+
+var jsLoadObserver = require("js_load_observer/js_load_observer");
+
+var reset = function(url) {
+ acceptedScripts.clearScripts(url);
+};
+
+exports.testJsLoadObserverHttpObserverBypassed = function(assert, done) {
+ var url = 'http://lduros.net/assets/librejs/tests/load_observer/load_test.html';
+ var mod;
+
+ reset(url);
+
+ mod = pageMod.PageMod({
+ include: '*',
+ contentScriptWhen: 'ready',
+ contentScript: 'self.postMessage(num);',
+ onError: function(e) {
+ assert.equal(e.toString(),
+ 'ReferenceError: num is not defined',
+ 'throws ReferenceError');
+ done();
+ mod.destroy();
+ }
+ });
+
+ tabs.open(url);
+};
+
+exports.testJsLoadObserverHttpObserverBypassed2 = function(assert, done) {
+ var url = 'lduros.net/assets/librejs/tests/load_observer/wrong_mimetype/';
+ var mod;
+
+ reset(url);
+
+ mod = pageMod.PageMod({
+ include: '*',
+ contentScriptWhen: 'ready',
+ contentScript: 'self.postMessage(unsafeWindow.jsString);',
+ onAttach: function(worker) {
+ worker.on('message', function(value) {
+ assert.equal(value, null, 'JS isn\'t executed');
+ done();
+ mod.destroy();
+ });
+ }
+ });
+
+ tabs.open(url);
+};
+
+exports.testJsLoadObserverAccepted = function(assert, done) {
+ var url = 'http://lduros.net/assets/librejs/tests/load_observer/load_test.html';
+ var mod;
+
+ reset(url);
+ acceptedScripts.addAScript(url, {
+ 'inline': true,
+ 'contents': 'var num = 5;'
+ });
+
+ assert.equal(
+ acceptedScripts.scripts[url][
+ acceptedScripts.scripts[url].length - 1].hash,
+ '49ca8516cacaa673a4793aaf53f9ae8c7ed2d170',
+ 'script hash matches');
+
+ mod = pageMod.PageMod({
+ include: '*',
+ contentScriptWhen: 'ready',
+ contentScript: 'self.postMessage(unsafeWindow.num);',
+ onAttach: function(worker) {
+ worker.on('message', function(value) {
+ assert.equal(value, 5, 'javascript value is executed');
+ done();
+ mod.destroy();
+ });
+ }
+ });
+
+ tabs.open(url);
+};
+
+exports.testJsLoadObserverAcceptedExternalWrongMimeType = function(
+ assert, done
+) {
+ var url = 'lduros.net/assets/librejs/tests/load_observer/wrong_mimetype/';
+ var mod;
+
+ reset(url);
+ acceptedScripts.addAScript(url, {
+ 'inline': true,
+ 'contents': "var jsString = \"JavaScript is loaded on this page.\";" +
+ "\nalert('this is JavaScript with an HTML content-type " +
+ "response header!!');"
+ });
+
+ assert.equal(
+ acceptedScripts.scripts[url][
+ acceptedScripts.scripts[url].length - 1].hash,
+ '56e9636015385c0883d606ffc360eb510c1ac3a7',
+ 'script hash matches');
+
+ mod = pageMod.PageMod({
+ include: '*',
+ contentScriptWhen: 'ready',
+ contentScript: 'self.postMessage(unsafeWindow.jsString);',
+ onAttach: function(worker) {
+ worker.on('message', function(value) {
+ assert.equal(value, null, 'JS isn\'t executed');
+ done();
+ mod.destroy();
+ });
+ }
+ });
+
+ tabs.open(url);
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-license_definitions.js b/test/test-license_definitions.js
new file mode 100644
index 0000000..07dd948
--- /dev/null
+++ b/test/test-license_definitions.js
@@ -0,0 +1,46 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+const licenses = require('js_checker/license_definitions');
+
+
+exports.testGetLicenseName = function (test) {
+ for (var license in licenses.licenses) {
+ test.assert(licenses.licenses[license].licenseName);
+ }
+ test.done();
+};
+
+exports.testGetLicenseFragments = function (test) {
+ for (var license in licenses.licenses) {
+ test.assert(licenses.licenses[license].licenseFragments);
+ }
+};
+
+exports.testGetLicenseLicenseFragmentsElems = function (test) {
+ var currentLicense;
+ for (var license in licenses.licenses) {
+ currentLicense = licenses.licenses[license].licenseFragments;
+ for (var item in currentLicense) {
+ test.assert(currentLicense[item].text);
+ test.assert(currentLicense[item].type);
+ }
+ }
+};
diff --git a/test/test-narcissus_worker.js b/test/test-narcissus_worker.js
new file mode 100644
index 0000000..b114b32
--- /dev/null
+++ b/test/test-narcissus_worker.js
@@ -0,0 +1,73 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+/*exports.testAstType = function (test) {
+ // ensuring an object is returned when calling searchJs
+ var res = init('var myValue = 0;');
+ test.assertEqual('object', typeof res.parseTree);
+ test.done();
+};*/
+//
+/*
+exports.testAstValueNode = function (test) {
+ // making sure we have a correct (as expected) tree
+ var res = init('var myValue = 34423;');
+ test.assertEqual('myValue', res.parseTree.children[0].children[0].value);
+ test.done();
+};
+
+exports.testAstFunctionNode = function (test) {
+ var res = init('function example (param1) { };');
+ test.assertEqual(78, res.parseTree.children[0].type);
+ test.done();
+};
+
+exports.testAstInvokesEval = function (test) {
+ // ensuring "eval" is caught.
+ var res = init('var string = "var i = 0;"; eval(string);');
+ test.assertEqual('eval', res.parseTree.children[1].value);
+ test.done();
+};
+
+exports.testBlockcomment = function (test) {
+ var jsString = "/* A comment\n* for this new\n* file\n*\/\nvar myJS = 'a string';";
+ var res = init(jsString);
+ test.assertEqual(" A comment\n* for this new\n* file\n", res.parseTree.children[0].blockComments);
+};
+
+exports.testSingleLineComment = function (test) {
+ var jsString = "// this is not free software\nvar myJS = 'a string';";
+ var res = init(jsString);
+ test.assertEqual(" this is not free software", res.parseTree.children[0].blockComments);
+};
+
+
+exports.testMultipleLineComment = function (test) {
+ var i = 0, jsString, expectedResult, ast;
+
+ jsString = "// Below I'm assigning 'a string' to variable myJS\n// this is rather complicated\nvar myJS = 'a string';";
+ expectedResult = [" Below I'm assigning 'a string' to variable myJS", " this is rather complicated"];
+ var res = init(jsString);
+ for (; i < expectedResult.length; i++) {
+ test.assertEqual(expectedResult[i], res.parseTree.children[0].blockComments[i]);
+ }
+};
+*/
diff --git a/test/test-nonfree_checker.js b/test/test-nonfree_checker.js
new file mode 100644
index 0000000..7179a56
--- /dev/null
+++ b/test/test-nonfree_checker.js
@@ -0,0 +1,101 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+const check = require("js_checker/free_checker");
+const licenses = require("js_checker/license_definitions");
+const mockNodes = require("./mock/mock_nodes_with_comments");
+
+var mockLicense = function () {
+ return {
+ 'name': 'A Fake License',
+ 'licenseFragments': [{text: "<VERSION>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur id libero ut justo laoreet congue sed a tortor. Sed iaculis, lacus sit amet cursus facilisis, ligula ligula rutrum leo, et laoreet urna sapien id risus. Curabitur suscipit felis vitae nisl laoreet tempor. Nulla facilisi. Praesent sem magna, sodales sed blandit ut, hendrerit sit amet ante. Quisque sed erat eget ante vehicula fermentum sit amet ac nibh. Ut euismod, lorem non dignissim auctor, orci nulla facilisis nibh, congue aliquam ante libero non metus. Nam vitae lorem tortor. Nunc vehicula justo a odio ornare sollicitudin. Quisque egestas ultrices pretium. Sed tortor quam, dictum sed cursus suscipit, rhoncus id lacus.\nIn eu feugiat ipsum. Integer fringilla dapibus nunc iaculis imperdiet. Duis eros felis, eleifend ac lobortis convallis, hendrerit in ligula. Curabitur volutpat, turpis sed pretium vestibulum, ipsum sem sollicitudin turpis, a sollicitudin enim erat eget dolor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque tristique imperdiet libero et iaculis. Aliquam facilisis mauris at neque tincidunt suscipit facilisis felis eleifend. Aliquam condimentum enim at nisi placerat ultrices. Nullam id sapien lectus. Vivamus id felis lorem, at hendrerit est.\n\nCurabitur augue urna, eleifend ac rutrum venenatis, lobortis sagittis purus. Etiam quam odio, sodales elementum volutpat eu, condimentum eu nunc. In hac habitasse platea dictumst. Cras eu arcu a arcu scelerisque iaculis in vel nunc. Integer vitae varius leo. Vestibulum ultricies, magna nec sodales gravida, leo eros tincidunt mi, ac ornare nibh magna vel turpis. Sed ornare viverra lectus, et varius orci vehicula ac.\n\n", type: licenses.types.SHORT}, {text: "A very short license mention", type: licenses.types.SHORT}]
+ };
+};
+
+exports.testStripLicenseToRegexp_1 = function (test) {
+ test.assert(check.freeCheck.stripLicenseToRegexp(mockLicense()));
+ test.done();
+};
+exports.testStripLicenseToRegexp_2 = function (test) {
+ var resultText = /.*?LoremipsumdolorsitametconsecteturadipiscingelitCurabituridliberoutjustolaoreetconguesedatortorSediaculislacussitametcursusfacilisisligulaligularutrumleoetlaoreeturnasapienidrisusCurabitursuscipitfelisvitaenisllaoreettemporNullafacilisiPraesentsemmagnasodalessedblandituthendreritsitametanteQuisquesederategetantevehiculafermentumsitametacnibhUteuismodloremnondignissimauctororcinullafacilisisnibhconguealiquamanteliberononmetusNamvitaeloremtortorNuncvehiculajustoaodioornaresollicitudinQuisqueegestasultricespretiumSedtortorquamdictumsedcursussuscipitrhoncusidlacusIneufeugiatipsumIntegerfringilladapibusnunciaculisimperdietDuiserosfeliseleifendaclobortisconvallishendreritinligulaCurabiturvolutpatturpissedpretiumvestibulumipsumsemsollicitudinturpisasollicitudinenimerategetdolorLoremipsumdolorsitametconsecteturadipiscingelitPellentesquetristiqueimperdietliberoetiaculisAliquamfacilisismaurisatnequetinciduntsuscipitfacilisisfeliseleifendAliquamcondimentumenimatnisiplaceratultricesNullamidsapienlectusVivamusidfelisloremathendreritestCurabituraugueurnaeleifendacrutrumvenenatislobortissagittispurusEtiamquamodiosodaleselementumvolutpateucondimentumeununcInhachabitasseplateadictumstCraseuarcuaarcuscelerisqueiaculisinvelnuncIntegervitaevariusleoVestibulumultriciesmagnanecsodalesgravidaleoerostinciduntmiacornarenibhmagnavelturpisSedornareviverralectusetvariusorcivehiculaac/i;
+ var t = check.freeCheck.stripLicenseToRegexp(mockLicense());
+ test.assertEqual(resultText.toString(), t.licenseFragments[0].regex.toString());
+ test.done();
+};
+
+exports.testStripLicenseToRegexpForMultipleStrings = function (test) {
+ var resultText = /Averyshortlicensemention/i;
+ var item;
+ t = check.freeCheck.stripLicenseToRegexp(mockLicense());
+ for (item in t.licenseFragments) {
+ test.assert(t.licenseFragments[item].text);
+ test.assert(t.licenseFragments[item].type);
+ test.assert(t.licenseFragments[item].regex);
+ }
+ test.assertEqual(resultText.toString(), t.licenseFragments[1].regex.toString());
+ test.done();
+};
+
+exports.testGetComment = function (test) {
+ var n = mockNodes.mockNodesWithComments.gplv3Node;
+ var comment = "*@licstart The following is the entire license notice for the JavaScript code in this page.* A Fake JS Library\n * Copyright (C) 2011 Patrick Star\n * \n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n * \n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n * \n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see .\n @licend The above is the entire license notice for the JavaScript code in this page.";
+
+ test.assertEqual(comment, check.freeCheck.getComment(n.children[0]));
+};
+
+exports.testGetSingleLineComment = function (test) {
+ var n = mockNodes.mockNodesWithComments.gplv3Node.children[1];
+ var comment = " a single line comment. another single line comment.";
+
+ test.assertEqual(comment, check.freeCheck.getComment(n));
+};
+
+exports.testCheckNodeFreeLicense = function (test) {
+ var n = mockNodes.mockNodesWithComments.gplv3Node.children[0];
+ n.counter = 2;
+ n.parent = {type: 42};
+ test.assertEqual('GNU General Public License (GPL) version 3',
+ check.freeCheck.checkNodeFreeLicense(n).licenseName);
+};
+
+exports.testCheckNodeFreeLicense2 = function (test) {
+ var n = { blockComments: "/*\n * Piwik - Web Analytics\n *\n * JavaScript tracking client\n *\n * @link http://piwik.org\n * @source http://dev.piwik.org/trac/browser/trunk/js/piwik.js\n * @license http://www.opensource.org/licenses/bsd-license.php Simplified BSD\n *\n *\n*@licstart The following is the entire license notice for the JavaScript code in this page.\n\nCopyright (c) 1999, Loic Duros\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n Neither the name of the Blah nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.@licend The above is the entire license notice for the JavaScript code in this page. */", counter: 2, parent: {type: 42} };
+
+ test.assertEqual(
+ 'BSD 3-Clause License',
+ check.freeCheck.checkNodeFreeLicense(n).licenseName);
+
+
+};
+
+exports.testCheckNodeFreeLicenseNotFree = function (test) {
+ var n = mockNodes.mockNodesWithComments.gplv3Node.children[1];
+ test.assertNotEqual(true, check.freeCheck.checkNodeFreeLicense(n));
+};
+
+/*
+exports.testLicenseToRegexp = function (test) {
+ var loader = test.makeSandboxedLoader();
+ var module = loader.require('js_checker/free_checker');
+ var privateScope = loader.findSandboxForModule('js_checker/free_checker'.toString()).globalScope;
+ // ensure the regex values are truthy.
+ test.assert(privateScope.licenses.licenses.gplv2.licenseFragments[0].regex);
+}
+*/
diff --git a/test/test-nontrivial_checker.js b/test/test-nontrivial_checker.js
new file mode 100644
index 0000000..1e5f2d5
--- /dev/null
+++ b/test/test-nontrivial_checker.js
@@ -0,0 +1,180 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+const nonTrivialCheckModule = require("js_checker/nontrivial_checker");
+const check = nonTrivialCheckModule.nonTrivialChecker(false, false);
+const mn = require("./mock/mock_nodes");
+var testRunner;
+
+const constants = require("js_checker/constant_types");
+var checkTypes = constants.checkTypes;
+
+var testCheckNontrivial = function (assert, n) {
+ assert.equal(checkTypes.NONTRIVIAL, check.checkNontrivial(n).type);
+};
+
+
+exports.testInvokesEvalIdentifier = function (assert) {
+ // a node that could be found during
+ // jsChecker walkTree execution.
+ // n corresponds to "eval".
+ var n = mn.mockNodes.eval;
+ // making sure we have a correct (as expected) tree
+ assert.equal(true, check.invokesEval(n));
+ //testCheckNontrivial(test, n1);
+};
+
+exports.testInvokesEvalIdentifier_2 = function(assert) {
+ // a node that could be found during
+ // jsChecker walkTree execution.
+ // n corresponds to "evaluate"
+ var n = mn.mockNodes.evaluate;
+ // making sure we have a correct (as expected) tree
+ assert.notEqual(true, check.invokesEval(n));
+};
+
+exports.testInvokesMethodBracketSuffix = function(assert) {
+ // n corresponds to window['eval']('var i;');
+ var n = mn.mockNodes["window['eval']('var i;');"];
+ assert.equal(true, check.invokesMethodBracketSuffix(n));
+ testCheckNontrivial(assert, n);
+};
+
+exports.testInvokesMethodBracketSuffixArray = function(assert) {
+ // n1 corresponds to array[num] = 'some text';
+ var n = mn.mockNodes["array[num] = 'some text';"];
+ assert.notEqual(true, check.invokesMethodBracketSuffix(n));
+};
+
+exports.testCreatesXhrObject = function(assert) {
+ // n1 corresponds to identifier "XMLHttpRequest"
+ var n = mn.mockNodes.XMLHttpRequest;
+ assert.equal(true, check.createsXhrObject(n));
+ testCheckNontrivial(assert, n);
+};
+
+exports.testCreatesXhrObject_MS = function (assert) {
+ // n1 corresponds to identifier "ActiveXObject"
+ var n = mn.mockNodes.ActiveXObject;
+ assert.equal(true, check.createsXhrObject(n));
+};
+
+exports.testInvokesXhrOpen = function (assert) {
+ // n1 corresponds to:
+ // "oReq.open("GET", "http://localhost/test.xml", true);"
+ var n = mn.mockNodes["oReq.open('GET', 'http://localhost/test.xml', true;)"];
+ assert.equal(true, check.invokesXhrOpen(n));
+ testCheckNontrivial(assert, n);
+};
+
+exports.testInvokesMethodOpenNotXhr = function (assert) {
+ // n1 corresponds to:
+ // "oReq.open("a random string");"
+ var n = mn.mockNodes["oReq.open('a random string');"];
+ assert.notEqual('global', check.invokesXhrOpen(n));
+};
+
+exports.testCreatesScriptElement = function (assert) {
+ // n1 corresponds to:
+ // "document.createElement('script');"
+ var n = mn.mockNodes["document.createElement('script');"];
+ assert.equal(true, check.createsScriptElement(n));
+ testCheckNontrivial(assert, n);
+};
+
+exports.testScriptWrittenAsHtmlString = function(assert) {
+ // string written corresponds to:
+ //<script src=\"evil-js.js\"type=\"text/javascript\></script>
+ // and written with document.write();
+ var n = mn.mockNodes[
+ 'document.write("script src=\"evil-js.js\"type=\"text/javascript></script>")'];
+ assert.equal(true, check.writesScriptAsHtmlString(n));
+ testCheckNontrivial(assert, n);
+};
+
+exports.testScriptWrittenAsStringConcat = function(assert) {
+ // string written corresponds to:
+ // document.write('a ' + ' text');
+ // since we are not currently analyzing such construct
+ // we are flagging it as nontrivial.
+ var n = mn.mockNodes["document.write('a ' + ' text');"];
+ assert.equal(true, check.writesScriptAsHtmlString(n));
+ testCheckNontrivial(assert, n);
+};
+
+exports.testWriteNonscriptHtmlString = function(assert) {
+// corresponds to: document.write('<h1>some text</h1>');
+ var n = mn.mockNodes["document.write('<h1>some text</h1>')"];
+ assert.equal(false, check.writesScriptAsHtmlString(n));
+};
+
+/*exports.testSetsInnerHTMLProperty = function (test) {
+ var n = mn.mockNodes['element.innerHTML = "<script src=\'externalscript.js\'></script>";'];
+ test.assertEqual(true, check.setsInnerHTMLProperty(n));
+ testCheckNontrivial(test, n);
+ test.done();
+};*/
+
+/*exports.testSetsInnerHTMLPropertyNonscript = function (test) {
+ var n = mn.mockNodes['element.innerHTML = "<h1>A headline!</h1>";'];
+ test.assertNotEqual(true, check.setsInnerHTMLProperty(n));
+ test.done();
+};*/
+
+/*
+exports.testSetsInnerHTMLPropertyConcat = function (test) {
+ var n = mn.mockNodes['element.innerHTML = "script src" + "=\'eviljs.js\'";'];
+ test.assertEqual(true, check.setsInnerHTMLProperty(n));
+ testCheckNontrivial(test, n);
+ test.done();
+};
+*/
+/*exports.testCheckNonTrivialWithFuncDefAndIsLoadedExternally = function (test) {
+ var subcheck = nonTrivialCheckModule.nonTrivialChecker(true, false);
+ // a node that could be found during
+ // jsChecker walkTree execution.
+ // n corresponds to "function example(param1) {}"
+ var n = mn.mockNodes['function example(param1) {}'];
+ // making sure we have a correct (as expected) tree
+ test.assertEqual('local', subcheck.checkNontrivial(n));
+ test.done();
+};
+
+exports.testCheckNonTrivialWithFuncDefAndHtmlLoadsExternalScripts = function (test) {
+ var subcheck = nonTrivialCheckModule.nonTrivialChecker(false, true);
+ // a node that could be found during
+ // jsChecker walkTree execution.
+ // n corresponds to "function example(param1) {}"
+ var n = mn.mockNodes['function example(param1) {}'];
+ // making sure we have a correct (as expected) tree
+ test.assertEqual('local', subcheck.checkNontrivial(n));
+ test.done();
+};
+
+exports.testCheckNonTrivialWithFuncDefAndHtmlLoadsExternalScriptsAndIsLoadedExternally = function (test) {
+ // that's not really possible, but avoiding silent bugs.
+ var subcheck = nonTrivialCheckModule.nonTrivialChecker(true, true);
+ var n = mn.mockNodes['function example(param1) {}'];
+ // making sure we have a correct (as expected) tree
+ test.assertEqual('local', subcheck.checkNontrivial(n));
+ test.done();
+};*/
+
+require('sdk/test').run(exports);
diff --git a/test/test-privacy_checker.js b/test/test-privacy_checker.js
new file mode 100644
index 0000000..4be09d5
--- /dev/null
+++ b/test/test-privacy_checker.js
@@ -0,0 +1,55 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+const privacyCheck = require("js_checker/privacy_checker").privacyCheck;
+
+exports.testPrivacyCheckerGoogleAnalyticsRegex = function(assert) {
+ // original analytics code this was designed for
+ var scriptText =
+ "var _gaq = _gaq || [];\n" +
+ "_gaq.push(['_setAccount', 'UA-5555555-1']);\n" +
+ "_gaq.push(['_trackPageview']);\n" +
+ "\n" +
+ "(function() {\n" +
+ "var ga = document.createElement('script'); ga.type = " +
+ "'text/javascript'; ga.async = true;\n" +
+ "ga.src = ('https:' == document.location.protocol ? 'https://ssl'" +
+ " : 'http://www') + '.google-analytics.com/ga.js';\n" +
+ "var s = document.getElementsByTagName('script')[0]; " +
+ "s.parentNode.insertBefore(ga, s);\n" +
+ "})();";
+ var check = privacyCheck.checkScriptPrivacyThreat(scriptText);
+ assert.equal(check, true, 'regex recognizes old GA code');
+
+ // newer analytics code
+ scriptText =
+ "var _gaq = _gaq || [];\n" +
+ "_gaq.push(['_setAccount', 'UA-5555555-2']);\n" +
+ "\n" +
+ "(function() {\n" +
+ " var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n" +
+ " ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n" +
+ " var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n" +
+ "})();";
+ check = privacyCheck.checkScriptPrivacyThreat(scriptText);
+ assert.equal(check, true, 'regex recognizes new GA code');
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-relation_checker.js b/test/test-relation_checker.js
new file mode 100644
index 0000000..25bf1c5
--- /dev/null
+++ b/test/test-relation_checker.js
@@ -0,0 +1,68 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var relationChecker = require('js_checker/relation_checker').relationChecker('b');
+const mn = require("./mock/mock_nodes");
+
+// the fake node.
+var nVar = mn.mockNodes["var def = 'blah';var i = 0;\n\n def = 'something else';"];
+nVar.global = true;
+
+var nFunc = mn.mockNodes["function test (myArgument) { doSomething(); }"];
+nFunc.global = true;
+
+exports.testIsWindowProperty = function (test) {
+ test.assertEqual(relationChecker.isWindowProperty('alert'), true);
+ test.assertEqual(relationChecker.isWindowProperty('alerts'), false);
+ test.assertEqual(relationChecker.isWindowProperty('RegExp'), true);
+ test.assertEqual(relationChecker.isWindowProperty('console'), true);
+};
+
+exports.testCheckNodeForVars = function (test) {
+ relationChecker.storeNodeVars(nVar);
+ test.assertEqual('def' in relationChecker.variableDeclarations,
+ true);
+ test.assertEqual('i' in relationChecker.variableDeclarations,
+ true);
+};
+
+
+exports.testCheckNodeForFunctions = function (test) {
+ relationChecker.storeNodeFunctions(nFunc);
+ test.assertEqual('test' in relationChecker.functionDeclarations,
+ true);
+};
+
+exports.testCheckMethodNotAdded = function (test) {
+ relationChecker.storeNodeFunctions(nFunc);
+ relationChecker.storeNodeFunctions(mn.mockNodes["var myObj = { 'myMethod': function (arg) { alert(arg); } }"]);
+ test.assertEqual('myMethod' in relationChecker.functionDeclarations, false);
+};
+
+
+
+
+exports.testStoreNodeGlobalDeclarations = function (test) {
+ var check = require('js_checker/relation_checker').relationChecker('b');
+ check.storeNodeGlobalDeclarations(nVar);
+ test.assertEqual('def' in check.variableDeclarations, true);
+ check.storeNodeGlobalDeclarations(nFunc);
+ test.assertEqual('test' in check.functionDeclarations, true);
+};
diff --git a/test/test-removed_scripts.js b/test/test-removed_scripts.js
new file mode 100644
index 0000000..d79d15c
--- /dev/null
+++ b/test/test-removed_scripts.js
@@ -0,0 +1,67 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var removedScripts = require('script_entries/removed_scripts').removedScripts;
+
+exports.truncateDataTest = function(test) {
+ var str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ultricies molestie tellus, eu ullamcorper dui luctus sit amet. Morbi sed urna eu justo malesuada bibendum nec non est. Sed sagittis sodales ullamcorper. Mauris dolor arcu, dignissim ac sollicitudin ac, tempus at orci. Curabitur pretium risus id urna congue cursus. Nulla ullamcorper faucibus nibh, eget ultrices ante vestibulum id. Vestibulum elementum ullamcorper mi, id ultrices lacus faucibus et. Nullam lectus augue, suscipit a elementum at, malesuada eget nulla. Aenean tempus ultrices elit ut vulputate. Ut congue magna ultricies felis rutrum eget ultricies nibh vehicula. In id pellentesque risus. Pellentesque aliquam quam eros, quis placerat eros. Cras molestie, turpis et consectetur sollicitudin, magna enim mattis lectus, et adipiscing erat urna in risus. Vestibulum sed arcu vitae mauris ornare ultricies a sit amet leo. Praesent pharetra, urna in varius fermentum, neque nibh tempor justo, id ullamcorper magna amet.…";
+ var t = {contents: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque ultricies molestie tellus, eu ullamcorper dui luctus sit amet. Morbi sed urna eu justo malesuada bibendum nec non est. Sed sagittis sodales ullamcorper. Mauris dolor arcu, dignissim ac sollicitudin ac, tempus at orci. Curabitur pretium risus id urna congue cursus. Nulla ullamcorper faucibus nibh, eget ultrices ante vestibulum id. Vestibulum elementum ullamcorper mi, id ultrices lacus faucibus et. Nullam lectus augue, suscipit a elementum at, malesuada eget nulla. Aenean tempus ultrices elit ut vulputate. Ut congue magna ultricies felis rutrum eget ultricies nibh vehicula. In id pellentesque risus. Pellentesque aliquam quam eros, quis placerat eros. Cras molestie, turpis et consectetur sollicitudin, magna enim mattis lectus, et adipiscing erat urna in risus. Vestibulum sed arcu vitae mauris ornare ultricies a sit amet leo. Praesent pharetra, urna in varius fermentum, neque nibh tempor justo, id ullamcorper magna amet. Something after 1000 character here should be removed."};
+
+ test.assertEqual(str.length, 1001);
+ removedScripts.truncateJsData(t);
+ test.assertEqual(str, t.contents);
+
+};
+
+exports.addAScriptInline = function(test) {
+ var jsString = 'var b = document.createElement("script");';
+ var script = {inline:true, contents: jsString, removalReason: 'creates a script element.'};
+ test.assertEqual(script.contents, jsString);
+ removedScripts.addAScript('http://www.example.org/', script);
+ var fetchedScript = removedScripts.getScripts('http://www.example.org/');
+ test.assert(fetchedScript);
+ test.assertEqual(fetchedScript[0].contents, jsString);
+};
+
+exports.testAddAScriptTwice = function (test) {
+ var jsString = 'var b = document.createElement("script");';
+ var script = {inline:true, contents: jsString, removalReason: 'creates a script element.'};
+ test.assertEqual(removedScripts.addAScript('http://www.example.org/', script), false);
+};
+
+exports.testIsFound = function (test) {
+ var url = 'http://lduros.net/';
+ var str = "http://www.lduros.net/assets/blah.js";
+ var script = {inline:false, contents: str};
+ removedScripts.addAScript('http://lduros.net/', script);
+ test.assertEqual(removedScripts.isFound(url, script), true);
+};
+
+exports.testIsFoundHash = function (test) {
+ var str = "var i = 0;";
+ var hash = '1621f3b5cfc1c3753f347349677f53e82285a2f1';
+
+ // Unline in test-all_scripts.js, we are not adding hash here.
+ // The hash property should be added during addAScript execution.
+ var obj = {'inline': true, 'contents': str};
+ removedScripts.addAScript('http://example.com/', obj);
+ test.assertEqual(removedScripts.scripts['http://example.com/'][removedScripts.scripts['http://example.com/'].length -1].hash, hash);
+ test.assertEqual(removedScripts.isFound('http://example.com/', obj), true);
+};
diff --git a/test/test-request.js b/test/test-request.js
new file mode 100644
index 0000000..a2f9f17
--- /dev/null
+++ b/test/test-request.js
@@ -0,0 +1,102 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var xhr2 = require("html_script_finder/dom_handler/request");
+var Request = require("sdk/request").Request;
+
+exports.testHttpsEverywhere = function (test) {
+
+ test.waitUntilDone();
+
+ var script = {url: 'https://static.fsf.org/nosvn/appeal2011/widget.js'};
+
+ var callback = function (script, text) {
+ //console.log('response received', text);
+ test.assert(true);
+ test.done();
+ };
+
+ var req = xhr2.request(script, callback);
+
+ req.request();
+
+};
+
+exports.testXhr = function (test) {
+
+ // async.
+ test.waitUntilDone();
+
+ var script = {url: 'http://lduros.net/assets/js/prettify/prettify.js'};
+
+ var callback = function (script, text) {
+
+ //console.log('response received', text);
+ test.assert(true);
+ test.done();
+ };
+
+ var req = xhr2.request(script, callback);
+
+ req.request();
+
+};
+
+exports.testXhr2 = function (test) {
+
+ // async.
+ test.waitUntilDone();
+
+ var script = {url: 'http://www.fsf.org/graphics/widget/global/widget.js'};
+
+ var callback = function (script, text) {
+
+ //console.log('response received', text);
+ test.assert(true);
+ test.done();
+ };
+
+ var req = xhr2.request(script, callback);
+
+ req.request();
+
+};
+
+exports.testCompareXhr2WithSDKRequest = function (test) {
+
+ test.waitUntilDone();
+
+ var url = 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js';
+
+ Request({
+ 'url': url,
+ 'onComplete': function (response) {
+ console.log('first response received');
+ var script = {'url': url};
+ var callback = function(script, text) {
+ test.assertEqual(response.text, text);
+ test.done();
+ };
+
+ var req = xhr2.request(script, callback);
+ req.request();
+ }
+ }).get();
+};
diff --git a/test/test-script_detector.js b/test/test-script_detector.js
new file mode 100644
index 0000000..c6f3955
--- /dev/null
+++ b/test/test-script_detector.js
@@ -0,0 +1,49 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var pageMod = require("sdk/page-mod");
+var tabs = require("sdk/tabs");
+var data = require("sdk/self").data;
+
+exports.testScriptsFetched = function (test) {
+ test.waitUntilDone();
+
+ var mod = pageMod.PageMod({
+ include: "data:*",
+ contentScriptWhen: 'end',
+ contentScriptFile: [data.url('settings/third-party/jquery/jquery.min.js'),
+ data.url('complain/contact_finder.js'),
+ data.url('complain/pagemod_finder.js'),
+ data.url('script_detector/script_detector.js')],
+ contentScript: "scriptDetector.init();",
+ onAttach: function (worker) {
+ worker.on('message', function (message) {
+ if (message.event === 'scriptsFetched') {
+ test.assertEqual(message.value.blocked[0].contents, "var num = 5;");
+ test.assertEqual(message.value.blocked[0].inline, true);
+ test.done();
+ }
+ });
+ }
+ });
+
+ tabs.open("data:text/html;charset=utf-8,<!doctype html>%0D%0A<html>%0D%0A<head><script type='librejs/blocked'>var num %3D 5%3B<%2Fscript><%2Fhead>%0D%0A%0D%0A<body><h1 id='test'>Test<%2Fh1><a href='contact.html'>contact</a><%2Fbody><%2Fhtml>");
+
+};
diff --git a/test/test-script_object.js b/test/test-script_object.js
new file mode 100644
index 0000000..29579b5
--- /dev/null
+++ b/test/test-script_object.js
@@ -0,0 +1,50 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var scriptObject = require("html_script_finder/dom_handler/script_object");
+
+exports.testCreateNewScript = function(assert) {
+ var script1, script2;
+
+ script1 = scriptObject.Script({'type': 'inline',
+ 'status': 'test',
+ 'text': 'test',
+ 'element': {}});
+
+ assert.equal('object', typeof script1);
+ assert.equal('inline', script1.type);
+
+ script2 = scriptObject.Script({'type': 'external',
+ 'status': 'test',
+ 'element': {}});
+ assert.equal(script2.text, null);
+};
+
+exports.testRemoveNarcissusBugLine = function(assert) {
+ var script = scriptObject.Script({'type': 'external',
+ 'status': 'test',
+ 'element': {}});
+ var scriptText = "var i = 0;\n\nthis.narcissusBugFixLibreJS";
+ var scriptText2 = "var i = 0;";
+ assert.equal(script.removeNarcissusBugLine(scriptText), 'var i = 0;');
+ assert.equal(script.removeNarcissusBugLine(scriptText2), 'var i = 0;');
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-script_properties.js b/test/test-script_properties.js
new file mode 100644
index 0000000..c7928c0
--- /dev/null
+++ b/test/test-script_properties.js
@@ -0,0 +1,29 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+var scriptProperties = require("html_script_finder/dom_handler/script_properties");
+const scriptTypes = scriptProperties.scriptTypes;
+const statusTypes = scriptProperties.statusTypes;
+
+exports.testScriptTypes = function (assert) {
+ assert.equal(scriptTypes.INLINE, 0);
+ assert.equal(scriptTypes.EXTERNAL, 1);
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-stream_loader.js b/test/test-stream_loader.js
new file mode 100644
index 0000000..b2a51b2
--- /dev/null
+++ b/test/test-stream_loader.js
@@ -0,0 +1,35 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var streamLoader = require("http_observer/stream_loader.js");
+var {Cc, Ci, Cu, Cm, Cr} = require("chrome");
+
+exports.testListener = function (assert) {
+ var mozStreamLoader = Cc["@mozilla.org/network/unichar-stream-loader;1"].
+ createInstance(Ci.nsIUnicharStreamLoader);
+ mozStreamLoader.init(streamLoader.streamLoader().listener);
+ var ios = Cc["@mozilla.org/network/io-service;1"]
+ .getService(Ci.nsIIOService);
+ var chan = ios.newChannel("http://example.com", null, null);
+ chan.asyncOpen(mozStreamLoader, null);
+ assert.ok(true);
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-ui_info.js b/test/test-ui_info.js
new file mode 100644
index 0000000..4cf3ecd
--- /dev/null
+++ b/test/test-ui_info.js
@@ -0,0 +1,42 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var uiInfo = require("ui/ui_info").testModule;
+
+
+exports.testFoundInContactList = function (test) {
+
+ uiInfo.contactList['www.lduros.net'] = 'http://lduros.net/contact';
+
+ test.assertEqual(uiInfo.foundInContactList('http://www.lduros.net/somepage.html'),
+ 'http://lduros.net/contact');
+
+
+};
+
+exports.testNotFoundInContactList = function (test) {
+
+ delete uiInfo.contactList['www.lduros.net'];
+
+ test.assertEqual(uiInfo.foundInContactList('http://www.lduros.net/somepage.html'),
+ false);
+
+
+};
diff --git a/test/test-url_handler.js b/test/test-url_handler.js
new file mode 100644
index 0000000..b0e388d
--- /dev/null
+++ b/test/test-url_handler.js
@@ -0,0 +1,78 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+const urlHandler = require('url_handler/url_handler');
+
+exports.testRemoveFragment1 = function (test) {
+ var url = 'http://example.org/blah.html#section';
+ var result = urlHandler.removeFragment(url);
+ test.assertEqual(result, 'http://example.org/blah.html');
+};
+
+exports.testRemoveFragmentWithQueryString = function (test) {
+ // test for the Amazon Track Package related bug.
+ var url = 'http://example.org/blah.html?q=something#section';
+ var result = urlHandler.removeFragment(url);
+ test.assertEqual(result, 'http://example.org/blah.html?q=something');
+};
+
+exports.testQueryString = function (test) {
+ // test for the Amazon Track Package related bug.
+ var url = 'http://example.org/blah.html';
+ var t = urlHandler.parse(url);
+ t.search = 'librejs=contact';
+ console.log(JSON.stringify(t));
+ test.assertEqual(t.search, 'librejs=contact');
+ test.assertEqual(urlHandler.format(t), 'http://example.org/blah.html?librejs=contact');
+};
+
+exports.testAddQuery = function (test) {
+ // test for the Amazon Track Package related bug.
+ var url = 'http://example.org/blah.html?t=1';
+ var t = urlHandler.addQuery(url, 'librejs=contact');
+ test.assertEqual(t, 'http://example.org/blah.html?t=1&librejs=contact');
+};
+
+exports.testAddQueryWithFragment = function (test) {
+ // test for the Amazon Track Package related bug.
+ var url = 'http://example.org/blah.html?t=1#topic1';
+ var t = urlHandler.addQuery(url, 'librejs=contact');
+ test.assertEqual(t, 'http://example.org/blah.html?t=1&librejs=contact#topic1');
+};
+
+exports.testGetHostname = function (test) {
+ var url = 'http://example.org/some-site.html';
+ test.assertEqual(urlHandler.getHostname(url), 'example.org');
+};
+
+exports.testGetHostnameWithWWW = function (test) {
+ var url = 'http://www.example.org/some-site.html';
+ test.assertEqual(urlHandler.getHostname(url), 'www.example.org');
+};
+
+exports.testGetHostnameWithWWW2 = function (test) {
+ var url = 'http://www.lduros.net/somepage.html';
+ test.assertEqual(urlHandler.getHostname(url), 'www.lduros.net');
+};
+
+exports.testDONOTHaveSameHostname = function (test) {
+ var url1 = 'http://marcotempest.com/screen/PublicContactStartV3/language/en#librejs=true';
+ var url2 = 'http://www.google.com/search?hl=en&output=search&sclient=psy-ab&q=marco+tempest&btnG=';
+ test.assertEqual(urlHandler.haveSameHostname(url1, url2), false);
+};
diff --git a/test/test-web-label-finder.js b/test/test-web-label-finder.js
new file mode 100644
index 0000000..ea0588a
--- /dev/null
+++ b/test/test-web-label-finder.js
@@ -0,0 +1,195 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+const {Cc,Ci} = require('chrome');
+var parser = Cc["@mozilla.org/xmlextras/domparser;1"]
+ .createInstance(Ci.nsIDOMParser);
+
+var WebLabelFinder = require('html_script_finder/web_labels/js_web_labels')
+ .WebLabelFinder;
+
+exports.testSearchForJsLinkEmpty = function (assert) {
+ var finder = new WebLabelFinder();
+ var doc = parser.parseFromString('<html></html>', 'text/html');
+ finder.init(doc, 'http://www.rootstrikers.org', function() {});
+ assert.strictEqual(finder.searchForJsLink(), false);
+};
+
+exports.testSearchForJsLinkJsLicense = function (assert) {
+ var finder = new WebLabelFinder();
+ var doc = parser.parseFromString(
+ '<html><body>' +
+ '<a href="lic.html" rel="jslicense">JavaScript License Info</a>' +
+ '</body></html>', 'text/html');
+ finder.init(doc, 'http://www.rootstrikers.org', function() {});
+
+ assert.strictEqual(
+ finder.searchForJsLink(),
+ 'http://www.rootstrikers.org/lic.html#librejs=true'
+ );
+};
+
+exports.testSearchForJsLinkDataJsLicense = function (assert) {
+ var finder = new WebLabelFinder();
+ var doc = parser.parseFromString(
+ '<html><body>' +
+ '<a href="lic.html" data-jslicense="1">JavaScript License</a>' +
+ '</body></html>', 'text/html');
+ finder.init(doc, 'http://www.rootstrikers.org', function() {});
+
+ assert.strictEqual(
+ finder.searchForJsLink(),
+ 'http://www.rootstrikers.org/lic.html#librejs=true'
+ );
+};
+
+exports.testIsLicenseFreeEmpty = function(assert) {
+ var finder = new WebLabelFinder();
+ // listCheck is initialized by WebLabelFinder.matchListWithDefs...
+ // I'm initializing it here to prevent errors when testing.
+ finder.listCheck = {};
+
+ var lic = {
+ licenses: []
+ };
+ var licArray = [];
+ var jslicenseURL = null;
+ var callback = function() { };
+ assert.strictEqual(
+ finder.isLicenseFree(lic, licArray, jslicenseURL, callback),
+ false,
+ 'A script with no license info is considered nonfree'
+ );
+};
+
+exports.testIsLicenseFree1 = function(assert) {
+ var finder = new WebLabelFinder();
+ finder.listCheck = {};
+
+ var lic = {
+ 'fileName': 'filepicker.js',
+ 'fileUrl': 'http://www.rootstrikers.org/vendor/filepicker.js',
+ 'fileHash': null,
+ 'licenses': [{
+ 'licenseName': 'Expat',
+ 'licenseUrl': 'http://www.jclark.com/xml/copying.txt'
+ }],
+ 'sources':[{
+ 'sourceName': 'filepicker.js',
+ 'sourceUrl': 'http://www.rootstrikers.org/vendor/filepicker.js'
+ }]
+ };
+ var licArray = [];
+ var jslicenseURL = null;
+ var callback = function() { };
+ assert.strictEqual(
+ finder.isLicenseFree(lic, licArray, jslicenseURL, callback),
+ true,
+ 'A script with one free license is considered free'
+ );
+};
+
+exports.testIsLicenseFree3 = function(assert) {
+ var finder = new WebLabelFinder();
+ finder.listCheck = {};
+
+ var lic = {
+ 'fileName': 'all.min.js',
+ 'fileUrl': 'http://example.com/all.min.js',
+ 'fileHash': null,
+ 'licenses': [
+ {
+ 'licenseName': 'GNU-GPL-3.0',
+ 'licenseUrl': 'http://www.gnu.org/licenses/gpl-3.0.html'
+ },
+ {
+ 'licenseName': 'Expat',
+ 'licenseUrl': 'http://www.jclark.com/xml/copying.txt'
+ },
+ {
+ 'licenseName': 'MPL-2.0',
+ 'licenseUrl': 'http://www.mozilla.org/MPL/2.0'
+ }
+ ],
+ 'sources':[
+ {
+ 'sourceName': 'gpl3.js',
+ 'sourceUrl': 'http://www.example.com/gpl3.js'
+ },
+ {
+ 'sourceName': 'expat.js',
+ 'sourceUrl': 'http://www.example.com/expat.js'
+ },
+ {
+ 'sourceName': 'mpl.js',
+ 'sourceUrl': 'http://www.example.com/mpl.js'
+ }
+ ]
+ };
+ var licArray = [];
+ var jslicenseURL = null;
+ var callback = function() { };
+ assert.strictEqual(
+ finder.isLicenseFree(lic, licArray, jslicenseURL, callback),
+ true,
+ 'A script with three free licenses is considered free'
+ );
+};
+
+exports.testIsLicenseNotFree = function(assert) {
+ var finder = new WebLabelFinder();
+ finder.listCheck = {};
+
+ var lic = {
+ 'fileName': 'filepicker.js',
+ 'fileUrl': 'http://www.rootstrikers.org/vendor/filepicker.js',
+ 'fileHash': null,
+ 'licenses': [
+ {
+ 'licenseName': 'Expat',
+ 'licenseUrl': 'http://www.jclark.com/xml/copying.txt'
+ },
+ {
+ 'licenseName': 'Some-Unrecognized-License',
+ 'licenseUrl': 'http://www.example.com/nolicense.txt'
+ }
+ ],
+ 'sources':[
+ {
+ 'sourceName': 'filepicker.js',
+ 'sourceUrl': 'http://www.rootstrikers.org/vendor/filepicker.js'
+ },
+ {
+ 'sourceName': 'nonfree.js',
+ 'sourceUrl': 'http://www.example.com/nonfree.js'
+ }
+ ]
+ };
+ var licArray = [];
+ var jslicenseURL = null;
+ var callback = function() { };
+ assert.strictEqual(
+ finder.isLicenseFree(lic, licArray, jslicenseURL, callback),
+ false,
+ 'A script with one free license and one nonfree is considered nonfree'
+ );
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-web-labels.js b/test/test-web-labels.js
new file mode 100644
index 0000000..b55d6bb
--- /dev/null
+++ b/test/test-web-labels.js
@@ -0,0 +1,42 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var mockLicenseList = [{
+ 'fileName': 'jquery.min.js',
+ 'fileUrl': 'http://www.rootstrikers.org/bower_components/jquery/dist/jquery.min.js',
+ 'fileHash': null,
+ 'licenseName': 'Expat',
+ 'licenseUrl': 'http://www.jclark.com/xml/copying.txt',
+ 'free': true
+}];
+
+var dom_handler = require('html_script_finder/dom_handler');
+
+exports.testScriptHasJsWebLabel = function (assert) {
+ var dm = new dom_handler.DomHandler();
+ dm.licenseList = mockLicenseList;
+ dm.pageURL = 'http://rootstrikers.org/';
+ var script = {
+ 'src': 'http://www.rootstrikers.org/bower_components/jquery/dist/jquery.min.js'
+ };
+ assert.ok(dm.scriptHasJsWebLabel(script));
+};
+
+require('sdk/test').run(exports);
diff --git a/test/test-windowProperty.js b/test/test-windowProperty.js
new file mode 100644
index 0000000..6b8a29b
--- /dev/null
+++ b/test/test-windowProperty.js
@@ -0,0 +1,34 @@
+/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+var relationChecker = require('js_checker/relation_checker');
+const mn = require("./mock/mock_nodes");
+
+exports.testCheckIdentifierIsWindowProperty = function (assert) {
+ var tree = mn.mockNodes["alert('this is completely trivial');"];
+
+ var n = tree.children[0].expression.children[0];
+ n.parent = tree.children[0].expression;
+ var rel = relationChecker.relationChecker(n);
+ rel.checkIdentifierIsWindowProperty(n);
+ assert.equal(rel.nonWindowProperties.alert, null);
+};
+
+require('sdk/test').run(exports);
diff --git a/test/webpages/test-labels/index.html b/test/webpages/test-labels/index.html
new file mode 100644
index 0000000..a570089
--- /dev/null
+++ b/test/webpages/test-labels/index.html
@@ -0,0 +1,36 @@
+<!doctype html>
+
+<html>
+
+ <head>
+<!--/**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+-->
+ <title>A Page containing free JS</title>
+ <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
+ </head>
+
+ <body>
+ <h1>A page containing free js (jquery)</h1>
+
+ <a href="js-licenses.html" rel="jslicense">JavaScript License Information</a>
+ </body>
+
+</html>
diff --git a/test/webpages/test-labels/js-licenses.html b/test/webpages/test-labels/js-licenses.html
new file mode 100644
index 0000000..2d035dd
--- /dev/null
+++ b/test/webpages/test-labels/js-licenses.html
@@ -0,0 +1,45 @@
+<!doctype html>
+
+<html>
+
+ <head>
+
+<!-- /**
+ * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
+ * *
+ * Copyright (C) 2011, 2012, 2014 Loic J. Duros
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+-->
+ <title>JavaScript License Information</title>
+ </head>
+
+ <body>
+ <h1>License information for external JavaScript files present on this site.</h1>
+ <table id="jslicense-labels1">
+
+ <tr>
+ <td><a href="https://code.jquery.com/jquery-2.1.1.min.js">jquery-2.1.1.min.js</a></td>
+
+ <td><a href="http://www.jclark.com/xml/copying.txt">Expat</a></td>
+
+ <td><a href="https://code.jquery.com/jquery-2.1.1.js">jquery-2.1.1.js</a></td>
+ </tr>
+
+ </table>
+ </body>
+
+</html>