| OLD | NEW | 
|    1 /* |    1 /* | 
|    2  * This file is part of Adblock Plus <https://adblockplus.org/>, |    2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
|    3  * Copyright (C) 2006-2016 Eyeo GmbH |    3  * Copyright (C) 2006-2016 Eyeo GmbH | 
|    4  * |    4  * | 
|    5  * Adblock Plus is free software: you can redistribute it and/or modify |    5  * Adblock Plus is free software: you can redistribute it and/or modify | 
|    6  * it under the terms of the GNU General Public License version 3 as |    6  * it under the terms of the GNU General Public License version 3 as | 
|    7  * published by the Free Software Foundation. |    7  * published by the Free Software Foundation. | 
|    8  * |    8  * | 
|    9  * Adblock Plus is distributed in the hope that it will be useful, |    9  * Adblock Plus is distributed in the hope that it will be useful, | 
|   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of |   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|   12  * GNU General Public License for more details. |   12  * GNU General Public License for more details. | 
|   13  * |   13  * | 
|   14  * You should have received a copy of the GNU General Public License |   14  * You should have received a copy of the GNU General Public License | 
|   15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. |   15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
|   16  */ |   16  */ | 
|   17  |   17  | 
|   18 "use strict"; |   18 "use strict"; | 
|   19  |   19  | 
|   20 let fs = require("fs"); |   20 const fs = require("fs"); | 
|   21 let path = require("path"); |   21 const path = require("path"); | 
|   22 let SandboxedModule = require("sandboxed-module"); |   22 const SandboxedModule = require("sandboxed-module"); | 
|   23  |   23  | 
|   24 const Cr = exports.Cr = { |   24 const Cr = exports.Cr = { | 
|   25   NS_OK: 0, |   25   NS_OK: 0, | 
|   26   NS_BINDING_ABORTED: 0x804B0002, |   26   NS_BINDING_ABORTED: 0x804B0002, | 
|   27   NS_ERROR_FAILURE: 0x80004005 |   27   NS_ERROR_FAILURE: 0x80004005 | 
|   28 }; |   28 }; | 
|   29  |   29  | 
|   30 const MILLIS_IN_SECOND = exports.MILLIS_IN_SECOND = 1000; |   30 const MILLIS_IN_SECOND = exports.MILLIS_IN_SECOND = 1000; | 
|   31 const MILLIS_IN_MINUTE = exports.MILLIS_IN_MINUTE = 60 * MILLIS_IN_SECOND; |   31 const MILLIS_IN_MINUTE = exports.MILLIS_IN_MINUTE = 60 * MILLIS_IN_SECOND; | 
|   32 const MILLIS_IN_HOUR = exports.MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE; |   32 const MILLIS_IN_HOUR = exports.MILLIS_IN_HOUR = 60 * MILLIS_IN_MINUTE; | 
|   33 const MILLIS_IN_DAY = exports.MILLIS_IN_DAY = 24 * MILLIS_IN_HOUR; |   33  | 
 |   34 function URL(urlString) | 
 |   35 { | 
 |   36   return require("url").parse(urlString); | 
 |   37 } | 
