From 190208b620276837b06d7b0865f67a53fda8243a Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Fri, 17 Jun 2016 14:36:36 -0400
Subject: [PATCH 01/27] Clean up yield-timers: support multiple, move logic to
 Threads.

---
 src/engine/execute.js   | 14 +-------------
 src/engine/sequencer.js |  8 ++++----
 src/engine/thread.js    | 31 +++++++++++++++++++++++++++++--
 src/util/yieldtimers.js | 19 -------------------
 4 files changed, 34 insertions(+), 38 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index 0d1dbc3cc..6c58cd156 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -1,5 +1,3 @@
-var YieldTimers = require('../util/yieldtimers.js');
-
 /**
  * If set, block calls, args, and return values will be logged to the console.
  * @const {boolean}
@@ -13,11 +11,6 @@ var execute = function (sequencer, thread) {
     var currentBlockId = thread.peekStack();
     var currentStackFrame = thread.peekStackFrame();
 
-    // Save the yield timer ID, in case a primitive makes a new one
-    // @todo hack - perhaps patch this to allow more than one timer per
-    // primitive, for example...
-    var oldYieldTimerId = YieldTimers.timerId;
-
     var opcode = runtime.blocks.getOpcode(currentBlockId);
 
     // Generate values for arguments (inputs).
@@ -64,17 +57,12 @@ var execute = function (sequencer, thread) {
         done: function() {
             sequencer.proceedThread(thread);
         },
-        timeout: YieldTimers.timeout,
+        timeout: thread.addTimeout.bind(thread),
         stackFrame: currentStackFrame,
         startSubstack: function (substackNum) {
             sequencer.stepToSubstack(thread, substackNum);
         }
     });
-    // Update if the thread has set a yield timer ID
-    // @todo hack
-    if (YieldTimers.timerId > oldYieldTimerId) {
-        thread.yieldTimerId = YieldTimers.timerId;
-    }
     if (DEBUG_BLOCK_CALLS) {
         console.log('ending stack frame: ', currentStackFrame);
         console.log('returned: ', primitiveReturnValue);
diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js
index deaa15266..1541d1c6f 100644
--- a/src/engine/sequencer.js
+++ b/src/engine/sequencer.js
@@ -53,10 +53,10 @@ Sequencer.prototype.stepThreads = function (threads) {
                 // Normal-mode thread: step.
                 this.startThread(activeThread);
             } else if (activeThread.status === Thread.STATUS_YIELD) {
-                // Yield-mode thread: check if the time has passed.
-                if (!YieldTimers.resolve(activeThread.yieldTimerId)) {
-                    // Thread is still yielding
-                    // if YieldTimers.resolve returns false.
+                // Yield-mode thread: resolve timers.
+                activeThread.resolveTimeouts();
+                if (activeThread.status === Thread.STATUS_YIELD) {
+                    // Still yielding.
                     numYieldingThreads++;
                 }
             } else if (activeThread.status === Thread.STATUS_DONE) {
diff --git a/src/engine/thread.js b/src/engine/thread.js
index c98efab48..bd991db27 100644
--- a/src/engine/thread.js
+++ b/src/engine/thread.js
@@ -1,3 +1,5 @@
+var YieldTimers = require('../util/yieldtimers.js');
+
 /**
  * A thread is a running stack context and all the metadata needed.
  * @param {?string} firstBlock First block to execute in the thread.
@@ -30,10 +32,10 @@ function Thread (firstBlock) {
     this.status = 0; /* Thread.STATUS_RUNNING */
 
     /**
-     * Yield timer ID (for checking when the thread should unyield).
+     * Execution-synced timeouts.
      * @type {number}
      */
-    this.yieldTimerId = -1;
+    this.timeoutIds = [];
 }
 
 /**
@@ -104,4 +106,29 @@ Thread.prototype.yield = function () {
     this.status = Thread.STATUS_YIELD;
 };
 
+/**
+ * Add an execution-synced timeouts for this thread.
+ * See also: util/yieldtimers.js:timeout
+ * @param {!Function} callback To be called when the timer is done.
+ * @param {number} timeDelta Time to wait, in ms.
+ */
+Thread.prototype.addTimeout = function (callback, timeDelta) {
+    var timeoutId = YieldTimers.timeout(callback, timeDelta);
+    this.timeoutIds.push(timeoutId);
+};
+
+/**
+ * Attempt to resolve all execution-synced timeouts on this thread.
+ */
+Thread.prototype.resolveTimeouts = function () {
+    var newTimeouts = [];
+    for (var i = 0; i < this.timeoutIds.length; i++) {
+        var resolved = YieldTimers.resolve(this.timeoutIds[i]);
+        if (!resolved) {
+            newTimeouts.push(this.timeoutIds[i]);
+        }
+    }
+    this.timeoutIds = newTimeouts;
+};
+
 module.exports = Thread;
diff --git a/src/util/yieldtimers.js b/src/util/yieldtimers.js
index 45e244eaf..84c6d3259 100644
--- a/src/util/yieldtimers.js
+++ b/src/util/yieldtimers.js
@@ -68,23 +68,4 @@ YieldTimers.resolve = function (id) {
     return true;
 };
 
-/**
- * Reject a timer so the callback never executes.
- * @param {number} id Timer ID to reject.
- */
-YieldTimers.reject = function (id) {
-    if (YieldTimers.timers[id]) {
-        delete YieldTimers.timers[id];
-    }
-};
-
-/**
- * Reject all timers currently stored.
- * Especially useful for a Scratch "stop."
- */
-YieldTimers.rejectAll = function () {
-    YieldTimers.timers = {};
-    YieldTimers.timerId = 0;
-};
-
 module.exports = YieldTimers;

From 34659c9b7b2aa4a66664591460a52712e1ea96c5 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Fri, 17 Jun 2016 15:08:54 -0400
Subject: [PATCH 02/27] Allow console timers

---
 .eslintrc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.eslintrc b/.eslintrc
index bcd88942f..fcb231522 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -8,7 +8,7 @@
         "max-len": [2, 80, 4],
         "semi": [2, "always"],
         "strict": [2, "never"],
