<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>test/call-load-test.js</filename>
    </added>
    <added>
      <filename>test/envjs-prototype.js</filename>
    </added>
    <added>
      <filename>test/rhino-call-load-test.js</filename>
    </added>
    <added>
      <filename>test/rhino-prototype.js</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -94,4 +94,4 @@ load(&quot;build/runtest/env.js&quot;);
     
 })(Envjs);
 
-Envjs.wait(0);
\ No newline at end of file
+Envjs.wait();
\ No newline at end of file</diff>
      <filename>bin/jquery-1.3.2-test.js</filename>
    </modified>
    <modified>
      <diff>@@ -172,18 +172,26 @@
         &lt;arg value=&quot;test/test-with-envs-jar.js&quot;/&gt;
         &lt;jvmarg value=&quot;-Dfile.encoding=utf-8&quot;/&gt;
       &lt;/java&gt;
+      &lt;java fork=&quot;true&quot; jar=&quot;${DIST_DIR}/env-js.jar&quot; failonerror=&quot;true&quot;&gt;
+        &lt;arg value=&quot;test/envjs-call-load-test.js&quot;/&gt;
+        &lt;jvmarg value=&quot;-Dfile.encoding=utf-8&quot;/&gt;
+      &lt;/java&gt;
+      &lt;java fork=&quot;true&quot; jar=&quot;${DIST_DIR}/env-js.jar&quot; failonerror=&quot;true&quot;&gt;
+        &lt;arg value=&quot;test/envjs-prototype.js&quot;/&gt;
+        &lt;jvmarg value=&quot;-Dfile.encoding=utf-8&quot;/&gt;
+      &lt;/java&gt;
       &lt;java fork=&quot;true&quot; jar=&quot;${RHINO_JAR}&quot; failonerror=&quot;true&quot;&gt;
         &lt;arg value=&quot;test/test-with-rhino-jar.js&quot;/&gt;
         &lt;jvmarg value=&quot;-Dfile.encoding=utf-8&quot;/&gt;
       &lt;/java&gt;
       &lt;java fork=&quot;true&quot; jar=&quot;${RHINO_JAR}&quot; failonerror=&quot;true&quot;&gt;
-        &lt;arg value=&quot;test/envjs-call-load-test.js&quot;/&gt;
+        &lt;arg value=&quot;test/rhino-call-load-test.js&quot;/&gt;
         &lt;jvmarg value=&quot;-Dfile.encoding=utf-8&quot;/&gt;
       &lt;/java&gt;
       &lt;java fork=&quot;true&quot; jar=&quot;${RHINO_JAR}&quot; failonerror=&quot;true&quot;&gt;
-        &lt;arg value=&quot;test/prototype.js&quot;/&gt;
+        &lt;arg value=&quot;test/rhino-prototype.js&quot;/&gt;
         &lt;jvmarg value=&quot;-Dfile.encoding=utf-8&quot;/&gt;
       &lt;/java&gt;
     &lt;/target&gt;
     