|   34  |   38  | 
|   35 let globals = { |   39 let globals = { | 
|   36   atob: data => new Buffer(data, "base64").toString("binary"), |   40   atob: data => new Buffer(data, "base64").toString("binary"), | 
|   37   btoa: data => new Buffer(data, "binary").toString("base64"), |   41   btoa: data => new Buffer(data, "binary").toString("base64"), | 
|   38   Ci: { |   42   Ci: { | 
|   39   }, |   43   }, | 
|   40   Cu: { |   44   Cu: { | 
|   41     import: () => {}, |   45     import() {}, | 
|   42     reportError: e => undefined |   46     reportError(e) {} | 
|   43   }, |   47   }, | 
|   44   console: { |   48   console: { | 
|   45     log: () => undefined, |   49     log() {}, | 
|   46     error: () => undefined, |   50     error() {} | 
|   47   }, |   51   }, | 
|   48   navigator: { |   52   navigator: { | 
|   49   }, |   53   }, | 
|   50   onShutdown: { |   54   onShutdown: { | 
|   51     add: () => |   55     add() {} | 
|   52     { |  | 
|   53     } |  | 
|   54   }, |   56   }, | 
|   55   Services: { |   57   Services: { | 
|   56     obs: { |   58     obs: { | 
|   57       addObserver: () => |   59       addObserver() {} | 
|   58       { |  | 
|   59       } |  | 
|   60     }, |   60     }, | 
|   61     vc: { |   61     vc: { | 
|   62       compare: (v1, v2) => |   62       compare(v1, v2) | 
|   63       { |   63       { | 
|   64         function comparePart(p1, p2) |   64         function comparePart(p1, p2) | 
|   65         { |   65         { | 
|   66           if (p1 != "*" && p2 == "*") |   66           if (p1 != "*" && p2 == "*") | 
|   67             return -1; |   67             return -1; | 
|   68           else if (p1 == "*" && p2 != "*") |   68           else if (p1 == "*" && p2 != "*") | 
|   69             return 1; |   69             return 1; | 
|   70           else if (p1 == p2) |   70           else if (p1 == p2) | 
|   71             return 0; |   71             return 0; | 
|   72           else |   72           return parseInt(p1, 10) - parseInt(p2, 10); | 
|   73             return parseInt(p1, 10) - parseInt(p2, 10); |  | 
|   74         } |   73         } | 
|   75  |   74  | 
|   76         let parts1 = v1.split("."); |   75         let parts1 = v1.split("."); | 
|   77         let parts2 = v2.split("."); |   76         let parts2 = v2.split("."); | 
|   78         for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) |   77         for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) | 
|   79         { |   78         { | 
|   80           let result = comparePart(parts1[i] || "0", parts2[i] || "0"); |   79           let result = comparePart(parts1[i] || "0", parts2[i] || "0"); | 
|   81           if (result != 0) |   80           if (result != 0) | 
|   82             return result; |   81             return result; | 
|   83         } |   82         } | 
|   84         return 0; |   83         return 0; | 
|   85       } |   84       } | 
|   86     } |   85     } | 
|   87   }, |   86   }, | 
|   88   XPCOMUtils: { |   87   XPCOMUtils: { | 
|   89     generateQI: () => |   88     generateQI() {} | 
|   90     { |  | 
|   91     } |  | 
|   92   }, |   89   }, | 
|   93   URL: function(urlString) |   90   URL | 
|   94   { |  | 
|   95     return require("url").parse(urlString); |  | 
|   96   } |  | 
|   97 }; |   91 }; | 
|   98  |   92  | 
|   99 let knownModules = new Map(); |   93 let knownModules = new Map(); | 
|  100 for (let dir of [path.join(__dirname, "stub-modules"), |   94 for (let dir of [path.join(__dirname, "stub-modules"), | 
|  101                  path.join(__dirname, "..", "lib")]) |   95                  path.join(__dirname, "..", "lib")]) | 
 |   96 { | 
|  102   for (let file of fs.readdirSync(path.resolve(dir))) |   97   for (let file of fs.readdirSync(path.resolve(dir))) | 
 |   98   { | 
|  103     if (path.extname(file) == ".js") |   99     if (path.extname(file) == ".js") | 
|  104       knownModules[path.basename(file, ".js")] = path.resolve(dir, file); |  100       knownModules[path.basename(file, ".js")] = path.resolve(dir, file); | 
 |  101   } | 
 |  102 } | 