-        "no-console": [2, {"allow": ["log", "warn", "error", "groupCollapsed", "groupEnd"]}],
+        "no-console": [2, {"allow": ["log", "warn", "error", "groupCollapsed", "groupEnd", "time", "timeEnd"]}],
         "valid-jsdoc": ["error", {"requireReturn": false}]
     },
     "env": {

From 97f7571c6faa5454579b9776b6e51b8cfbcc9cf2 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Fri, 17 Jun 2016 15:10:12 -0400
Subject: [PATCH 03/27] Prototype implementation of yielding reporters

---
 src/engine/execute.js   | 53 ++++++++++++++++++++++++++++++++++-------
 src/engine/sequencer.js |  3 +--
 src/engine/thread.js    | 17 ++++++++++++-
 3 files changed, 61 insertions(+), 12 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index 6c58cd156..add9c9909 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -1,10 +1,19 @@
+var Thread = require('./thread');
+
 /**
  * If set, block calls, args, and return values will be logged to the console.
  * @const {boolean}
  */
 var DEBUG_BLOCK_CALLS = true;
 
-var execute = function (sequencer, thread) {
+/**
+ * Execute a block.
+ * @param {!Sequencer} sequencer Which sequencer is executing.
+ * @param {!Thread} thread Thread which to read and execute.
+ * @param {string=} opt_waitingInputName If evaluating an input, its name.
+ * @return {?Any} Reported value, if available immediately.
+ */
+var execute = function (sequencer, thread, opt_waitingInputName) {
     var runtime = sequencer.runtime;
 
     // Current block to execute is the one on the top of the stack.
@@ -27,11 +36,29 @@ var execute = function (sequencer, thread) {
     for (var inputName in inputs) {
         var input = inputs[inputName];
         var inputBlockId = input.block;
-        // Push to the stack to evaluate this input.
-        thread.pushStack(inputBlockId);
-        var result = execute(sequencer, thread);
-        thread.popStack();
-        argValues[input.name] = result;
+        // Is there a value for this input waiting in the stack frame?
+        if (currentStackFrame.reported &&
+            currentStackFrame.reported[inputName]) {
+            // Use that value.
+            argValues[inputName] = currentStackFrame.reported[inputName];
+        } else {
+            // Otherwise, we need to evaluate the block.
+            // Push to the stack to evaluate this input.
+            thread.pushStack(inputBlockId);
+            if (DEBUG_BLOCK_CALLS) {
+                console.time('Yielding reporter evaluation');
+            }
+            var result = execute(sequencer, thread, inputName);
+            // Did the reporter yield?
+            if (thread.status === Thread.STATUS_YIELD) {
+                // Reporter yielded; don't pop stack and wait for it to unyield.
+                // The value will be populated once the reporter unyields,
+                // and passed up to the currentStackFrame on next execution.
+                return;
+            }
+            thread.popStack();
+            argValues[inputName] = result;
+        }
     }
 
     if (!opcode) {
@@ -51,21 +78,29 @@ var execute = function (sequencer, thread) {
         console.log('and stack frame: ', currentStackFrame);
     }
     var primitiveReturnValue = null;
-    // @todo deal with the return value
     primitiveReturnValue = blockFunction(argValues, {
         yield: thread.yield.bind(thread),
         done: function() {
             sequencer.proceedThread(thread);
         },
+        report: function(reportedValue) {
+            thread.pushReportedValue(opt_waitingInputName, reportedValue);
+            if (DEBUG_BLOCK_CALLS) {
+                console.log('Reported: ', reportedValue,
+                    ' for ', opt_waitingInputName);
+                console.timeEnd('Yielding reporter evaluation');
+            }
+            sequencer.proceedThread(thread);
+        },
         timeout: thread.addTimeout.bind(thread),
-        stackFrame: currentStackFrame,
+        stackFrame: currentStackFrame.executionContext,
         startSubstack: function (substackNum) {
             sequencer.stepToSubstack(thread, substackNum);
         }
     });
     if (DEBUG_BLOCK_CALLS) {
         console.log('ending stack frame: ', currentStackFrame);
-        console.log('returned: ', primitiveReturnValue);
+        console.log('returned immediately: ', primitiveReturnValue);
         console.groupEnd();
     }
     return primitiveReturnValue;
diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js
index 1541d1c6f..e82d4054c 100644
--- a/src/engine/sequencer.js
+++ b/src/engine/sequencer.js
@@ -1,6 +1,5 @@
 var Timer = require('../util/timer');
 var Thread = require('./thread');
-var YieldTimers = require('../util/yieldtimers.js');
 var execute = require('./execute.js');
 
 function Sequencer (runtime) {
@@ -101,7 +100,7 @@ Sequencer.prototype.startThread = function (thread) {
     // move to done.
     if (thread.status === Thread.STATUS_RUNNING &&
         thread.peekStack() === currentBlockId) {
-        this.proceedThread(thread, currentBlockId);
+        this.proceedThread(thread);
     }
 };
 
diff --git a/src/engine/thread.js b/src/engine/thread.js
index bd991db27..65b251648 100644
--- a/src/engine/thread.js
+++ b/src/engine/thread.js
@@ -69,7 +69,10 @@ Thread.prototype.pushStack = function (blockId) {
     // Push an empty stack frame, if we need one.
     // Might not, if we just popped the stack.
     if (this.stack.length > this.stackFrames.length) {
-        this.stackFrames.push({});
+        this.stackFrames.push({
+            reported: {}, // Collects reported input values.
+            executionContext: {} // A context passed to block implementations.
+        });
     }
 };
 
@@ -99,6 +102,18 @@ Thread.prototype.peekStackFrame = function () {
     return this.stackFrames[this.stackFrames.length - 1];
 };
 
+/**
+ * Push a reported value to the parent of the current stack frame.
+ * @param {!string} inputName Name of input reported.
+ * @param {!Any} value Reported value to push.
+ */
+Thread.prototype.pushReportedValue = function (inputName, value) {
+    var parentStackFrame = this.stackFrames[this.stackFrames.length - 2];
+    if (parentStackFrame) {
+        parentStackFrame.reported[inputName] = value;
+    }
+};
+
 /**
  * Yields the thread.
  */

From 7ef3807b18bbe258cb3f318fa7ef4a5c6d6c3e11 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Fri, 17 Jun 2016 15:10:28 -0400
Subject: [PATCH 04/27] Example of a yielding reporter (returns random number
 after 1s)

---
 src/blocks/scratch3_operators.js | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js
index 94329b5a3..0b4471c35 100644
--- a/src/blocks/scratch3_operators.js
+++ b/src/blocks/scratch3_operators.js
@@ -15,7 +15,8 @@ Scratch3OperatorsBlocks.prototype.getPrimitives = function() {
         'math_number': this.number,
         'text': this.text,
         'operator_add': this.add,
-        'operator_equals': this.equals
+        'operator_equals': this.equals,
+        'operator_random': this.random
     };
 };
 
@@ -35,4 +36,15 @@ Scratch3OperatorsBlocks.prototype.equals = function (args) {
     return args.OPERAND1 == args.OPERAND2;
 };
 
+Scratch3OperatorsBlocks.prototype.random = function (args, util) {
+    // As a demo, this implementation of random returns after 1 second of yield.
+    // @todo Match Scratch 2.0 implementation with int-truncation.
+    // See: http://bit.ly/1Qc0GzC
+    util.yield();
+    setTimeout(function() {
+        var randomValue = (Math.random() * (args.TO - args.FROM)) + args.FROM;
+        util.report(randomValue);
+    }, 1000);
+};
+
 module.exports = Scratch3OperatorsBlocks;

From d15c93af053452c8818059001947caf17e10e8cd Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Fri, 17 Jun 2016 15:53:58 -0400
Subject: [PATCH 05/27] Keep "waiting reporter name" on the stack frame.

Also add highlighting for inputs.
---
 src/engine/execute.js | 14 ++++++++------
 src/engine/thread.js  |  8 +++++---
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index add9c9909..6657a3e15 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -10,10 +10,9 @@ var DEBUG_BLOCK_CALLS = true;
  * Execute a block.
  * @param {!Sequencer} sequencer Which sequencer is executing.
  * @param {!Thread} thread Thread which to read and execute.
- * @param {string=} opt_waitingInputName If evaluating an input, its name.
  * @return {?Any} Reported value, if available immediately.
  */
-var execute = function (sequencer, thread, opt_waitingInputName) {
+var execute = function (sequencer, thread) {
     var runtime = sequencer.runtime;
 
     // Current block to execute is the one on the top of the stack.
@@ -48,14 +47,18 @@ var execute = function (sequencer, thread, opt_waitingInputName) {
             if (DEBUG_BLOCK_CALLS) {
                 console.time('Yielding reporter evaluation');
             }
-            var result = execute(sequencer, thread, inputName);
+            runtime.glowBlock(inputBlockId, true);
+            var result = execute(sequencer, thread);
             // Did the reporter yield?
             if (thread.status === Thread.STATUS_YIELD) {
                 // Reporter yielded; don't pop stack and wait for it to unyield.
                 // The value will be populated once the reporter unyields,
                 // and passed up to the currentStackFrame on next execution.
+                // Save name of this input to be filled by child `util.report`.
+                currentStackFrame.waitingReporter = inputName;
                 return;
             }
+            runtime.glowBlock(inputBlockId, false);
             thread.popStack();
             argValues[inputName] = result;
         }
@@ -84,12 +87,11 @@ var execute = function (sequencer, thread, opt_waitingInputName) {
             sequencer.proceedThread(thread);
         },
         report: function(reportedValue) {
-            thread.pushReportedValue(opt_waitingInputName, reportedValue);
             if (DEBUG_BLOCK_CALLS) {
-                console.log('Reported: ', reportedValue,
-                    ' for ', opt_waitingInputName);
+                console.log('Reported: ', reportedValue);
                 console.timeEnd('Yielding reporter evaluation');
             }
+            thread.pushReportedValue(reportedValue);
             sequencer.proceedThread(thread);
         },
         timeout: thread.addTimeout.bind(thread),
diff --git a/src/engine/thread.js b/src/engine/thread.js
index 65b251648..bbb23f678 100644
--- a/src/engine/thread.js
+++ b/src/engine/thread.js
@@ -71,6 +71,7 @@ Thread.prototype.pushStack = function (blockId) {
     if (this.stack.length > this.stackFrames.length) {
         this.stackFrames.push({
             reported: {}, // Collects reported input values.
+            waitingReporter: null, // Name of waiting reporter.
             executionContext: {} // A context passed to block implementations.
         });
     }
@@ -104,13 +105,14 @@ Thread.prototype.peekStackFrame = function () {
 
 /**
  * Push a reported value to the parent of the current stack frame.
- * @param {!string} inputName Name of input reported.
  * @param {!Any} value Reported value to push.
  */
-Thread.prototype.pushReportedValue = function (inputName, value) {
+Thread.prototype.pushReportedValue = function (value) {
     var parentStackFrame = this.stackFrames[this.stackFrames.length - 2];
     if (parentStackFrame) {
-        parentStackFrame.reported[inputName] = value;
+        var waitingReporter = parentStackFrame.waitingReporter;
+        parentStackFrame.reported[waitingReporter] = value;
+        parentStackFrame.waitingReporter = null;
     }
 };
 

From bed3e28c02dd1e05d7c6288e29e3a78c6e98d9f0 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Fri, 17 Jun 2016 17:18:44 -0400
Subject: [PATCH 06/27] Simplifications of `execute` ordering

and always cache returned reporter values in currentStackFrame.reported.
---
 src/engine/execute.js | 34 ++++++++++++++++------------------
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index 6657a3e15..2112da0f0 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -21,6 +21,17 @@ var execute = function (sequencer, thread) {
 
     var opcode = runtime.blocks.getOpcode(currentBlockId);
 
+    if (!opcode) {
+        console.warn('Could not get opcode for block: ' + currentBlockId);
+        return;
+    }
+
+    var blockFunction = runtime.getOpcodeFunction(opcode);
+    if (!blockFunction) {
+        console.warn('Could not get implementation for opcode: ' + opcode);
+        return;
+    }
+
     // Generate values for arguments (inputs).
     var argValues = {};
 
@@ -36,11 +47,7 @@ var execute = function (sequencer, thread) {
         var input = inputs[inputName];
         var inputBlockId = input.block;
         // Is there a value for this input waiting in the stack frame?
-        if (currentStackFrame.reported &&
-            currentStackFrame.reported[inputName]) {
-            // Use that value.
-            argValues[inputName] = currentStackFrame.reported[inputName];
-        } else {
+        if (!currentStackFrame.reported[inputName]) {
             // Otherwise, we need to evaluate the block.
             // Push to the stack to evaluate this input.
             thread.pushStack(inputBlockId);
@@ -50,29 +57,20 @@ var execute = function (sequencer, thread) {
             runtime.glowBlock(inputBlockId, true);
             var result = execute(sequencer, thread);
             // Did the reporter yield?
+            currentStackFrame.waitingReporter = inputName;
             if (thread.status === Thread.STATUS_YIELD) {
                 // Reporter yielded; don't pop stack and wait for it to unyield.
                 // The value will be populated once the reporter unyields,
                 // and passed up to the currentStackFrame on next execution.
                 // Save name of this input to be filled by child `util.report`.
-                currentStackFrame.waitingReporter = inputName;
                 return;
             }
             runtime.glowBlock(inputBlockId, false);
-            thread.popStack();
+            thread.pushReportedValue(result);
             argValues[inputName] = result;
+            thread.popStack();
         }
-    }
-
-    if (!opcode) {
-        console.warn('Could not get opcode for block: ' + currentBlockId);
-        return;
-    }
-
-    var blockFunction = runtime.getOpcodeFunction(opcode);
-    if (!blockFunction) {
-        console.warn('Could not get implementation for opcode: ' + opcode);
-        return;
+        argValues[inputName] = currentStackFrame.reported[inputName];
     }
 
     if (DEBUG_BLOCK_CALLS) {

From 6181bcd5cba666cea2a49ca974f7a326e8b63e12 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 14:10:19 -0400
Subject: [PATCH 07/27] Refactor Thread.peekParentStackFrame

---
 src/engine/thread.js | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/engine/thread.js b/src/engine/thread.js
index bbb23f678..746d7dcc6 100644
--- a/src/engine/thread.js
+++ b/src/engine/thread.js
@@ -103,12 +103,20 @@ Thread.prototype.peekStackFrame = function () {
     return this.stackFrames[this.stackFrames.length - 1];
 };
 
+/**
+ * Get stack frame above the current top.
+ * @return {?Object} Second to last stack frame stored on this thread.
+ */
+Thread.prototype.peekParentStackFrame = function () {
+    return this.stackFrames[this.stackFrames.length - 2];
+};
+
 /**
  * Push a reported value to the parent of the current stack frame.
  * @param {!Any} value Reported value to push.
  */
 Thread.prototype.pushReportedValue = function (value) {
-    var parentStackFrame = this.stackFrames[this.stackFrames.length - 2];
+    var parentStackFrame = this.peekParentStackFrame();
     if (parentStackFrame) {
         var waitingReporter = parentStackFrame.waitingReporter;
         parentStackFrame.reported[waitingReporter] = value;

From 173f0615d3e99246318ec133bf54ff244aa9edbf Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 14:11:21 -0400
Subject: [PATCH 08/27] Refactor: always push reports to the stack frame

---
 src/engine/execute.js | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index 2112da0f0..dae207a9c 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -10,7 +10,6 @@ var DEBUG_BLOCK_CALLS = true;
  * Execute a block.
  * @param {!Sequencer} sequencer Which sequencer is executing.
  * @param {!Thread} thread Thread which to read and execute.
- * @return {?Any} Reported value, if available immediately.
  */
 var execute = function (sequencer, thread) {
     var runtime = sequencer.runtime;
@@ -47,7 +46,7 @@ var execute = function (sequencer, thread) {
         var input = inputs[inputName];
         var inputBlockId = input.block;
         // Is there a value for this input waiting in the stack frame?
-        if (!currentStackFrame.reported[inputName]) {
+        if (typeof currentStackFrame.reported[inputName] === 'undefined') {
             // Otherwise, we need to evaluate the block.
             // Push to the stack to evaluate this input.
             thread.pushStack(inputBlockId);
@@ -55,9 +54,8 @@ var execute = function (sequencer, thread) {
                 console.time('Yielding reporter evaluation');
             }
             runtime.glowBlock(inputBlockId, true);
-            var result = execute(sequencer, thread);
-            // Did the reporter yield?
             currentStackFrame.waitingReporter = inputName;
+            execute(sequencer, thread);
             if (thread.status === Thread.STATUS_YIELD) {
                 // Reporter yielded; don't pop stack and wait for it to unyield.
                 // The value will be populated once the reporter unyields,
@@ -66,8 +64,6 @@ var execute = function (sequencer, thread) {
                 return;
             }
             runtime.glowBlock(inputBlockId, false);
-            thread.pushReportedValue(result);
-            argValues[inputName] = result;
             thread.popStack();
         }
         argValues[inputName] = currentStackFrame.reported[inputName];
@@ -98,12 +94,16 @@ var execute = function (sequencer, thread) {
             sequencer.stepToSubstack(thread, substackNum);
         }
     });
+    if (thread.status === Thread.STATUS_RUNNING) {
+        if (DEBUG_BLOCK_CALLS) {
+            console.log('reporting value: ', primitiveReturnValue);
+        }
+        thread.pushReportedValue(primitiveReturnValue);
+    }
     if (DEBUG_BLOCK_CALLS) {
         console.log('ending stack frame: ', currentStackFrame);
-        console.log('returned immediately: ', primitiveReturnValue);
         console.groupEnd();
     }
-    return primitiveReturnValue;
 };
 
 module.exports = execute;

From b21c9edf046807bbdb926cb5afd6813b22475b1a Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 14:24:00 -0400
Subject: [PATCH 09/27] Commenting improvements

---
 src/engine/execute.js | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index dae207a9c..64e69ac77 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -45,22 +45,22 @@ var execute = function (sequencer, thread) {
     for (var inputName in inputs) {
         var input = inputs[inputName];
         var inputBlockId = input.block;
-        // Is there a value for this input waiting in the stack frame?
+        // Is there no value for this input waiting in the stack frame?
         if (typeof currentStackFrame.reported[inputName] === 'undefined') {
-            // Otherwise, we need to evaluate the block.
+            // If there's not, we need to evaluate the block.
             // Push to the stack to evaluate this input.
             thread.pushStack(inputBlockId);
             if (DEBUG_BLOCK_CALLS) {
-                console.time('Yielding reporter evaluation');
+                console.time('Reporter evaluation');
             }
             runtime.glowBlock(inputBlockId, true);
+            // Save name of input for `Thread.pushReportedValue`.
             currentStackFrame.waitingReporter = inputName;
             execute(sequencer, thread);
             if (thread.status === Thread.STATUS_YIELD) {
                 // Reporter yielded; don't pop stack and wait for it to unyield.
                 // The value will be populated once the reporter unyields,
                 // and passed up to the currentStackFrame on next execution.
-                // Save name of this input to be filled by child `util.report`.
                 return;
             }
             runtime.glowBlock(inputBlockId, false);

From 9d9749681bf21bb23e592d6e0ed367fbf82d197d Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 14:28:12 -0400
Subject: [PATCH 10/27] Comment and `else` for reporter finishes right away

---
 src/engine/execute.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index 64e69ac77..6dfd4e331 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -62,9 +62,11 @@ var execute = function (sequencer, thread) {
                 // The value will be populated once the reporter unyields,
                 // and passed up to the currentStackFrame on next execution.
                 return;
+            } else {
+                // Reporter finished right away; pop the stack.
+                runtime.glowBlock(inputBlockId, false);
+                thread.popStack();
             }
-            runtime.glowBlock(inputBlockId, false);
-            thread.popStack();
         }
         argValues[inputName] = currentStackFrame.reported[inputName];
     }

From e83cfa6049f59ca1bfa5c3c704867ed7288518d0 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 14:29:47 -0400
Subject: [PATCH 11/27] Add comment and clear currentStackFrame.reported

---
 src/engine/execute.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index 6dfd4e331..007739b0b 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -71,6 +71,12 @@ var execute = function (sequencer, thread) {
         argValues[inputName] = currentStackFrame.reported[inputName];
     }
 
+    // If we've gotten this far, all of the input blocks are evaluated,
+    // and `argValues` is fully populated. So, execute the block primitive.
+    // First, clear `currentStackFrame.reported`, so any subsequent execution
+    // (e.g., on return from a substack) gets fresh inputs.
+    currentStackFrame.reported = {};
+
     if (DEBUG_BLOCK_CALLS) {
         console.groupCollapsed('Executing: ' + opcode);
         console.log('with arguments: ', argValues);

From e56c6e69803c983c424059788dc1f339f6267c3f Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 14:31:48 -0400
Subject: [PATCH 12/27] Rename `primitiveReturnValue` ->
 `primitiveReportedValue`

---
 src/engine/execute.js | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index 007739b0b..2cee0a1c9 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -82,8 +82,8 @@ var execute = function (sequencer, thread) {
         console.log('with arguments: ', argValues);
         console.log('and stack frame: ', currentStackFrame);
     }
-    var primitiveReturnValue = null;
-    primitiveReturnValue = blockFunction(argValues, {
+    var primitiveReportedValue = null;
+    primitiveReportedValue = blockFunction(argValues, {
         yield: thread.yield.bind(thread),
         done: function() {
             sequencer.proceedThread(thread);
@@ -104,9 +104,9 @@ var execute = function (sequencer, thread) {
     });
     if (thread.status === Thread.STATUS_RUNNING) {
         if (DEBUG_BLOCK_CALLS) {
-            console.log('reporting value: ', primitiveReturnValue);
+            console.log('reporting value: ', primitiveReportedValue);
         }
-        thread.pushReportedValue(primitiveReturnValue);
+        thread.pushReportedValue(primitiveReportedValue);
     }
     if (DEBUG_BLOCK_CALLS) {
         console.log('ending stack frame: ', currentStackFrame);

From f210c12d4d37ae401f029de5e280bf411719d4d6 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 14:42:06 -0400
Subject: [PATCH 13/27] Add more operators for testing

---
 src/blocks/scratch3_operators.js | 42 ++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js
index 0b4471c35..03fe3e352 100644
--- a/src/blocks/scratch3_operators.js
+++ b/src/blocks/scratch3_operators.js
@@ -15,7 +15,14 @@ Scratch3OperatorsBlocks.prototype.getPrimitives = function() {
         'math_number': this.number,
         'text': this.text,
         'operator_add': this.add,
+        'operator_subtract': this.subtract,
+        'operator_multiply': this.multiply,
+        'operator_divide': this.divide,
+        'operator_lt': this.lt,
         'operator_equals': this.equals,
+        'operator_gt': this.gt,
+        'operator_and': this.and,
+        'operator_or': this.or,
         'operator_random': this.random
     };
 };
@@ -32,10 +39,45 @@ Scratch3OperatorsBlocks.prototype.add = function (args) {
     return args.NUM1 + args.NUM2;
 };
 
+Scratch3OperatorsBlocks.prototype.subtract = function (args) {
+    return args.NUM1 - args.NUM2;
+};
+
+Scratch3OperatorsBlocks.prototype.multiply = function (args) {
+    return args.NUM1 * args.NUM2;
+};
+
+Scratch3OperatorsBlocks.prototype.divide = function (args) {
+    return args.NUM1 / args.NUM2;
+};
+
+Scratch3OperatorsBlocks.prototype.lt = function (args) {
+    return args.OPERAND1 < args.OPERAND2;
+};
+
 Scratch3OperatorsBlocks.prototype.equals = function (args) {
     return args.OPERAND1 == args.OPERAND2;
 };
 
+Scratch3OperatorsBlocks.prototype.gt = function (args) {
+    return args.OPERAND1 > args.OPERAND2;
+};
+
+Scratch3OperatorsBlocks.prototype.and = function (args) {
+    if (!args.OPERAND1 || !args.OPERAND2) {
+        return false;
+    }
+    return true;
+};
+
+Scratch3OperatorsBlocks.prototype.or = function (args) {
+    return args.OPERAND1 || args.OPERAND2;
+};
+
+Scratch3OperatorsBlocks.prototype.not = function (args) {
+    return !args.OPERAND;
+};
+
 Scratch3OperatorsBlocks.prototype.random = function (args, util) {
     // As a demo, this implementation of random returns after 1 second of yield.
     // @todo Match Scratch 2.0 implementation with int-truncation.

From f802faa461ae102cea802f0781b9e80defa4974e Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 14:42:56 -0400
Subject: [PATCH 14/27] operator_not in primitive table

---
 src/blocks/scratch3_operators.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js
index 03fe3e352..55b3b1129 100644
--- a/src/blocks/scratch3_operators.js
+++ b/src/blocks/scratch3_operators.js
@@ -23,6 +23,7 @@ Scratch3OperatorsBlocks.prototype.getPrimitives = function() {
         'operator_gt': this.gt,
         'operator_and': this.and,
         'operator_or': this.or,
+        'operator_not': this.not,
         'operator_random': this.random
     };
 };

From c63747e61bce51c0ad78ddc6f35f84d90230f60d Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 15:04:28 -0400
Subject: [PATCH 15/27] Move stepping logic for reporters to sequencer

---
 src/engine/execute.js   | 23 ++++++-----------------
 src/engine/sequencer.js | 27 +++++++++++++++++++++++++++
 2 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index 2cee0a1c9..6e1962808 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -48,24 +48,13 @@ var execute = function (sequencer, thread) {
         // Is there no value for this input waiting in the stack frame?
         if (typeof currentStackFrame.reported[inputName] === 'undefined') {
             // If there's not, we need to evaluate the block.
-            // Push to the stack to evaluate this input.
-            thread.pushStack(inputBlockId);
-            if (DEBUG_BLOCK_CALLS) {
-                console.time('Reporter evaluation');
-            }
-            runtime.glowBlock(inputBlockId, true);
-            // Save name of input for `Thread.pushReportedValue`.
-            currentStackFrame.waitingReporter = inputName;
-            execute(sequencer, thread);
-            if (thread.status === Thread.STATUS_YIELD) {
-                // Reporter yielded; don't pop stack and wait for it to unyield.
-                // The value will be populated once the reporter unyields,
-                // and passed up to the currentStackFrame on next execution.
+            var reporterYielded = (
+                sequencer.stepToReporter(thread, inputBlockId, inputName)
+            );
+            // If the reporter yielded, return immediately;
+            // it needs time to finish and report its value.
+            if (reporterYielded) {
                 return;
-            } else {
-                // Reporter finished right away; pop the stack.
-                runtime.glowBlock(inputBlockId, false);
-                thread.popStack();
             }
         }
         argValues[inputName] = currentStackFrame.reported[inputName];
diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js
index e82d4054c..27e3b9996 100644
--- a/src/engine/sequencer.js
+++ b/src/engine/sequencer.js
@@ -127,6 +127,33 @@ Sequencer.prototype.stepToSubstack = function (thread, substackNum) {
     }
 };
 
+/**
+ * Step a thread into an input reporter, and manage its status appropriately.
+ * @param {!Thread} thread Thread object to step to reporter.
+ * @param {!string} blockId ID of reporter block.
+ * @param {!string} inputName Name of input on parent block.
+ * @return {boolean} True if yielded, false if it finished immediately.
+ */
+Sequencer.prototype.stepToReporter = function (thread, blockId, inputName) {
+    var currentStackFrame = thread.peekStackFrame();
+    // Push to the stack to evaluate the reporter block.
+    thread.pushStack(blockId);
+    // Save name of input for `Thread.pushReportedValue`.
+    currentStackFrame.waitingReporter = inputName;
+    // Actually execute the block.
+    this.startThread(thread);
+    if (thread.status === Thread.STATUS_YIELD) {
+        // Reporter yielded; caller must wait for it to unyield.
+        // The value will be populated once the reporter unyields,
+        // and passed up to the currentStackFrame on next execution.
+        return true;
+    } else if (thread.status === Thread.STATUS_DONE) {
+        // Reporter finished, mark the thread as running.
+        thread.status = Thread.STATUS_RUNNING;
+        return false;
+    }
+};
+
 /**
  * Finish stepping a thread and proceed it to the next block.
  * @param {!Thread} thread Thread object to proceed.

From d44b806b4f4b883393306dd30aad90647592d210 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 16:44:53 -0400
Subject: [PATCH 16/27] Add blocking yield mode

---
 src/blocks/scratch3_operators.js |  2 +-
 src/engine/execute.js            |  1 +
 src/engine/sequencer.js          | 26 ++++++++++++++++++++++++++
 src/engine/thread.js             | 17 ++++++++++++++++-
 4 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js
index 55b3b1129..fe194da45 100644
--- a/src/blocks/scratch3_operators.js
+++ b/src/blocks/scratch3_operators.js
@@ -83,7 +83,7 @@ Scratch3OperatorsBlocks.prototype.random = function (args, util) {
     // As a demo, this implementation of random returns after 1 second of yield.
     // @todo Match Scratch 2.0 implementation with int-truncation.
     // See: http://bit.ly/1Qc0GzC
-    util.yield();
+    util.yieldAndBlock();
     setTimeout(function() {
         var randomValue = (Math.random() * (args.TO - args.FROM)) + args.FROM;
         util.report(randomValue);
diff --git a/src/engine/execute.js b/src/engine/execute.js
index 6e1962808..008305182 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -74,6 +74,7 @@ var execute = function (sequencer, thread) {
     var primitiveReportedValue = null;
     primitiveReportedValue = blockFunction(argValues, {
         yield: thread.yield.bind(thread),
+        yieldAndBlock: thread.yieldAndBlock.bind(thread),
         done: function() {
             sequencer.proceedThread(thread);
         },
diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js
index 27e3b9996..480267fdc 100644
--- a/src/engine/sequencer.js
+++ b/src/engine/sequencer.js
@@ -32,6 +32,13 @@ Sequencer.WORK_TIME = 10;
 Sequencer.prototype.stepThreads = function (threads) {
     // Start counting toward WORK_TIME
     this.timer.start();
+    // Check for a blocking thread.
+    var blockingThread = this.getBlockingThread_(threads);
+    if (blockingThread) {
+        // Attempt to resolve any timeouts, but otherwise stop stepping.
+        blockingThread.resolveTimeouts();
+        return [];
+    }
     // List of threads which have been killed by this step.
     var inactiveThreads = [];
     // If all of the threads are yielding, we should yield.
@@ -63,6 +70,10 @@ Sequencer.prototype.stepThreads = function (threads) {
                 activeThread.status = Thread.STATUS_RUNNING;
                 // @todo Deal with the return value
             }
+            // Has the thread gone into "blocking" mode? If so, stop stepping.
+            if (activeThread.status === Thread.STATUS_YIELD_BLOCK) {
+                return inactiveThreads;
+            }
             if (activeThread.stack.length === 0 &&
                 activeThread.status === Thread.STATUS_DONE) {
                 // Finished with this thread - tell runtime to clean it up.
@@ -78,6 +89,21 @@ Sequencer.prototype.stepThreads = function (threads) {
     return inactiveThreads;
 };
 
+/**
+ * Return the thread blocking all other threads, if one exists.
+ * If not, return false.
+ * @param {Array.<Thread>} threads List of which threads to check.
+ * @return {?Thread} The blocking thread if one exists.
+ */
+Sequencer.prototype.getBlockingThread_ = function (threads) {
+    for (var i = 0; i < threads.length; i++) {
+        if (threads[i].status === Thread.STATUS_YIELD_BLOCK) {
+            return threads[i];
+        }
+    }
+    return false;
+};
+
 /**
  * Step the requested thread
  * @param {!Thread} thread Thread object to step
diff --git a/src/engine/thread.js b/src/engine/thread.js
index 746d7dcc6..781197110 100644
--- a/src/engine/thread.js
+++ b/src/engine/thread.js
@@ -52,13 +52,21 @@ Thread.STATUS_RUNNING = 0;
  */
 Thread.STATUS_YIELD = 1;
 
+/**
+ * Thread status for a yielded thread that should block all other threads.
+ * This is desirable when an asynchronous capability should appear to take
+ * a synchronous amount of time (e.g., color touching color).
+ * @const
+ */
+Thread.STATUS_YIELD_BLOCK = 2;
+
 /**
  * Thread status for a finished/done thread.
  * Thread is moved to this state when the interpreter
  * can proceed with execution.
  * @const
  */
-Thread.STATUS_DONE = 2;
+Thread.STATUS_DONE = 3;
 
 /**
  * Push stack and update stack frames appropriately.
@@ -131,6 +139,13 @@ Thread.prototype.yield = function () {
     this.status = Thread.STATUS_YIELD;
 };
 
+/**
+ * Yields the thread and blocks other threads until unyielded.
+ */
+Thread.prototype.yieldAndBlock = function () {
+    this.status = Thread.STATUS_YIELD_BLOCK;
+};
+
 /**
  * Add an execution-synced timeouts for this thread.
  * See also: util/yieldtimers.js:timeout

From 405ad1044e2669563b44d73274187356b6f79f1b Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 16:46:45 -0400
Subject: [PATCH 17/27] getBlockingThread_ returns null when none available.

---
 src/engine/sequencer.js | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js
index 480267fdc..12d86b41b 100644
--- a/src/engine/sequencer.js
+++ b/src/engine/sequencer.js
@@ -91,7 +91,6 @@ Sequencer.prototype.stepThreads = function (threads) {
 
 /**
  * Return the thread blocking all other threads, if one exists.
- * If not, return false.
  * @param {Array.<Thread>} threads List of which threads to check.
  * @return {?Thread} The blocking thread if one exists.
  */
@@ -101,7 +100,7 @@ Sequencer.prototype.getBlockingThread_ = function (threads) {
             return threads[i];
         }
     }
-    return false;
+    return null;
 };
 
 /**

From 09b9c506a9236831d8f641452619244af28eda9f Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Mon, 20 Jun 2016 16:47:42 -0400
Subject: [PATCH 18/27] Check for blocking case in stepToReporter

---
 src/engine/sequencer.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js
index 12d86b41b..10657d4d0 100644
--- a/src/engine/sequencer.js
+++ b/src/engine/sequencer.js
@@ -167,7 +167,8 @@ Sequencer.prototype.stepToReporter = function (thread, blockId, inputName) {
     currentStackFrame.waitingReporter = inputName;
     // Actually execute the block.
     this.startThread(thread);
-    if (thread.status === Thread.STATUS_YIELD) {
+    if (thread.status === Thread.STATUS_YIELD ||
+        thread.status === Thread.STATUS_YIELD_BLOCK) {
         // Reporter yielded; caller must wait for it to unyield.
         // The value will be populated once the reporter unyields,
         // and passed up to the currentStackFrame on next execution.

From 8f6a88c0955c45870a1ba40ac89c6ced3e14453e Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Fri, 24 Jun 2016 10:52:49 -0400
Subject: [PATCH 19/27] Ensure predicates always return booleans

---
 src/blocks/scratch3_operators.js | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js
index fe194da45..837411262 100644
--- a/src/blocks/scratch3_operators.js
+++ b/src/blocks/scratch3_operators.js
@@ -53,30 +53,27 @@ Scratch3OperatorsBlocks.prototype.divide = function (args) {
 };
 
 Scratch3OperatorsBlocks.prototype.lt = function (args) {
-    return args.OPERAND1 < args.OPERAND2;
+    return Boolean(args.OPERAND1 < args.OPERAND2);
 };
 
 Scratch3OperatorsBlocks.prototype.equals = function (args) {
-    return args.OPERAND1 == args.OPERAND2;
+    return Boolean(args.OPERAND1 == args.OPERAND2);
 };
 
 Scratch3OperatorsBlocks.prototype.gt = function (args) {
-    return args.OPERAND1 > args.OPERAND2;
+    return Boolean(args.OPERAND1 > args.OPERAND2);
 };
 
 Scratch3OperatorsBlocks.prototype.and = function (args) {
-    if (!args.OPERAND1 || !args.OPERAND2) {
-        return false;
-    }
-    return true;
+    return Boolean(args.OPERAND1 && args.OPERAND2);
 };
 
 Scratch3OperatorsBlocks.prototype.or = function (args) {
-    return args.OPERAND1 || args.OPERAND2;
+    return Boolean(args.OPERAND1 || args.OPERAND2);
 };
 
 Scratch3OperatorsBlocks.prototype.not = function (args) {
-    return !args.OPERAND;
+    return Boolean(!args.OPERAND);
 };
 
 Scratch3OperatorsBlocks.prototype.random = function (args, util) {

From d72cc55c119502121db5b1036a7a2821bd03484a Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Fri, 24 Jun 2016 11:14:22 -0400
Subject: [PATCH 20/27] Example that uses promises instead of `util.report`

---
 package.json                     |  3 ++-
 src/blocks/scratch3_operators.js | 13 +++++++++----
 src/engine/execute.js            | 27 ++++++++++++++++++---------
 3 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/package.json b/package.json
index e55a497e1..2d4d54773 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,8 @@
   },
   "dependencies": {
     "htmlparser2": "3.9.0",
-    "memoizee": "0.3.10"
+    "memoizee": "0.3.10",
+    "promise": "7.1.1"
   },
   "devDependencies": {
     "eslint": "2.7.0",
diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js
index 837411262..4237f47da 100644
--- a/src/blocks/scratch3_operators.js
+++ b/src/blocks/scratch3_operators.js
@@ -1,3 +1,5 @@
+var Promise = require('promise');
+
 function Scratch3OperatorsBlocks(runtime) {
     /**
      * The runtime instantiating this block package.
@@ -81,10 +83,13 @@ Scratch3OperatorsBlocks.prototype.random = function (args, util) {
     // @todo Match Scratch 2.0 implementation with int-truncation.
     // See: http://bit.ly/1Qc0GzC
     util.yieldAndBlock();
-    setTimeout(function() {
-        var randomValue = (Math.random() * (args.TO - args.FROM)) + args.FROM;
-        util.report(randomValue);
-    }, 1000);
+    var examplePromise = new Promise(function(resolve) {
+        setTimeout(function() {
+            var res = (Math.random() * (args.TO - args.FROM)) + args.FROM;
+            resolve(res);
+        }, 1000);
+    });
+    return examplePromise;
 };
 
 module.exports = Scratch3OperatorsBlocks;
diff --git a/src/engine/execute.js b/src/engine/execute.js
index 008305182..e491cf778 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -1,3 +1,4 @@
+var Promise = require('promise');
 var Thread = require('./thread');
 
 /**
@@ -78,21 +79,29 @@ var execute = function (sequencer, thread) {
         done: function() {
             sequencer.proceedThread(thread);
         },
-        report: function(reportedValue) {
-            if (DEBUG_BLOCK_CALLS) {
-                console.log('Reported: ', reportedValue);
-                console.timeEnd('Yielding reporter evaluation');
-            }
-            thread.pushReportedValue(reportedValue);
-            sequencer.proceedThread(thread);
-        },
         timeout: thread.addTimeout.bind(thread),
         stackFrame: currentStackFrame.executionContext,
         startSubstack: function (substackNum) {
             sequencer.stepToSubstack(thread, substackNum);
         }
     });
-    if (thread.status === Thread.STATUS_RUNNING) {
+
+    // Deal with any reported value.
+    // If it's a promise, wait until promise resolves.
+    var isPromise = (
+        primitiveReportedValue &&
+        primitiveReportedValue.then &&
+        typeof primitiveReportedValue.then === 'function'
+    );
+    if (isPromise) {
+        primitiveReportedValue.then(function(resolvedValue) {
+            if (DEBUG_BLOCK_CALLS) {
+                console.log('reporting value: ', resolvedValue);
+            }
+            thread.pushReportedValue(resolvedValue);
+            sequencer.proceedThread(thread);
+        });
+    } else if (thread.status === Thread.STATUS_RUNNING) {
         if (DEBUG_BLOCK_CALLS) {
             console.log('reporting value: ', primitiveReportedValue);
         }

From 57057bfffcebc7e1c5a994500957349bc1fc1a80 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Fri, 24 Jun 2016 11:16:56 -0400
Subject: [PATCH 21/27] Remove unused require to fix build

---
 src/engine/execute.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index e491cf778..097af742b 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -1,4 +1,3 @@
-var Promise = require('promise');
 var Thread = require('./thread');
 
 /**

From 9881ee76b93e2740726298e49e758a784d9c96f4 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Fri, 24 Jun 2016 11:19:38 -0400
Subject: [PATCH 22/27] Deal with promise rejection also.

---
 src/engine/execute.js | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index 097af742b..528a3bb93 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -94,12 +94,21 @@ var execute = function (sequencer, thread) {
     );
     if (isPromise) {
         primitiveReportedValue.then(function(resolvedValue) {
+            // Promise resolved: the primitive reported a value.
             if (DEBUG_BLOCK_CALLS) {
                 console.log('reporting value: ', resolvedValue);
             }
             thread.pushReportedValue(resolvedValue);
             sequencer.proceedThread(thread);
-        });
+        }, function(rejectionReason) {
+            // Promise rejected: the primitive had some error.
+            // Log it and proceed.
+            if (DEBUG_BLOCK_CALLS) {
+                console.warn('primitive rejected promise: ', rejectionReason);
+            }
+            sequencer.proceedThread(thread);
+        }
+    );
     } else if (thread.status === Thread.STATUS_RUNNING) {
         if (DEBUG_BLOCK_CALLS) {
             console.log('reporting value: ', primitiveReportedValue);

From 9a7ab57f6f5d4a6875901c899cdc546c1a5fc13a Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Tue, 28 Jun 2016 13:39:44 -0400
Subject: [PATCH 23/27] Always yield thread when a promise is returned.

---
 src/engine/execute.js | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index 528a3bb93..632b29c82 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -93,6 +93,11 @@ var execute = function (sequencer, thread) {
         typeof primitiveReportedValue.then === 'function'
     );
     if (isPromise) {
+        if (thread.status === Thread.STATUS_RUNNING) {
+            // Primitive returned a promise; automatically yield thread.
+            thread.status = Thread.STATUS_YIELD;
+        }
+        // Promise handlers
         primitiveReportedValue.then(function(resolvedValue) {
             // Promise resolved: the primitive reported a value.
             if (DEBUG_BLOCK_CALLS) {
@@ -107,8 +112,7 @@ var execute = function (sequencer, thread) {
                 console.warn('primitive rejected promise: ', rejectionReason);
             }
             sequencer.proceedThread(thread);
-        }
-    );
+        });
     } else if (thread.status === Thread.STATUS_RUNNING) {
         if (DEBUG_BLOCK_CALLS) {
             console.log('reporting value: ', primitiveReportedValue);

From 6daee9a70e5f5ad55e8f45e6fb9edcf7021c1cae Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Thu, 30 Jun 2016 16:57:12 -0400
Subject: [PATCH 24/27] Remove VM-locking yield mode per discussion

---
 src/blocks/scratch3_operators.js |  3 +--
 src/engine/execute.js            |  1 -
 src/engine/sequencer.js          | 25 -------------------------
 src/engine/thread.js             | 17 +----------------
 4 files changed, 2 insertions(+), 44 deletions(-)

diff --git a/src/blocks/scratch3_operators.js b/src/blocks/scratch3_operators.js
index 4237f47da..75077061c 100644
--- a/src/blocks/scratch3_operators.js
+++ b/src/blocks/scratch3_operators.js
@@ -78,11 +78,10 @@ Scratch3OperatorsBlocks.prototype.not = function (args) {
     return Boolean(!args.OPERAND);
 };
 
-Scratch3OperatorsBlocks.prototype.random = function (args, util) {
+Scratch3OperatorsBlocks.prototype.random = function (args) {
     // As a demo, this implementation of random returns after 1 second of yield.
     // @todo Match Scratch 2.0 implementation with int-truncation.
     // See: http://bit.ly/1Qc0GzC
-    util.yieldAndBlock();
     var examplePromise = new Promise(function(resolve) {
         setTimeout(function() {
             var res = (Math.random() * (args.TO - args.FROM)) + args.FROM;
diff --git a/src/engine/execute.js b/src/engine/execute.js
index 632b29c82..8fbb73dfc 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -74,7 +74,6 @@ var execute = function (sequencer, thread) {
     var primitiveReportedValue = null;
     primitiveReportedValue = blockFunction(argValues, {
         yield: thread.yield.bind(thread),
-        yieldAndBlock: thread.yieldAndBlock.bind(thread),
         done: function() {
             sequencer.proceedThread(thread);
         },
diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js
index 10657d4d0..81813a141 100644
--- a/src/engine/sequencer.js
+++ b/src/engine/sequencer.js
@@ -32,13 +32,6 @@ Sequencer.WORK_TIME = 10;
 Sequencer.prototype.stepThreads = function (threads) {
     // Start counting toward WORK_TIME
     this.timer.start();
-    // Check for a blocking thread.
-    var blockingThread = this.getBlockingThread_(threads);
-    if (blockingThread) {
-        // Attempt to resolve any timeouts, but otherwise stop stepping.
-        blockingThread.resolveTimeouts();
-        return [];
-    }
     // List of threads which have been killed by this step.
     var inactiveThreads = [];
     // If all of the threads are yielding, we should yield.
@@ -70,10 +63,6 @@ Sequencer.prototype.stepThreads = function (threads) {
                 activeThread.status = Thread.STATUS_RUNNING;
                 // @todo Deal with the return value
             }
-            // Has the thread gone into "blocking" mode? If so, stop stepping.
-            if (activeThread.status === Thread.STATUS_YIELD_BLOCK) {
-                return inactiveThreads;
-            }
             if (activeThread.stack.length === 0 &&
                 activeThread.status === Thread.STATUS_DONE) {
                 // Finished with this thread - tell runtime to clean it up.
@@ -89,20 +78,6 @@ Sequencer.prototype.stepThreads = function (threads) {
     return inactiveThreads;
 };
 
-/**
- * Return the thread blocking all other threads, if one exists.
- * @param {Array.<Thread>} threads List of which threads to check.
- * @return {?Thread} The blocking thread if one exists.
- */
-Sequencer.prototype.getBlockingThread_ = function (threads) {
-    for (var i = 0; i < threads.length; i++) {
-        if (threads[i].status === Thread.STATUS_YIELD_BLOCK) {
-            return threads[i];
-        }
-    }
-    return null;
-};
-
 /**
  * Step the requested thread
  * @param {!Thread} thread Thread object to step
diff --git a/src/engine/thread.js b/src/engine/thread.js
index 781197110..746d7dcc6 100644
--- a/src/engine/thread.js
+++ b/src/engine/thread.js
@@ -52,21 +52,13 @@ Thread.STATUS_RUNNING = 0;
  */
 Thread.STATUS_YIELD = 1;
 
-/**
- * Thread status for a yielded thread that should block all other threads.
- * This is desirable when an asynchronous capability should appear to take
- * a synchronous amount of time (e.g., color touching color).
- * @const
- */
-Thread.STATUS_YIELD_BLOCK = 2;
-
 /**
  * Thread status for a finished/done thread.
  * Thread is moved to this state when the interpreter
  * can proceed with execution.
  * @const
  */
-Thread.STATUS_DONE = 3;
+Thread.STATUS_DONE = 2;
 
 /**
  * Push stack and update stack frames appropriately.
@@ -139,13 +131,6 @@ Thread.prototype.yield = function () {
     this.status = Thread.STATUS_YIELD;
 };
 
-/**
- * Yields the thread and blocks other threads until unyielded.
- */
-Thread.prototype.yieldAndBlock = function () {
-    this.status = Thread.STATUS_YIELD_BLOCK;
-};
-
 /**
  * Add an execution-synced timeouts for this thread.
  * See also: util/yieldtimers.js:timeout

From ab6e0d383963e852f454dcfb1d141f914631f485 Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Thu, 30 Jun 2016 17:06:50 -0400
Subject: [PATCH 25/27] Remove YieldTimers, unused WeDo blocks

---
 playground/index.html          |   6 --
 src/blocks/scratch3_control.js |  13 +--
 src/blocks/wedo2.js            | 152 ---------------------------------
 src/engine/execute.js          |   1 -
 src/engine/runtime.js          |   3 +-
 src/engine/sequencer.js        |  12 +--
 src/engine/thread.js           |  33 -------
 src/util/yieldtimers.js        |  71 ---------------
 8 files changed, 11 insertions(+), 280 deletions(-)
 delete mode 100644 src/blocks/wedo2.js
 delete mode 100644 src/util/yieldtimers.js

diff --git a/playground/index.html b/playground/index.html
index 0d4903d3d..82535807b 100644
--- a/playground/index.html
+++ b/playground/index.html
@@ -79,12 +79,6 @@
           </block>
           <block type="control_delete_this_clone"></block>
         </category>
-        <category name="Wedo">
-            <block type="wedo_setcolor"></block>
-            <block type="wedo_motorspeed"></block>
-            <block type="wedo_whentilt"></block>
-            <block type="wedo_whendistanceclose"></block>
-        </category>
         <category name="Operators">
             <block type="operator_add">
               <value name="NUM1">
diff --git a/src/blocks/scratch3_control.js b/src/blocks/scratch3_control.js
index 1d05a8c7a..e13edefd9 100644
--- a/src/blocks/scratch3_control.js
+++ b/src/blocks/scratch3_control.js
@@ -1,3 +1,5 @@
+var Promise = require('promise');
+
 function Scratch3ControlBlocks(runtime) {
     /**
      * The runtime instantiating this block package.
@@ -38,11 +40,12 @@ Scratch3ControlBlocks.prototype.forever = function(args, util) {
     util.startSubstack();
 };
 
-Scratch3ControlBlocks.prototype.wait = function(args, util) {
-    util.yield();
-    util.timeout(function() {
-        util.done();
-    }, 1000 * args.DURATION);
+Scratch3ControlBlocks.prototype.wait = function(args) {
+    return new Promise(function(resolve) {
+        setTimeout(function() {
+            resolve();
+        }, 1000 * args.DURATION);
+    });
 };
 
 Scratch3ControlBlocks.prototype.if = function(args, util) {
diff --git a/src/blocks/wedo2.js b/src/blocks/wedo2.js
deleted file mode 100644
index d7516bc18..000000000
--- a/src/blocks/wedo2.js
+++ /dev/null
@@ -1,152 +0,0 @@
-
-var YieldTimers = require('../util/yieldtimers.js');
-
-function WeDo2Blocks(runtime) {
-    /**
-     * The runtime instantiating this block package.
-     * @type {Runtime}
-     */
-    this.runtime = runtime;
-
-    /**
-     * Current motor speed, as a percentage (100 = full speed).
-     * @type {number}
-     * @private
-     */
-    this._motorSpeed = 100;
-
-    /**
-     * The timeout ID for a pending motor action.
-     * @type {?int}
-     * @private
-     */
-    this._motorTimeout = null;
-}
-
-/**
- * Retrieve the block primitives implemented by this package.
- * @return {Object.<string, Function>} Mapping of opcode to Function.
- */
-WeDo2Blocks.prototype.getPrimitives = function() {
-    return {
-        'wedo_motorclockwise': this.motorClockwise,
-        'wedo_motorcounterclockwise': this.motorCounterClockwise,
-        'wedo_motorspeed': this.motorSpeed,
-        'wedo_setcolor': this.setColor,
-        'wedo_whendistanceclose': this.whenDistanceClose,
-        'wedo_whentilt': this.whenTilt
-    };
-};
-
-/**
- * Clamp a value between a minimum and maximum value.
- * @todo move this to a common utility class.
- * @param {number} val The value to clamp.
- * @param {number} min The minimum return value.
- * @param {number} max The maximum return value.
- * @returns {number} The clamped value.
- * @private
- */
-WeDo2Blocks.prototype._clamp = function(val, min, max) {
-    return Math.max(min, Math.min(val, max));
-};
-
-/**
- * Common implementation for motor blocks.
- * @param {string} direction The direction to turn ('left' or 'right').
- * @param {number} durationSeconds The number of seconds to run.
- * @param {Object} util The util instance to use for yielding and finishing.
- * @private
- */
-WeDo2Blocks.prototype._motorOnFor = function(direction, durationSeconds, util) {
-    if (this._motorTimeout > 0) {
-        // @todo maybe this should go through util
-        YieldTimers.resolve(this._motorTimeout);
-        this._motorTimeout = null;
-    }
-    if (typeof window !== 'undefined' && window.native) {
-        window.native.motorRun(direction, this._motorSpeed);
-    }
-
-    var instance = this;
-    var myTimeout = this._motorTimeout = util.timeout(function() {
-        if (instance._motorTimeout == myTimeout) {
-            instance._motorTimeout = null;
-        }
-        if (typeof window !== 'undefined' && window.native) {
-            window.native.motorStop();
-        }
-        util.done();
-    }, 1000 * durationSeconds);
-
-    util.yield();
-};
-
-WeDo2Blocks.prototype.motorClockwise = function(argValues, util) {
-    this._motorOnFor('right', parseFloat(argValues[0]), util);
-};
-
-WeDo2Blocks.prototype.motorCounterClockwise = function(argValues, util) {
-    this._motorOnFor('left', parseFloat(argValues[0]), util);
-};
-
-WeDo2Blocks.prototype.motorSpeed = function(argValues) {
-    var speed = argValues[0];
-    switch (speed) {
-    case 'slow':
-        this._motorSpeed = 20;
-        break;
-    case 'medium':
-        this._motorSpeed = 50;
-        break;
-    case 'fast':
-        this._motorSpeed = 100;
-        break;
-    }
-};
-
-/**
- * Convert a color name to a WeDo color index.
- * Supports 'mystery' for a random hue.
- * @param {string} colorName The color to retrieve.
- * @returns {number} The WeDo color index.
- * @private
- */
-WeDo2Blocks.prototype._getColor = function(colorName) {
-    var colors = {
-        'yellow': 7,
-        'orange': 8,
-        'coral': 9,
-        'magenta': 1,
-        'purple': 2,
-        'blue': 3,
-        'green': 6,
-        'white': 10
-    };
-
-    if (colorName == 'mystery') {
-        return Math.floor((Math.random() * 10) + 1);
-    }
-
-    return colors[colorName];
-};
-
-WeDo2Blocks.prototype.setColor = function(argValues, util) {
-    if (typeof window !== 'undefined' && window.native) {
-        var colorIndex = this._getColor(argValues[0]);
-        window.native.setLedColor(colorIndex);
-    }
-    // Pause for quarter second
-    util.yield();
-    util.timeout(function() {
-        util.done();
-    }, 250);
-};
-
-WeDo2Blocks.prototype.whenDistanceClose = function() {
-};
-
-WeDo2Blocks.prototype.whenTilt = function() {
-};
-
-module.exports = WeDo2Blocks;
diff --git a/src/engine/execute.js b/src/engine/execute.js
index 8fbb73dfc..acff32585 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -77,7 +77,6 @@ var execute = function (sequencer, thread) {
         done: function() {
             sequencer.proceedThread(thread);
         },
-        timeout: thread.addTimeout.bind(thread),
         stackFrame: currentStackFrame.executionContext,
         startSubstack: function (substackNum) {
             sequencer.stepToSubstack(thread, substackNum);
diff --git a/src/engine/runtime.js b/src/engine/runtime.js
index f6ad79f0b..8c4c862e1 100644
--- a/src/engine/runtime.js
+++ b/src/engine/runtime.js
@@ -6,8 +6,7 @@ var util = require('util');
 var defaultBlockPackages = {
     'scratch3_control': require('../blocks/scratch3_control'),
     'scratch3_event': require('../blocks/scratch3_event'),
-    'scratch3_operators': require('../blocks/scratch3_operators'),
-    'wedo2': require('../blocks/wedo2')
+    'scratch3_operators': require('../blocks/scratch3_operators')
 };
 
 /**
diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js
index 81813a141..5eca9c202 100644
--- a/src/engine/sequencer.js
+++ b/src/engine/sequencer.js
@@ -52,16 +52,8 @@ Sequencer.prototype.stepThreads = function (threads) {
                 // Normal-mode thread: step.
                 this.startThread(activeThread);
             } else if (activeThread.status === Thread.STATUS_YIELD) {
-                // Yield-mode thread: resolve timers.
-                activeThread.resolveTimeouts();
-                if (activeThread.status === Thread.STATUS_YIELD) {
-                    // Still yielding.
-                    numYieldingThreads++;
-                }
-            } else if (activeThread.status === Thread.STATUS_DONE) {
-                // Moved to a done state - finish up
-                activeThread.status = Thread.STATUS_RUNNING;
-                // @todo Deal with the return value
+                // Yielding thread: do nothing for this step.
+                continue;
             }
             if (activeThread.stack.length === 0 &&
                 activeThread.status === Thread.STATUS_DONE) {
diff --git a/src/engine/thread.js b/src/engine/thread.js
index 746d7dcc6..d14d83f90 100644
--- a/src/engine/thread.js
+++ b/src/engine/thread.js
@@ -1,5 +1,3 @@
-var YieldTimers = require('../util/yieldtimers.js');
-
 /**
  * A thread is a running stack context and all the metadata needed.
  * @param {?string} firstBlock First block to execute in the thread.
@@ -30,12 +28,6 @@ function Thread (firstBlock) {
      * @type {number}
      */
     this.status = 0; /* Thread.STATUS_RUNNING */
-
-    /**
-     * Execution-synced timeouts.
-     * @type {number}
-     */
-    this.timeoutIds = [];
 }
 
 /**
@@ -131,29 +123,4 @@ Thread.prototype.yield = function () {
     this.status = Thread.STATUS_YIELD;
 };
 
-/**
- * Add an execution-synced timeouts for this thread.
- * See also: util/yieldtimers.js:timeout
- * @param {!Function} callback To be called when the timer is done.
- * @param {number} timeDelta Time to wait, in ms.
- */
-Thread.prototype.addTimeout = function (callback, timeDelta) {
-    var timeoutId = YieldTimers.timeout(callback, timeDelta);
-    this.timeoutIds.push(timeoutId);
-};
-
-/**
- * Attempt to resolve all execution-synced timeouts on this thread.
- */
-Thread.prototype.resolveTimeouts = function () {
-    var newTimeouts = [];
-    for (var i = 0; i < this.timeoutIds.length; i++) {
-        var resolved = YieldTimers.resolve(this.timeoutIds[i]);
-        if (!resolved) {
-            newTimeouts.push(this.timeoutIds[i]);
-        }
-    }
-    this.timeoutIds = newTimeouts;
-};
-
 module.exports = Thread;
diff --git a/src/util/yieldtimers.js b/src/util/yieldtimers.js
deleted file mode 100644
index 84c6d3259..000000000
--- a/src/util/yieldtimers.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * @fileoverview Timers that are synchronized with the Scratch sequencer.
- */
-var Timer = require('./timer');
-
-function YieldTimers () {}
-
-/**
- * Shared collection of timers.
- * Each timer is a [Function, number] with the callback
- * and absolute time for it to run.
- * @type {Object.<number,Array>}
- */
-YieldTimers.timers = {};
-
-/**
- * Monotonically increasing timer ID.
- * @type {number}
- */
-YieldTimers.timerId = 0;
-
-/**
- * Utility for measuring time.
- * @type {!Timer}
- */
-YieldTimers.globalTimer = new Timer();
-
-/**
- * The timeout function is passed to primitives and is intended
- * as a convenient replacement for window.setTimeout.
- * The sequencer will attempt to resolve the timer every time
- * the yielded thread would have been stepped.
- * @param {!Function} callback To be called when the timer is done.
- * @param {number} timeDelta Time to wait, in ms.
- * @return {number} Timer ID to be used with other methods.
- */
-YieldTimers.timeout = function (callback, timeDelta) {
-    var id = ++YieldTimers.timerId;
-    YieldTimers.timers[id] = [
-        callback,
-        YieldTimers.globalTimer.time() + timeDelta
-    ];
-    return id;
-};
-
-/**
- * Attempt to resolve a timeout.
- * If the time has passed, call the callback.
- * Otherwise, do nothing.
- * @param {number} id Timer ID to resolve.
- * @return {boolean} True if the timer has resolved.
- */
-YieldTimers.resolve = function (id) {
-    var timer = YieldTimers.timers[id];
-    if (!timer) {
-        // No such timer.
-        return false;
-    }
-    var callback = timer[0];
-    var time = timer[1];
-    if (YieldTimers.globalTimer.time() < time) {
-        // Not done yet.
-        return false;
-    }
-    // Execute the callback and remove the timer.
-    callback();
-    delete YieldTimers.timers[id];
-    return true;
-};
-
-module.exports = YieldTimers;

From ec4567aa8ad99b264673a909543186a50009de8c Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Thu, 30 Jun 2016 17:12:16 -0400
Subject: [PATCH 26/27] Simplify logic for Thread status

---
 src/engine/sequencer.js | 22 ++++++++++------------
 src/engine/thread.js    |  9 +++++----
 2 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js
index 5eca9c202..1498d6320 100644
--- a/src/engine/sequencer.js
+++ b/src/engine/sequencer.js
@@ -134,17 +134,10 @@ Sequencer.prototype.stepToReporter = function (thread, blockId, inputName) {
     currentStackFrame.waitingReporter = inputName;
     // Actually execute the block.
     this.startThread(thread);
-    if (thread.status === Thread.STATUS_YIELD ||
-        thread.status === Thread.STATUS_YIELD_BLOCK) {
-        // Reporter yielded; caller must wait for it to unyield.
-        // The value will be populated once the reporter unyields,
-        // and passed up to the currentStackFrame on next execution.
-        return true;
-    } else if (thread.status === Thread.STATUS_DONE) {
-        // Reporter finished, mark the thread as running.
-        thread.status = Thread.STATUS_RUNNING;
-        return false;
-    }
+    // If a reporter yielded, caller must wait for it to unyield.
+    // The value will be populated once the reporter unyields,
+    // and passed up to the currentStackFrame on next execution.
+    return thread.status === Thread.STATUS_YIELD;
 };
 
 /**
@@ -155,7 +148,8 @@ Sequencer.prototype.proceedThread = function (thread) {
     var currentBlockId = thread.peekStack();
     // Mark the status as done and proceed to the next block.
     this.runtime.glowBlock(currentBlockId, false);
-    thread.status = Thread.STATUS_DONE;
+    // If the block was yielding, move back to running state.
+    thread.status = Thread.STATUS_RUNNING;
     // Pop from the stack - finished this level of execution.
     thread.popStack();
     // Push next connected block, if there is one.
@@ -167,6 +161,10 @@ Sequencer.prototype.proceedThread = function (thread) {
     while (thread.peekStack() === null && thread.stack.length > 0) {
         thread.popStack();
     }
+    // If we still can't find a next block to run, mark the thread as done.
+    if (thread.peekStack() === null) {
+        thread.status = Thread.STATUS_DONE;
+    }
 };
 
 module.exports = Sequencer;
diff --git a/src/engine/thread.js b/src/engine/thread.js
index d14d83f90..e5c4df2e4 100644
--- a/src/engine/thread.js
+++ b/src/engine/thread.js
@@ -32,22 +32,23 @@ function Thread (firstBlock) {
 
 /**
  * Thread status for initialized or running thread.
- * Threads are in this state when the primitive is called for the first time.
+ * This is the default state for a thread - execution should run normally,
+ * stepping from block to block.
  * @const
  */
 Thread.STATUS_RUNNING = 0;
 
 /**
  * Thread status for a yielded thread.
- * Threads are in this state when a primitive has yielded.
+ * Threads are in this state when a primitive has yielded; execution is paused
+ * until the relevant primitive unyields.
  * @const
  */
 Thread.STATUS_YIELD = 1;
 
 /**
  * Thread status for a finished/done thread.
- * Thread is moved to this state when the interpreter
- * can proceed with execution.
+ * Thread is in this state when there are no more blocks to execute.
  * @const
  */
 Thread.STATUS_DONE = 2;

From 1c24770f8ca6dba227c4e1033fd43a48ccccbc7c Mon Sep 17 00:00:00 2001
From: Tim Mickel <tim.mickel@gmail.com>
Date: Thu, 30 Jun 2016 17:13:43 -0400
Subject: [PATCH 27/27] Remove debug calls from `execute`

---
 src/engine/execute.js | 25 +------------------------
 1 file changed, 1 insertion(+), 24 deletions(-)

diff --git a/src/engine/execute.js b/src/engine/execute.js
index acff32585..188f0bf52 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -1,11 +1,5 @@
 var Thread = require('./thread');
 
-/**
- * If set, block calls, args, and return values will be logged to the console.
- * @const {boolean}
- */
-var DEBUG_BLOCK_CALLS = true;
-
 /**
  * Execute a block.
  * @param {!Sequencer} sequencer Which sequencer is executing.
@@ -66,11 +60,6 @@ var execute = function (sequencer, thread) {
     // (e.g., on return from a substack) gets fresh inputs.
     currentStackFrame.reported = {};
 
-    if (DEBUG_BLOCK_CALLS) {
-        console.groupCollapsed('Executing: ' + opcode);
-        console.log('with arguments: ', argValues);
-        console.log('and stack frame: ', currentStackFrame);
-    }
     var primitiveReportedValue = null;
     primitiveReportedValue = blockFunction(argValues, {
         yield: thread.yield.bind(thread),
@@ -98,29 +87,17 @@ var execute = function (sequencer, thread) {
         // Promise handlers
         primitiveReportedValue.then(function(resolvedValue) {
             // Promise resolved: the primitive reported a value.
-            if (DEBUG_BLOCK_CALLS) {
-                console.log('reporting value: ', resolvedValue);
-            }
             thread.pushReportedValue(resolvedValue);
             sequencer.proceedThread(thread);
         }, function(rejectionReason) {
             // Promise rejected: the primitive had some error.
             // Log it and proceed.
-            if (DEBUG_BLOCK_CALLS) {
-                console.warn('primitive rejected promise: ', rejectionReason);
-            }
+            console.warn('Primitive rejected promise: ', rejectionReason);
             sequencer.proceedThread(thread);
         });
     } else if (thread.status === Thread.STATUS_RUNNING) {
-        if (DEBUG_BLOCK_CALLS) {
-            console.log('reporting value: ', primitiveReportedValue);
-        }
         thread.pushReportedValue(primitiveReportedValue);
     }
-    if (DEBUG_BLOCK_CALLS) {
-        console.log('ending stack frame: ', currentStackFrame);
-        console.groupEnd();
-    }
 };
 
 module.exports = execute;