-    &lt;/project&gt;
+&lt;/project&gt;</diff>
      <filename>build.xml</filename>
    </modified>
    <modified>
      <diff></diff>
      <filename>dist/env-js.jar</filename>
    </modified>
    <modified>
      <diff>@@ -8275,7 +8275,7 @@ $w.__defineGetter__(&quot;location&quot;, function(url){
 				this.search + this.hash;
 		},
 		get protocol(){
-			return protocol.exec(this.href)[0];
+			return this.href &amp;&amp; protocol.exec(this.href)[0];
 		},
 		set protocol(_protocol){
 			$w.location = _protocol + this.host + this.pathname + 
@@ -8411,49 +8411,177 @@ $w.__defineGetter__(&quot;navigator&quot;, function(){
 /*
 *	timer.js
 */
-	
 
 $debug(&quot;Initializing Window Timer.&quot;);
 
 //private
-var $timers = [];
+var $timers = $env.timers = $env.timers || [];
+var $event_loop_running = false;
+$timers.lock = $env.sync(function(fn){fn();});
+
+var $timer = function(fn, interval){
+  this.fn = fn;
+  this.interval = interval;
+  this.at = Date.now() + interval;
+  this.running = false; // allows for calling wait() from callbacks
+};
+  
+$timer.prototype.start = function(){};
+$timer.prototype.stop = function(){};
+
+var convert_time = function(time) {
+  time = time*1;
+  if ( isNaN(time) || time &lt; 0 ) {
+    time = 0;
+  }
+  if ( $event_loop_running &amp;&amp; time &lt; 4 ) {
+    time = 4;
+  }
+  return time;
+}
 
 window.setTimeout = function(fn, time){
   var num;
-  return num = window.setInterval(function(){
-    fn();
-    window.clearInterval(num);
-  }, time);
+  time = convert_time(time);
+  $timers.lock(function(){
+    num = $timers.length+1;
+    var tfn;
+    if (typeof fn == 'string') {
+      tfn = function() {
+        try {
+          eval(fn);
+        } catch (e) {
+          $env.error(e);
+        } finally {
+          window.clearInterval(num);
+        }
+      };
+    } else {
+      tfn = function() {
+        try {
+          fn();
+        } catch (e) {
+          $env.error(e);
+        } finally {
+          window.clearInterval(num);
+        }
+      };
+    }
+    $debug(&quot;Creating timer number &quot;+num);
+    $timers[num] = new $timer(tfn, time);
+    $timers[num].start();
+  });
+  return num;
 };
 
 window.setInterval = function(fn, time){
-	var num = $timers.length;
-	
-    if (typeof fn == 'string') {
-        var fnstr = fn; 
-        fn = function() { 
-            eval(fnstr); 
-        }; 
-    }
-	if(time===0){
-	    fn();
-	}else{
-	    //$debug(&quot;Creating timer number &quot;+num);
-    	$timers[num] = new $env.timer(fn, time);
-    	$timers[num].start();
-	}
-	return num;
+  time = convert_time(time);
+  if ( time &lt; 10 ) {
+    time = 10;
+  }
+  if (typeof fn == 'string') {
+    var fnstr = fn; 
+    fn = function() { 
+      eval(fnstr);
+    }; 
+  }
+  var num;
+  $timers.lock(function(){
+    num = $timers.length+1;
+    //$debug(&quot;Creating timer number &quot;+num);
+    $timers[num] = new $timer(fn, time);
+    $timers[num].start();
+  });
+  return num;
 };
 
 window.clearInterval = window.clearTimeout = function(num){
-	//$log(&quot;clearing interval &quot;+num);
-	if ( $timers[num] ) {
-	    
-		$timers[num].stop();
-		delete $timers[num];
-	}
+  //$log(&quot;clearing interval &quot;+num);
+  $timers.lock(function(){
+    if ( $timers[num] ) {
+      $timers[num].stop();
+      delete $timers[num];
+    }
+  });
 };	
-	/*
+
+// wait === null/undefined: execute any timers as they fire, waiting until there are none left
+// wait(n) (n &gt; 0): execute any timers as they fire until there are none left waiting at least n ms
+// but no more, even if there are future events/current threads
+// wait(0): execute any immediately runnable timers and return
+
+// FIX: make a priority queue ...
+
+window.$wait = $env.wait = $env.wait || function(wait) {
+  var start = Date.now();
+  var old_loop_running = $event_loop_running;
+  $event_loop_running = true; 
+  if (wait !== 0 &amp;&amp; wait !== null &amp;&amp; wait !== undefined){
+    wait += Date.now();
+  }
+  for (;;) {
+    var earliest;
+    $timers.lock(function(){
+      earliest = undefined;
+      for(var i in $timers){
+        if( isNaN(i*0) ) {
+          continue;
+        }
+        var timer = $timers[i];
+        if( !timer.running &amp;&amp; ( !earliest || timer.at &lt; earliest.at) ) {
+          earliest = timer;
+        }
+      }
+    });
+    var sleep = earliest &amp;&amp; earliest.at - Date.now();
+    if ( earliest &amp;&amp; sleep &lt;= 0 ) {
+      var f = earliest.fn;
+      try {
+        earliest.running = true;
+        f();
+      } catch (e) {
+        $env.error(e);
+      } finally {
+        earliest.running = false;
+      }
+      var goal = earliest.at + earliest.interval;
+      var now = Date.now();
+      if ( goal &lt; now ) {
+        earliest.at = now;
+      } else {
+        earliest.at = goal;
+      }
+      continue;
+    }
+
+    // bunch of subtle cases here ...
+    if ( !earliest ) {
+      // no events in the queue (but maybe XHR will bring in events, so ...
+      if ( !wait || wait &lt; Date.now() ) {
+        // Loop ends if there are no events and a wait hasn't been requested or has expired
+        break;
+      }
+      // no events, but a wait requested: fall through to sleep
+    } else {
+      // there are events in the queue, but they aren't firable now
+      if ( wait === 0 || ( wait &gt; 0 &amp;&amp; wait &lt; Date.now () ) ) {
+        // loop ends even if there are events but the user specifcally asked not to wait too long
+        break;
+      }
+      // there are events and the user wants to wait: fall through to sleep
+    }
+
+    // Releated to ajax threads ... hopefully can go away ..
+    var interval =  $wait.interval || 100;
+    if ( !sleep || sleep &gt; interval ) {
+      sleep = interval;
+    }
+    java.lang.Thread.currentThread().sleep(sleep);
+  }
+  $event_loop_running = old_loop_running;
+};
+
+/*
 * event.js
 */
 // Window Events</diff>
      <filename>dist/env.js</filename>
    </modified>
    <modified>
      <diff>@@ -99,11 +99,12 @@ var Envjs = function(){
     
     //resolves location relative to base or window location
     $env.location = function(path, base){};
-    
-    //For Java the window.timer is created using the java.lang.Thread in combination
-    //with the java.lang.Runnable
-    $env.timer = function(fn, time){};	
-    
+  
+    $env.sync = function(fn){
+      var self = this;
+      return function(){ return fn.apply(self,arguments); }
+    }
+  
     $env.javaEnabled = false;	
     
     //Used in the XMLHttpRquest implementation to run a
@@ -307,6 +308,8 @@ var Envjs = function(){
         return e&amp;&amp;e.rhinoException?e.rhinoException.lineSource():&quot;(line ?)&quot;;
     };
     
+    $env.sync = sync;
+  
     //For Java the window.location object is a java.net.URL
     $env.location = function(path, base){
       var protocol = new RegExp('(^file\:|^http\:|^https\:)');
@@ -317,8 +320,8 @@ var Envjs = function(){
           return new java.net.URL(new java.net.URL(base), path).toString()+'';
         }else{
             //return an absolute url from a url relative to the window location
-            if(window.location.href.length &gt; 0){
                 base = window.location.href.substring(0, window.location.href.lastIndexOf('/'));
+            if(window.location.href.length &gt; 0){
                 return base + '/' + path;
             }else{
                 return new java.io.File(  path ).toURL().toString()+'';
@@ -326,41 +329,6 @@ var Envjs = function(){
         }
     };
     
-    var timers = [];
-
-    //For Java the window.timer is created using the java.lang.Thread in combination
-    //with the java.lang.Runnable
-    $env.timer = function(fn, time){
-       var running = true;
-        
-        var run = sync(function(){ //while happening only thing in this timer    
-    	    //$env.debug(&quot;running timed function&quot;);
-            fn();
-        });
-        var _this = this;
-        var thread = new java.lang.Thread(new java.lang.Runnable({
-            run: function(){
-                try {
-                    while (running){
-                        java.lang.Thread.currentThread().sleep(time);
-                        run.apply(_this);
-                    }
-                }catch(e){
-                    $env.debug(&quot;interuption running timed function&quot;);
-                    _this.stop();
-                    $env.onInterrupt();
-                };
-            }
-        }));
-        this.start = function(){ 
-            thread.start(); 
-        };
-        this.stop = sync(function(num){
-            running = false;
-            thread.interrupt();
-        })
-    };
-    
     //Since we're running in rhino I guess we can safely assume
     //java is 'enabled'.  I'm sure this requires more thought
     //than I've given it here
@@ -379,15 +347,10 @@ var Envjs = function(){
             fn();
         });
         
-        var async = (new java.lang.Thread(new java.lang.Runnable({
-            run: run
-        })));
-        
         try{
-            async.start();
+            spawn(run);
         }catch(e){
             $env.error(&quot;error while running async&quot;, e);
-            async.interrupt();
             $env.onInterrupt();
         }
     };
@@ -8932,7 +8895,7 @@ $w.__defineGetter__(&quot;location&quot;, function(url){
 				this.search + this.hash;
 		},
 		get protocol(){
-			return protocol.exec(this.href)[0];
+			return this.href &amp;&amp; protocol.exec(this.href)[0];
 		},
 		set protocol(_protocol){
 			$w.location = _protocol + this.host + this.pathname + 
@@ -9068,49 +9031,177 @@ $w.__defineGetter__(&quot;navigator&quot;, function(){
 /*
 *	timer.js
 */
-	
 
 $debug(&quot;Initializing Window Timer.&quot;);
 
 //private
-var $timers = [];
+var $timers = $env.timers = $env.timers || [];
+var $event_loop_running = false;
+$timers.lock = $env.sync(function(fn){fn();});
+
+var $timer = function(fn, interval){
+  this.fn = fn;
+  this.interval = interval;
+  this.at = Date.now() + interval;
+  this.running = false; // allows for calling wait() from callbacks
+};
+  
+$timer.prototype.start = function(){};
+$timer.prototype.stop = function(){};
+
+var convert_time = function(time) {
+  time = time*1;
+  if ( isNaN(time) || time &lt; 0 ) {
+    time = 0;
+  }
+  if ( $event_loop_running &amp;&amp; time &lt; 4 ) {
+    time = 4;
+  }
+  return time;
+}
 
 window.setTimeout = function(fn, time){
   var num;
-  return num = window.setInterval(function(){
-    fn();
-    window.clearInterval(num);
-  }, time);
+  time = convert_time(time);
+  $timers.lock(function(){
+    num = $timers.length+1;
+    var tfn;
+    if (typeof fn == 'string') {
+      tfn = function() {
+        try {
+          eval(fn);
+        } catch (e) {
+          $env.error(e);
+        } finally {
+          window.clearInterval(num);
+        }
+      };
+    } else {
+      tfn = function() {
+        try {
+          fn();
+        } catch (e) {
+          $env.error(e);
+        } finally {
+          window.clearInterval(num);
+        }
+      };
+    }
+    $debug(&quot;Creating timer number &quot;+num);
+    $timers[num] = new $timer(tfn, time);
+    $timers[num].start();
+  });
+  return num;
 };
 
 window.setInterval = function(fn, time){
-	var num = $timers.length;
-	
-    if (typeof fn == 'string') {
-        var fnstr = fn; 
-        fn = function() { 
-            eval(fnstr); 
-        }; 
-    }
-	if(time===0){
-	    fn();
-	}else{
-	    //$debug(&quot;Creating timer number &quot;+num);
-    	$timers[num] = new $env.timer(fn, time);
-    	$timers[num].start();
-	}
-	return num;
+  time = convert_time(time);
+  if ( time &lt; 10 ) {
+    time = 10;
+  }
+  if (typeof fn == 'string') {
+    var fnstr = fn; 
+    fn = function() { 
+      eval(fnstr);
+    }; 
+  }
+  var num;
+  $timers.lock(function(){
+    num = $timers.length+1;
+    //$debug(&quot;Creating timer number &quot;+num);
+    $timers[num] = new $timer(fn, time);
+    $timers[num].start();
+  });
+  return num;
 };
 
 window.clearInterval = window.clearTimeout = function(num){
-	//$log(&quot;clearing interval &quot;+num);
-	if ( $timers[num] ) {
-	    
-		$timers[num].stop();
-		delete $timers[num];
-	}
+  //$log(&quot;clearing interval &quot;+num);
+  $timers.lock(function(){
+    if ( $timers[num] ) {
+      $timers[num].stop();
+      delete $timers[num];
+    }
+  });
 };	
-	/*
+
+// wait === null/undefined: execute any timers as they fire, waiting until there are none left
+// wait(n) (n &gt; 0): execute any timers as they fire until there are none left waiting at least n ms
+// but no more, even if there are future events/current threads
+// wait(0): execute any immediately runnable timers and return
+
+// FIX: make a priority queue ...
+
+window.$wait = $env.wait = $env.wait || function(wait) {
+  var start = Date.now();
+  var old_loop_running = $event_loop_running;
+  $event_loop_running = true; 
+  if (wait !== 0 &amp;&amp; wait !== null &amp;&amp; wait !== undefined){
+    wait += Date.now();
+  }
+  for (;;) {
+    var earliest;
+    $timers.lock(function(){
+      earliest = undefined;
+      for(var i in $timers){
+        if( isNaN(i*0) ) {
+          continue;
+        }
+        var timer = $timers[i];
+        if( !timer.running &amp;&amp; ( !earliest || timer.at &lt; earliest.at) ) {
+          earliest = timer;
+        }
+      }
+    });
+    var sleep = earliest &amp;&amp; earliest.at - Date.now();
+    if ( earliest &amp;&amp; sleep &lt;= 0 ) {
+      var f = earliest.fn;
+      try {
+        earliest.running = true;
+        f();
+      } catch (e) {
+        $env.error(e);
+      } finally {
+        earliest.running = false;
+      }
+      var goal = earliest.at + earliest.interval;
+      var now = Date.now();
+      if ( goal &lt; now ) {
+        earliest.at = now;
+      } else {
+        earliest.at = goal;
+      }
+      continue;
+    }
+
+    // bunch of subtle cases here ...
+    if ( !earliest ) {
+      // no events in the queue (but maybe XHR will bring in events, so ...
+      if ( !wait || wait &lt; Date.now() ) {
+        // Loop ends if there are no events and a wait hasn't been requested or has expired
+        break;
+      }
+      // no events, but a wait requested: fall through to sleep
+    } else {
+      // there are events in the queue, but they aren't firable now
+      if ( wait === 0 || ( wait &gt; 0 &amp;&amp; wait &lt; Date.now () ) ) {
+        // loop ends even if there are events but the user specifcally asked not to wait too long
+        break;
+      }
+      // there are events and the user wants to wait: fall through to sleep
+    }
+
+    // Releated to ajax threads ... hopefully can go away ..
+    var interval =  $wait.interval || 100;
+    if ( !sleep || sleep &gt; interval ) {
+      sleep = interval;
+    }
+    java.lang.Thread.currentThread().sleep(sleep);
+  }
+  $event_loop_running = old_loop_running;
+};
+
+/*
 * event.js
 */
 // Window Events</diff>
      <filename>dist/env.rhino.js</filename>
    </modified>
    <modified>
      <diff>@@ -6,37 +6,56 @@ $debug(&quot;Initializing Window Timer.&quot;);
 
 //private
 var $timers = $env.timers = $env.timers || [];
-var $lock_timers = function(fn){
-  $env.sync.call($timers,fn)();
-};
+var $event_loop_running = false;
+$timers.lock = $env.sync(function(fn){fn();});
 
 var $timer = function(fn, interval){
-  if ( (typeof interval) != &quot;number&quot; ) {
-    throw &quot;bad argument to timer&quot;;
-  }
   this.fn = fn;
   this.interval = interval;
   this.at = Date.now() + interval;
+  this.running = false; // allows for calling wait() from callbacks
 };
   
 $timer.prototype.start = function(){};
 $timer.prototype.stop = function(){};
 
+var convert_time = function(time) {
+  time = time*1;
+  if ( isNaN(time) || time &lt; 0 ) {
+    time = 0;
+  }
+  if ( $event_loop_running &amp;&amp; time &lt; 4 ) {
+    time = 4;
+  }
+  return time;
+}
+
 window.setTimeout = function(fn, time){
   var num;
-  $lock_timers(function(){
+  time = convert_time(time);
+  $timers.lock(function(){
     num = $timers.length+1;
     var tfn;
     if (typeof fn == 'string') {
       tfn = function() {
-        eval(fn);
-        window.clearInterval(num);
+        try {
+          eval(fn);
+        } catch (e) {
+          $env.error(e);
+        } finally {
+          window.clearInterval(num);
+        }
       };
     } else {
       tfn = function() {
-        fn();
-        window.clearInterval(num);
-      }
+        try {
+          fn();
+        } catch (e) {
+          $env.error(e);
+        } finally {
+          window.clearInterval(num);
+        }
+      };
     }
     $debug(&quot;Creating timer number &quot;+num);
     $timers[num] = new $timer(tfn, time);
@@ -46,14 +65,18 @@ window.setTimeout = function(fn, time){
 };
 
 window.setInterval = function(fn, time){
+  time = convert_time(time);
+  if ( time &lt; 10 ) {
+    time = 10;
+  }
   if (typeof fn == 'string') {
     var fnstr = fn; 
     fn = function() { 
-      eval(fnstr); 
+      eval(fnstr);
     }; 
   }
   var num;
-  $lock_timers(function(){
+  $timers.lock(function(){
     num = $timers.length+1;
     //$debug(&quot;Creating timer number &quot;+num);
     $timers[num] = new $timer(fn, time);
@@ -64,7 +87,7 @@ window.setInterval = function(fn, time){
 
 window.clearInterval = window.clearTimeout = function(num){
   //$log(&quot;clearing interval &quot;+num);
-  $lock_timers(function(){
+  $timers.lock(function(){
     if ( $timers[num] ) {
       $timers[num].stop();
       delete $timers[num];
@@ -72,26 +95,30 @@ window.clearInterval = window.clearTimeout = function(num){
   });
 };	
 
-// wait === null: execute any immediately runnable timers and return
-// wait(n) (n &gt; 0): execute any timers as they fire but no longer than n ms
-// wait(0): execute any timers as they fire, waiting until there are none left
+// wait === null/undefined: execute any timers as they fire, waiting until there are none left
+// wait(n) (n &gt; 0): execute any timers as they fire until there are none left waiting at least n ms
+// but no more, even if there are future events/current threads
+// wait(0): execute any immediately runnable timers and return
 
 // FIX: make a priority queue ...
 
 window.$wait = $env.wait = $env.wait || function(wait) {
+  var start = Date.now();
+  var old_loop_running = $event_loop_running;
+  $event_loop_running = true; 
   if (wait !== 0 &amp;&amp; wait !== null &amp;&amp; wait !== undefined){
     wait += Date.now();
   }
   for (;;) {
     var earliest;
-    $lock_timers(function(){
+    $timers.lock(function(){
       earliest = undefined;
       for(var i in $timers){
-        if( !$timers.hasOwnProperty(i) ) {
+        if( isNaN(i*0) ) {
           continue;
         }
         var timer = $timers[i];
-        if(!earliest || timer.at &lt; earliest.at) {
+        if( !timer.running &amp;&amp; ( !earliest || timer.at &lt; earliest.at) ) {
           earliest = timer;
         }
       }
@@ -99,15 +126,48 @@ window.$wait = $env.wait = $env.wait || function(wait) {
     var sleep = earliest &amp;&amp; earliest.at - Date.now();
     if ( earliest &amp;&amp; sleep &lt;= 0 ) {
       var f = earliest.fn;
-      f();
-      earliest.at = Date.now() + earliest.interval;
+      try {
+        earliest.running = true;
+        f();
+      } catch (e) {
+        $env.error(e);
+      } finally {
+        earliest.running = false;
+      }
+      var goal = earliest.at + earliest.interval;
+      var now = Date.now();
+      if ( goal &lt; now ) {
+        earliest.at = now;
+      } else {
+        earliest.at = goal;
+      }
       continue;
     }
-    if ( !earliest || ( wait !== 0 ) &amp;&amp; ( !wait || ( Date.now() + sleep &gt; wait ) ) ) {
-      break;
+
+    // bunch of subtle cases here ...
+    if ( !earliest ) {
+      // no events in the queue (but maybe XHR will bring in events, so ...
+      if ( !wait || wait &lt; Date.now() ) {
+        // Loop ends if there are no events and a wait hasn't been requested or has expired
+        break;
+      }
+      // no events, but a wait requested: fall through to sleep
+    } else {
+      // there are events in the queue, but they aren't firable now
+      if ( wait === 0 || ( wait &gt; 0 &amp;&amp; wait &lt; Date.now () ) ) {
+        // loop ends even if there are events but the user specifcally asked not to wait too long
+        break;
+      }
+      // there are events and the user wants to wait: fall through to sleep
     }
-    if (sleep) {
-      java.lang.Thread.currentThread().sleep(sleep);
+
+    // Releated to ajax threads ... hopefully can go away ..
+    var interval =  $wait.interval || 100;
+    if ( !sleep || sleep &gt; interval ) {
+      sleep = interval;
     }
+    java.lang.Thread.currentThread().sleep(sleep);
   }
+  $event_loop_running = old_loop_running;
 };
+</diff>
      <filename>src/window/timer.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,17 +1,5 @@
+whichJarFile = &quot;envjs&quot;
+multiwindow = true;
+whichInterpreter = whichJarFile + &quot; interpreter jar&quot;;
 load(&quot;dist/env.rhino.js&quot;);
-load(&quot;test/qunit.js&quot;);
-Envjs(&quot;test/index.html&quot;, {});
-
-test(&quot;'index.html' loaded correctly via 'Envjs()' call&quot;, function(){
-    expect(1);
-    try{ ok(document.getElementById('body').id == &quot;body&quot;,
-        &quot;'index.html' page content available&quot;);
-    }catch(e){print(e);}
-});
-
-test(&quot;window.location= following Envjs() initialization flagged as error&quot;,
-     function(){
-    expect(0);
-});
-
-Envjs.wait(0);
\ No newline at end of file
+load(&quot;test/call-load-test.js&quot;);</diff>
      <filename>test/envjs-call-load-test.js</filename>
    </modified>
    <modified>
      <diff>@@ -27,4 +27,4 @@ window.addEventListener(&quot;load&quot;,function(){
 
 window.location = &quot;test/index.html&quot;;
 
-Envjs.wait(0);
\ No newline at end of file
+Envjs.wait();
\ No newline at end of file</diff>
      <filename>test/primaryTests.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,3 @@
-whichJarFile = &quot;rhino&quot;
-whichInterpreter = whichJarFile + &quot; interpreter jar&quot;;
-multiwindow = false;
-load(&quot;dist/env.rhino.js&quot;);
 load(&quot;test/qunit.js&quot;);
 
 window.addEventListener(&quot;load&quot;,function(){
@@ -16,4 +12,4 @@ window.addEventListener(&quot;load&quot;,function(){
 
 window.location = &quot;test/index.html&quot;;
 
-Envjs.wait(0);
\ No newline at end of file
+Envjs.wait();
\ No newline at end of file</diff>
      <filename>test/prototype.js</filename>
    </modified>
    <modified>
      <diff>@@ -46,6 +46,69 @@ test(&quot;clearTimeout cancels execution of setTimeout callback&quot;, function() {
     stop();
 });
 
+test(&quot;setTimeout callbacks that throw run once&quot;, function() {
+    expect(2);
+    stop();
+    var called = 0;
+    var id = setTimeout(function(){
+        ok( called == 0, &quot;timeout called once&quot; );
+        called++;
+        throw &quot;an expected error&quot;;
+    }, 10);
+    setTimeout(function(){
+        ok( called == 1, &quot;called timeout once double checked&quot; );
+        clearTimeout(id);
+        start();
+    },100);
+});
+
+test(&quot;setInterval callbacks that are delayed execute immediately&quot;, function() {
+    expect(3);
+    stop();
+    var iteration = 0;
+    var last = Date.now();
+    var id = setInterval(function(){
+        var now = Date.now();
+        var since_last = now - last;
+        switch(iteration) {
+          case 0:
+            ok( since_last &gt; 60 &amp;&amp; since_last &lt; 140, &quot;first interval was correct&quot; );
+            while( (Date.now() - last ) &lt; 400 ) {}
+            break;
+          case 1:
+            ok( since_last &lt; 40, &quot;second interval was correct&quot; );
+            break;
+        default:
+            ok(  since_last &gt; 60 &amp;&amp; since_last &lt; 140, &quot;third interval was correct&quot; );
+            clearInterval(id);
+            start();
+        }
+        last = Date.now();
+        iteration++;
+    }, 100);
+});
+
+test(&quot;wait(n) waits at least n and then continues with nothing in the future&quot;, function() {
+    stop();
+    expect(1);
+    var now = Date.now();
+    Envjs.wait(1000);
+    ok( Date.now() - now &gt; 1000, &quot;wait waited long enough&quot; );
+    start();
+});
+
+test(&quot;wait(n) waits at least n and then continues with stuff in the future&quot;, function() {
+    stop();
+    expect(2);
+    var now = Date.now();
+    var t = setTimeout(function(){
+    },2000);
+    Envjs.wait(1000);
+    ok( Date.now() - now &gt; 1000, &quot;wait waited long enough&quot; );
+    ok( Date.now() - now &lt; 2000, &quot;wait didn't wait too long&quot; );
+    start();
+});
+
 // Local Variables:
 // espresso-indent-level:4
 // c-basic-offset:4</diff>
      <filename>test/unit/timer.js</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>7c283f98d650bcc8dde2ef9f2b1a7380caa0372f</id>
    </parent>
    <parent>
      <id>5d1943b240a34e83102ebf0fc90345b9c1dce3fb</id>
    </parent>
  </parents>
  <author>
    <name>Steven Parkes</name>
    <email>smparkes@smparkes.net</email>
  </author>
  <url>http://github.com/thatcher/env-js/commit/674673e649a2b1d8218858b340628b7ab588e066</url>
  <id>674673e649a2b1d8218858b340628b7ab588e066</id>
  <committed-date>2009-10-28T18:34:31-07:00</committed-date>
  <authored-date>2009-10-28T18:34:31-07:00</authored-date>
  <message>merge timer</message>
  <tree>238dad6e0243cb276458c0a467943689e8db1dc0</tree>
  <committer>
    <name>Steven Parkes</name>
    <email>smparkes@smparkes.net</email>
  </committer>
</commit>