|  105  |  103  | 
|  106 function addExports(exports) |  104 function addExports(exports) | 
|  107 { |  105 { | 
|  108   return function(source) |  106   return function(source) | 
|  109   { |  107   { | 
|  110     let extraExports = exports[path.basename(this.filename, ".js")]; |  108     let extraExports = exports[path.basename(this.filename, ".js")]; | 
|  111     if (extraExports) |  109     if (extraExports) | 
 |  110     { | 
|  112       for (let name of extraExports) |  111       for (let name of extraExports) | 
 |  112       { | 
|  113         source += ` |  113         source += ` | 
|  114           Object.defineProperty(exports, "${name}", {get: () => ${name}});`; |  114           Object.defineProperty(exports, "${name}", {get: () => ${name}});`; | 
 |  115       } | 
 |  116     } | 
|  115     return source; |  117     return source; | 
|  116   }; |  118   }; | 
|  117 } |  119 } | 
|  118  |  120  | 
|  119 function rewriteRequires(source) |  121 function rewriteRequires(source) | 
|  120 { |  122 { | 
|  121   function escapeString(str) |  123   function escapeString(str) | 
|  122   { |  124   { | 
|  123     return str.replace(/(["'\\])/g, "\\$1"); |  125     return str.replace(/(["'\\])/g, "\\$1"); | 
|  124   } |  126   } | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
|  137     options = {}; |  139     options = {}; | 
|  138  |  140  | 
|  139   let sourceTransformers = [rewriteRequires]; |  141   let sourceTransformers = [rewriteRequires]; | 
|  140   if (options.extraExports) |  142   if (options.extraExports) | 
|  141     sourceTransformers.push(addExports(options.extraExports)); |  143     sourceTransformers.push(addExports(options.extraExports)); | 
|  142  |  144  | 
|  143   // This module loads itself into a sandbox, keeping track of the require |  145   // This module loads itself into a sandbox, keeping track of the require | 
|  144   // function which can be used to load further modules into the sandbox. |  146   // function which can be used to load further modules into the sandbox. | 
|  145   return SandboxedModule.require("./_common", { |  147   return SandboxedModule.require("./_common", { | 
|  146     globals: Object.assign({}, globals, options.globals), |  148     globals: Object.assign({}, globals, options.globals), | 
|  147     sourceTransformers: sourceTransformers |  149     sourceTransformers | 
|  148   }).require; |  150   }).require; | 
|  149 }; |  151 }; | 
|  150  |  152  | 
|  151 exports.require = require; |  153 exports.require = require; | 
|  152  |  154  | 
|  153 exports.setupTimerAndXMLHttp = function() |  155 exports.setupTimerAndXMLHttp = function() | 
|  154 { |  156 { | 
|  155   let currentTime = 100000 * MILLIS_IN_HOUR; |  157   let currentTime = 100000 * MILLIS_IN_HOUR; | 
|  156   let startTime = currentTime; |  158   let startTime = currentTime; | 
|  157  |  159  | 
|  158   let fakeTimer = { |  160   let fakeTimer = { | 
|  159     callback: null, |  161     callback: null, | 
|  160     delay: -1, |  162     delay: -1, | 
|  161     nextExecution: 0, |  163     nextExecution: 0, | 
|  162  |  164  | 
|  163     initWithCallback: function(callback, delay, type) |  165     initWithCallback(callback, delay, type) | 
|  164     { |  166     { | 
|  165       if (this.callback) |  167       if (this.callback) | 
|  166         throw new Error("Only one timer instance supported"); |  168         throw new Error("Only one timer instance supported"); | 
|  167       if (type != 1) |  169       if (type != 1) | 
|  168         throw new Error("Only TYPE_REPEATING_SLACK timers supported"); |  170         throw new Error("Only TYPE_REPEATING_SLACK timers supported"); | 
|  169  |  171  | 
|  170       this.callback = callback; |  172       this.callback = callback; | 
|  171       this.delay = delay; |  173       this.delay = delay; | 
|  172       this.nextExecution = currentTime + delay; |  174       this.nextExecution = currentTime + delay; | 
|  173     }, |  175     }, | 
|  174  |  176  | 
|  175     trigger: function() |  177     trigger() | 
|  176     { |  178     { | 
|  177       if (currentTime < this.nextExecution) |  179       if (currentTime < this.nextExecution) | 
|  178         currentTime = this.nextExecution; |  180         currentTime = this.nextExecution; | 
|  179       try |  181       try | 
|  180       { |  182       { | 
|  181         this.callback(); |  183         this.callback(); | 
|  182       } |  184       } | 
|  183       finally |  185       finally | 
|  184       { |  186       { | 
|  185         this.nextExecution = currentTime + this.delay; |  187         this.nextExecution = currentTime + this.delay; | 
|  186       } |  188       } | 
|  187     }, |  189     }, | 
|  188  |  190  | 
|  189     cancel: function() |  191     cancel() | 
|  190     { |  192     { | 
|  191       this.nextExecution = -1; |  193       this.nextExecution = -1; | 
|  192     } |  194     } | 
|  193   }; |  195   }; | 
|  194  |  196  | 
|  195   let requests = []; |  197   let requests = []; | 
|  196   function XMLHttpRequest() |  198   function XMLHttpRequest() | 
|  197   { |  199   { | 
|  198     this._host = "http://example.com"; |  200     this._host = "http://example.com"; | 
|  199     this._loadHandlers = []; |  201     this._loadHandlers = []; | 
|  200     this._errorHandlers = []; |  202     this._errorHandlers = []; | 
|  201   }; |  203   } | 
|  202   XMLHttpRequest.prototype = |  204   XMLHttpRequest.prototype = { | 
|  203   { |  | 
|  204     _path: null, |  205     _path: null, | 
|  205     _data: null, |  206     _data: null, | 
|  206     _queryString: null, |  207     _queryString: null, | 
|  207     _loadHandlers: null, |  208     _loadHandlers: null, | 
|  208     _errorHandlers: null, |  209     _errorHandlers: null, | 
|  209     status: 0, |  210     status: 0, | 
|  210     readyState: 0, |  211     readyState: 0, | 
|  211     responseText: null, |  212     responseText: null, | 
|  212  |  213  | 
|  213     addEventListener: function(eventName, handler, capture) |  214     addEventListener(eventName, handler, capture) | 
|  214     { |  215     { | 
|  215       let list; |  216       let list; | 
|  216       if (eventName == "load") |  217       if (eventName == "load") | 
|  217         list = this._loadHandlers; |  218         list = this._loadHandlers; | 
|  218       else if (eventName == "error") |  219       else if (eventName == "error") | 
|  219         list = this._errorHandlers; |  220         list = this._errorHandlers; | 
|  220       else |  221       else | 
|  221         throw new Error("Event type " + eventName + " not supported"); |  222         throw new Error("Event type " + eventName + " not supported"); | 
|  222  |  223  | 
|  223       if (list.indexOf(handler) < 0) |  224       if (list.indexOf(handler) < 0) | 
|  224         list.push(handler); |  225         list.push(handler); | 
|  225     }, |  226     }, | 
|  226  |  227  | 
|  227     removeEventListener: function(eventName, handler, capture) |  228     removeEventListener(eventName, handler, capture) | 
|  228     { |  229     { | 
|  229       let list; |  230       let list; | 
|  230       if (eventName == "load") |  231       if (eventName == "load") | 
|  231         list = this._loadHandlers; |  232         list = this._loadHandlers; | 
|  232       else if (eventName == "error") |  233       else if (eventName == "error") | 
|  233         list = this._errorHandlers; |  234         list = this._errorHandlers; | 
|  234       else |  235       else | 
|  235         throw new Error("Event type " + eventName + " not supported"); |  236         throw new Error("Event type " + eventName + " not supported"); | 
|  236  |  237  | 
|  237       let index = list.indexOf(handler); |  238       let index = list.indexOf(handler); | 
|  238       if (index >= 0) |  239       if (index >= 0) | 
|  239         list.splice(index, 1); |  240         list.splice(index, 1); | 
|  240     }, |  241     }, | 
|  241  |  242  | 
|  242     open: function(method, url, async, user, password) |  243     open(method, url, async, user, password) | 
|  243     { |  244     { | 
|  244       if (method != "GET") |  245       if (method != "GET") | 
|  245         throw new Error("Only GET requests are supported"); |  246         throw new Error("Only GET requests are supported"); | 
|  246       if (typeof async != "undefined" && !async) |  247       if (typeof async != "undefined" && !async) | 
|  247         throw new Error("Sync requests are not supported"); |  248         throw new Error("Sync requests are not supported"); | 
|  248       if (typeof user != "undefined" || typeof password != "undefined") |  249       if (typeof user != "undefined" || typeof password != "undefined") | 
|  249         throw new Error("User authentification is not supported"); |  250         throw new Error("User authentification is not supported"); | 
|  250  |  251  | 
|  251       let match = /^data:[^,]+,/.exec(url); |  252       let match = /^data:[^,]+,/.exec(url); | 
|  252       if (match) |  253       if (match) | 
|  253       { |  254       { | 
|  254         this._data = decodeURIComponent(url.substr(match[0].length)); |  255         this._data = decodeURIComponent(url.substr(match[0].length)); | 
|  255         return; |  256         return; | 
|  256       } |  257       } | 
|  257  |  258  | 
|  258       if (url.substr(0, this._host.length + 1) != this._host + "/") |  259       if (url.substr(0, this._host.length + 1) != this._host + "/") | 
|  259         throw new Error("Unexpected URL: " + url + " (URL starting with " + this
     ._host + "expected)"); |  260         throw new Error("Unexpected URL: " + url + " (URL starting with " + this
     ._host + "expected)"); | 
|  260  |  261  | 
|  261       this._path = url.substr(this._host.length); |  262       this._path = url.substr(this._host.length); | 
|  262  |  263  | 
|  263       let queryIndex = this._path.indexOf("?"); |  264       let queryIndex = this._path.indexOf("?"); | 
|  264       this._queryString = ""; |  265       this._queryString = ""; | 
|  265       if (queryIndex >= 0) |  266       if (queryIndex >= 0) | 
|  266       { |  267       { | 
|  267         this._queryString = this._path.substr(queryIndex + 1); |  268         this._queryString = this._path.substr(queryIndex + 1); | 
|  268         this._path = this._path.substr(0, queryIndex); |  269         this._path = this._path.substr(0, queryIndex); | 
|  269       } |  270       } | 
|  270     }, |  271     }, | 
|  271  |  272  | 
|  272     send: function(data) |  273     send(data) | 
|  273     { |  274     { | 
|  274       if (!this._data && !this._path) |  275       if (!this._data && !this._path) | 
|  275         throw new Error("No request path set"); |  276         throw new Error("No request path set"); | 
|  276       if (typeof data != "undefined" && data) |  277       if (typeof data != "undefined" && data) | 
|  277         throw new Error("Sending data to server is not supported"); |  278         throw new Error("Sending data to server is not supported"); | 
|  278  |  279  | 
|  279       requests.push(Promise.resolve().then(() => |  280       requests.push(Promise.resolve().then(() => | 
|  280       { |  281       { | 
|  281         let result = [Cr.NS_OK, 404, ""]; |  282         let result = [Cr.NS_OK, 404, ""]; | 
|  282         if (this._data) |  283         if (this._data) | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
|  293         [this.channel.status, this.channel.responseStatus, this.responseText] = 
     result; |  294         [this.channel.status, this.channel.responseStatus, this.responseText] = 
     result; | 
|  294         this.status = this.channel.responseStatus; |  295         this.status = this.channel.responseStatus; | 
|  295  |  296  | 
|  296         let eventName = (this.channel.status == Cr.NS_OK ? "load" : "error"); |  297         let eventName = (this.channel.status == Cr.NS_OK ? "load" : "error"); | 
|  297         let event = {type: eventName}; |  298         let event = {type: eventName}; | 
|  298         for (let handler of this["_" + eventName + "Handlers"]) |  299         for (let handler of this["_" + eventName + "Handlers"]) | 
|  299           handler.call(this, event); |  300           handler.call(this, event); | 
|  300       })); |  301       })); | 
|  301     }, |  302     }, | 
|  302  |  303  | 
|  303     overrideMimeType: function(mime) |  304     overrideMimeType(mime) | 
|  304     { |  305     { | 
|  305     }, |  306     }, | 
|  306  |  307  | 
|  307     channel: |  308     channel: | 
|  308     { |  309     { | 
|  309       status: -1, |  310       status: -1, | 
|  310       responseStatus: 0, |  311       responseStatus: 0, | 
|  311       loadFlags: 0, |  312       loadFlags: 0, | 
|  312       INHIBIT_CACHING: 0, |  313       INHIBIT_CACHING: 0, | 
|  313       VALIDATE_ALWAYS: 0, |  314       VALIDATE_ALWAYS: 0, | 
|  314       QueryInterface: () => this |  315       QueryInterface: () => this | 
|  315     } |  316     } | 
|  316   }; |  317   }; | 
|  317  |  318  | 
|  318   XMLHttpRequest.requestHandlers = {}; |  319   XMLHttpRequest.requestHandlers = {}; | 
|  319   this.registerHandler = (path, handler) => |  320   this.registerHandler = (requestPath, handler) => | 
|  320   { |  321   { | 
|  321     XMLHttpRequest.requestHandlers[path] = handler; |  322     XMLHttpRequest.requestHandlers[requestPath] = handler; | 
|  322   }; |  323   }; | 
|  323  |  324  | 
|  324   function waitForRequests() |  325   function waitForRequests() | 
|  325   { |  326   { | 
|  326     if (requests.length) |  327     if (requests.length) | 
|  327     { |  328     { | 
|  328       let result = Promise.all(requests); |  329       let result = Promise.all(requests); | 
|  329       requests = []; |  330       requests = []; | 
|  330       return result.catch(e => |  331       return result.catch(e => | 
|  331       { |  332       { | 
|  332         console.error(e); |  333         console.error(e); | 
|  333       }).then(() => waitForRequests()); |  334       }).then(() => waitForRequests()); | 
|  334     } |  335     } | 
|  335     else |  336     return Promise.resolve(); | 
|  336       return Promise.resolve(); |  | 
|  337   } |  337   } | 
|  338  |  338  | 
|  339   function runScheduledTasks(maxMillis) |  339   function runScheduledTasks(maxMillis) | 
|  340   { |  340   { | 
|  341     let endTime = currentTime + maxMillis; |  341     let endTime = currentTime + maxMillis; | 
|  342     if (fakeTimer.nextExecution < 0 || fakeTimer.nextExecution > endTime) |  342     if (fakeTimer.nextExecution < 0 || fakeTimer.nextExecution > endTime) | 
|  343     { |  343     { | 
|  344       currentTime = endTime; |  344       currentTime = endTime; | 
|  345       return Promise.resolve(); |  345       return Promise.resolve(); | 
|  346     } |  346     } | 
|  347     else |  347     fakeTimer.trigger(); | 
|  348     { |  348     return waitForRequests().then(() => runScheduledTasks(endTime - currentTime)
     ); | 
|  349       fakeTimer.trigger(); |  | 
|  350       return waitForRequests().then(() => runScheduledTasks(endTime - currentTim
     e)); |  | 
|  351     } |  | 
|  352  |  | 
|  353     currentTime = endTime; |  | 
|  354   } |  349   } | 
|  355  |  350  | 
|  356   this.runScheduledTasks = (maxHours, initial, skip) => |  351   this.runScheduledTasks = (maxHours, initial, skip) => | 
|  357   { |  352   { | 
|  358     if (typeof maxHours != "number") |  353     if (typeof maxHours != "number") | 
|  359       throw new Error("Numerical parameter expected"); |  354       throw new Error("Numerical parameter expected"); | 
|  360     if (typeof initial != "number") |  355     if (typeof initial != "number") | 
|  361       initial = 0; |  356       initial = 0; | 
|  362     if (typeof skip != "number") |  357     if (typeof skip != "number") | 
|  363       skip = 0; |  358       skip = 0; | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
|  392         createInstance: () => fakeTimer |  387         createInstance: () => fakeTimer | 
|  393       } |  388       } | 
|  394     }, |  389     }, | 
|  395     Ci: { |  390     Ci: { | 
|  396       nsITimer: |  391       nsITimer: | 
|  397       { |  392       { | 
|  398         TYPE_ONE_SHOT: 0, |  393         TYPE_ONE_SHOT: 0, | 
|  399         TYPE_REPEATING_SLACK: 1, |  394         TYPE_REPEATING_SLACK: 1, | 
|  400         TYPE_REPEATING_PRECISE: 2 |  395         TYPE_REPEATING_PRECISE: 2 | 
|  401       }, |  396       }, | 
|  402       nsIHttpChannel: () => null, |  397       nsIHttpChannel: () => null | 
|  403     }, |  398     }, | 
|  404     Cr, |  399     Cr, | 
|  405     XMLHttpRequest, |  400     XMLHttpRequest, | 
|  406     Date: { |  401     Date: { | 
|  407       now: () => currentTime |  402       now: () => currentTime | 
|  408     } |  403     } | 
|  409   }; |  404   }; | 
|  410 }; |  405 }; | 
|  411  |  406  | 
 |  407 console.warn = console.log; | 
 |  408  | 
|  412 exports.setupRandomResult = function() |  409 exports.setupRandomResult = function() | 
|  413 { |  410 { | 
|  414   let randomResult = 0.5; |  411   let randomResult = 0.5; | 
|  415   Object.defineProperty(this, "randomResult", { |  412   Object.defineProperty(this, "randomResult", { | 
|  416     get: () => randomResult, |  413     get: () => randomResult, | 
|  417     set: value => randomResult = value |  414     set: value => randomResult = value | 
|  418   }); |  415   }); | 
|  419  |  416  | 
|  420   return { |  417   return { | 
|  421     Math: { |  418     Math: { | 
|  422       random: () => randomResult, |  419       random: () => randomResult, | 
|  423       min: Math.min, |  420       min: Math.min, | 
|  424       max: Math.max, |  421       max: Math.max, | 
|  425       round: Math.round |  422       round: Math.round | 
|  426     } |  423     } | 
|  427   }; |  424   }; | 
|  428 }; |  425 }; | 
|  429  |  426  | 
|  430 exports.unexpectedError = function(error) |  427 exports.unexpectedError = function(error) | 
|  431 { |  428 { | 
|  432   console.error(error); |  429   console.error(error); | 
|  433   this.ok(false, "Unexpected error: " + error); |  430   this.ok(false, "Unexpected error: " + error); | 
|  434 }; |  431 }; | 
| OLD | NEW |