diff --git a/test/harness/sth.js b/test/harness/sth.js
index 7ae7d20780918dee8fac89b0d89240e255b8cfff..9053ea6427172ff736c771bed7ff08354ba65370 100644
--- a/test/harness/sth.js
+++ b/test/harness/sth.js
@@ -1,14 +1,14 @@
-/// Copyright (c) 2009 Microsoft Corporation 
-/// 
+/// Copyright (c) 2009 Microsoft Corporation
+///
 /// Redistribution and use in source and binary forms, with or without modification, are permitted provided
-/// that the following conditions are met: 
+/// that the following conditions are met:
 ///    * Redistributions of source code must retain the above copyright notice, this list of conditions and
-///      the following disclaimer. 
-///    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
-///      the following disclaimer in the documentation and/or other materials provided with the distribution.  
+///      the following disclaimer.
+///    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+///      the following disclaimer in the documentation and/or other materials provided with the distribution.
 ///    * Neither the name of Microsoft nor the names of its contributors may be used to
 ///      endorse or promote products derived from this software without specific prior written permission.
-/// 
+///
 /// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 /// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 /// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
@@ -16,7 +16,7 @@
 /// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 /// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 /// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-/// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+/// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 //Do not cache any JSON files - see https://bugs.ecmascript.org/show_bug.cgi?id=87
@@ -52,7 +52,7 @@ function BrowserRunner() {
             if(currentTest.error instanceof SputnikError) {
                 currentTest.error = currentTest.message;
             } else {
-                currentTest.error = currentTest.error.name + ": " + currentTest.error.message
+                currentTest.error = currentTest.error.name + ": " + currentTest.error.message;
             }
         }
 
@@ -94,7 +94,7 @@ function BrowserRunner() {
         // Set up some globals.
         win.testRun = testRun;
         win.testFinished = testFinished;
-        
+
         //TODO: these should be moved to sta.js
         win.SputnikError = SputnikError;
         win.$ERROR = $ERROR;
@@ -112,59 +112,59 @@ function BrowserRunner() {
                     $.ajax({
                         async: false,
                         url: 'resources/scripts/global/' + include,
-                        success: function(s) { scriptCache[include] = s }
-                    })
+                        success: function(s) { scriptCache[include] = s; }
+                    });
                 }
 
                 // Finally, write the required script to the window.
                 doc.writeln("<script type='text/javascript'>" + scriptCache[include] + "</script>");
             }
         }
-           
+
         //Write out all of our helper functions
         doc.writeln("<script type='text/javascript'>" + PickledSimpleTestAPIs + "</script>");
-        
-        
-        
+
+
+
         //--Scenario 1: we're dealing with a global scope test case
         if (GlobalScopeTests[id]!==undefined) {
             win.iframeError = undefined;
             win.onerror = undefined;
             win.onErrorHack = undefined;
             var testDescrip = GlobalScopeTests[id];
-                
+
             //Add an error handler
             doc.writeln("<script type='text/javascript'>window.onerror = function(errorMsg, url, lineNumber) {window.iframeError = errorMsg;};" + "</script>");
             //Parse and execute the code
             doc.writeln("<script type='text/javascript'>onErrorHack = true;try{" + code + "}catch(test262RuntimeError){window.iframeError=test262RuntimeError.message || \"None\";}</script>");
-            
+
             //validation
             if (testDescrip.negative!==undefined) {  //An exception is expected
                 if (win.onErrorHack===undefined) {  //Hack for browsers not supporting window.onerror WRT early parse errors
-                    testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 
+                    testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '',
                             'pass', 'Not parsable');
                 }
                 else if (win.iframeError===undefined) { //no exception was thrown
-                    testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 
+                    testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '',
                             'fail', 'No Exception Thrown');
                 } else if(! (new RegExp(testDescrip.negative, "i").test(win.iframeError))) {  //wrong type of exception thrown
-                    testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 
+                    testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '',
                             'fail', 'Wrong Type of Exception Thrown');
                 } else {
-                    testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 
+                    testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '',
                             'pass', undefined);
                 }
             } else if (win.iframeError!==undefined) {  //Exception was not expected to be thrown
-                testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 
+                testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '',
                         'fail', 'Unexpected Exception');
             } else {
-                testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '', 
+                testRun(testDescrip.id, testDescrip.path, testDescrip.description, code, typeof testDescrip.precondition !== 'undefined' ? testDescrip.precondition.toString() : '',
                         'pass', undefined);
-            }   
+            }
         }
         //--Scenario 2:  we're dealing with a normal positive(?) test case
         else {
-        
+
             // Write ES5Harness.registerTest and fnGlobalObject, which returns the global object, and the testFinished call.
             doc.writeln("<script type='text/javascript'>ES5Harness = {};" +
                         "ES5Harness.registerTest = function(test) {" +
@@ -182,7 +182,7 @@ function BrowserRunner() {
         }
         doc.writeln("<script type='text/javascript'>testFinished();</script>");
         doc.close();
-    }
+    };
 }
 
 /* Loads tests from the sections specified in testcaseslist.json.
@@ -219,9 +219,9 @@ function TestLoader() {
         $.ajax({url: group.path, dataType: 'json', success: function(data) {
             group.tests = data.testsCollection.tests;
             loader.getNextTest();
-        },	
+        },
 	error: function (XMLHttpRequest, textStatus, errorThrown) {
-		//alert(XMLHttpRequest); 
+		//alert(XMLHttpRequest);
 	}
 
 	});
@@ -238,13 +238,13 @@ function TestLoader() {
 
             loader.version    = data.version;
             loader.date       = data.date;
-            loader.totalTests = data.numTests;               
+            loader.totalTests = data.numTests;
 
             for (var i = 0; i < testSuite.length; i++) {
                 testGroups[i] = {
                     path: testSuite[i],
                     tests: []
-                }
+                };
             }
             loader.onInitialized(loader.totalTests, loader.version, loader.date);
             getNextXML();
@@ -271,13 +271,13 @@ function TestLoader() {
             // We're done.
             loader.onTestsExhausted();
         }
-    }
+    };
 
     /* Start over at the beginning */
     this.reset = function() {
         currentTestIndex = 0;
         testGroupIndex = 0;
-    }
+    };
 }
 
 /* Controls test generation and running, and sends results to the presenter. */
@@ -294,22 +294,22 @@ function Controller() {
 
         if(state === 'running')
             setTimeout(loader.getNextTest, 10);
-    }
+    };
 
     loader.onInitialized = function(totalTests, version, date) {
         presenter.setVersion(version);
         presenter.setDate(date);
         presenter.setTotalTests(totalTests);
-    }
+    };
 
     loader.onLoadingNextSection = function(path) {
         presenter.updateStatus("Loading: " + path);
-    }
+    };
 
     loader.onTestReady = function(id, test) {
         presenter.updateStatus("Executing Test: " + id);
         runner.run(id, test);
-    }
+    };
 
     loader.onTestsExhausted = function() {
         state = 'stopped';
@@ -317,27 +317,27 @@ function Controller() {
         elapsed = elapsed/(1000*60);  //minutes
         elapsed = elapsed.toFixed(1);
         presenter.finished(elapsed);
-    }
+    };
 
     this.start = function() {
         state = 'running';
         startTime = new Date();
         loader.getNextTest();
         presenter.started();
-    }
-    
+    };
+
     this.pause = function() {
         elapsed += new Date() - startTime;
         state = 'paused';
         presenter.paused();
-    }
+    };
 
     this.reset = function() {
         startTime = new Date();
         elapsed = 0;
         loader.reset();
         presenter.reset();
-    }
+    };
 
     this.toggle = function() {
         if(state === 'running') {
@@ -345,16 +345,16 @@ function Controller() {
         } else {
             controller.start();
         }
-    }
+    };
 }
 
-var controller = new Controller()
+var controller = new Controller();
 
 /* Helper function which shows if we're in the 'debug' mode of the Test262 site.
-   This mode is only useful for debugging issues with the test harness and 
+   This mode is only useful for debugging issues with the test harness and
    website. */
 function isSiteDebugMode() {
-    var str=window.location.href.substring(window.location.href.indexOf("?")+1)
+    var str=window.location.href.substring(window.location.href.indexOf("?")+1);
     if(str.indexOf("sitedebug") > -1) {
         return true;
     }
@@ -385,7 +385,7 @@ $(function () {
             $(this).attr('targetDiv', '.content-browsers');
         }
 
-        //Attaching the click event to the header tab that shows the respective div of header            
+        //Attaching the click event to the header tab that shows the respective div of header
         $(this).click(function () {
             var target = $(this).attr('targetDiv');
             $('#contentContainer > div:visible').hide();
diff --git a/tools/SputnikConverter/ES5TestCase.cs b/tools/SputnikConverter/ES5TestCase.cs
index db39133a74010e7ccf88cc2176728b0629dfd928..bbe4ba04635f5afb998d2bc9583c54ceebab26ad 100644
--- a/tools/SputnikConverter/ES5TestCase.cs
+++ b/tools/SputnikConverter/ES5TestCase.cs
@@ -139,7 +139,7 @@ namespace Microsoft.Sputnik.Interop.ParserEngine
             }
             FileStream fs = new FileStream(destination.Remove(destination.LastIndexOf("\\")) + globalScopeFileName, FileMode.Create, FileAccess.Write);
             StreamWriter sw = new StreamWriter(fs);
-            sw.Write("this.GlobalScopeTests = this.GlobalScopeTests || new Array();\n");
+            sw.Write("this.GlobalScopeTests = this.GlobalScopeTests || {};\n");
             sw.Flush();
             sw.Close();
             fs.Close();
diff --git a/tools/converter/convert.js b/tools/converter/convert.js
index 7ec555e57c15e95c143999aaa8129950705e58ed..c7be73ffdbe04bb7892cf3e708b0e65e13db3ebb 100644
--- a/tools/converter/convert.js
+++ b/tools/converter/convert.js
@@ -8,6 +8,10 @@
    var t262 = global.t262;
    var platform = t262.platform;
    var regExp = platform.regExp;
+   var toRelPathStr = platform.toRelPathStr;
+   var toPathStr    = platform.toPathStr;
+   var toRelPath    = platform.toRelPath;
+   var toPath       = platform.toPath;
 
    var headerPattern = /(?:(?:\/\/.*)?\s*\n)*/;
    var captureCommentPattern = /\/\*\*?((?:\s|\S)*?)\*\/\s*\n/;
@@ -27,8 +31,9 @@
             /\}\s*\)/, ')',
             /\s*;?(?:\s|\n)*$/);
 
-   var captureFuncBodyPattern =
-     regExp(/^function(?:\s+\w*)?\(\s*\)\s*\{/,
+   // Matches a named function. Captures both the name and the body.
+   var captureFuncNameBodyPattern =
+     regExp(/^function\s+(\w*)\(\s*\)\s*\{/,
             '(', anyPattern, ')',
             /;?/, blanksPattern,
             /\}$/);
@@ -80,8 +85,10 @@
        propTexts.forEach(function(propText) {
          var propName = propText.match(/^\w+/)[0];
          var propVal = propText.substring(propName.length);
-         var propMatch = /^:?([^;]*);?\s*$/.exec(propVal);
-         if (propMatch) { propVal = propMatch[1]; }
+         // strip optional initial colon or final semicolon.
+         // The initial colon is only stripped if it comes immediately
+         // after the identifier with no intervening whitespace.
+         propVal = propVal.replace(/^:\s*/, '').replace(/;\s*$/, '');
          propVal = stripStars(propVal);
          if (propName in envelope.testRecord) {
            throw new Error('duplicate: ' + propName);
@@ -106,27 +113,49 @@
    }
 
    /**
-    * Given a function, return the source for an expression that, when
-    * evaluated in the environment the function assumes, will behave
-    * the same as calling that function in that environment.
+    * Given a function that indicates success by returning a truthy
+    * value, return the source for a Program that, when evaluated in
+    * the environment the function assumes, will behave the same as
+    * calling that function in that environment and asserting the
+    * truthiness of the result.
+    *
+    * <p>Programs do not conveniently return any value, even their
+    * completion value, so Programs in canonical test262 style instead
+    * indicate success simply by completing normally, i.e., without
+    * throwing anything. The convertion assumes a one argument
+    * <code>assertTrue</code> function which throws an indication of
+    * test failure iff given a falsy argument.
+    *
+    * <p>Unless it specifies otherwise, the Program source may be
+    * executed strict and/or non-strict, and it may be exeuted within
+    * the try block of a try/catch or try/catch finally, i.e., as a
+    * Block rather than as a Program.
     */
-   function expressionize(func) {
+   function functionToProgramSrc(func) {
      var funcSrc = '' + func;
-     var cfbMatch = captureFuncBodyPattern.exec(funcSrc);
-     if (cfbMatch) {
-       // Look for special cases
-       var body = cfbMatch[1].trim();
+     var cfnbMatch = captureFuncNameBodyPattern.exec(funcSrc);
+     if (!cfnbMatch) {
+       throw new Error('Could not recognize: "' + funcSrc + '"');
+     }
+     var name = cfnbMatch[1].trim();
+     var body = cfnbMatch[2].trim();
 
-       var cebMatch = captureExprBodyPattern.exec(body);
-       if (cebMatch) { return '(' + cebMatch[1].trim() + ')'; }
+     // Look for special cases
 
-       var cpMatch = capturePredicatePattern.exec(body);
-       if (cpMatch) { return '(' + cpMatch[1].trim() + ')'; }
+     var cebMatch = captureExprBodyPattern.exec(body);
+     if (cebMatch) {
+       return 'assertTrue(' + cebMatch[1].trim() + ');';
+     }
 
-     } else {
-       // signal an error?
+     var cpMatch = capturePredicatePattern.exec(body);
+     if (cpMatch) {
+       return 'assertTrue(' + cpMatch[1].trim() + ');';
      }
-     return '(' + funcSrc + ').call(this)';
+
+     // General case
+
+     return funcSrc + '\n' +
+       'assertTrue(' + name + '.call(this));';
    }
 
    /**
@@ -158,27 +187,25 @@
                         'forceNonStrict');
 
      if (testRecords.length !== 1) {
-       // We plan to lift this restriction in order to support test
+       // We may lift this restriction in order to support test
        // generators.
        throw new Error('not singleton: ' + name);
      }
      var testRecord = testRecords[0];
 
      if (typeof testRecord.test === 'function') {
-       testRecord.test = envelope.rest +
-         'assertTrue(' + expressionize(testRecord.test) + ');\n';
+       testRecord.test = envelope.rest + '\n' +
+         functionToProgramSrc(testRecord.test);
      }
-     if (typeof testRecord.precondition === 'function') {
-       var precondition = expressionize(testRecord.precondition);
-       if (precondition === '(true)') {
-         delete testRecord.precondition;
-       } else {
-         testRecord.precondition = precondition;
-       }
+     if ('precondition' in testRecord) {
+       // Only ietestcenter tests currently have preconditions, and they
+       // plan to drop them. So canonical test262 style omits
+       // them.
+       delete testRecord.precondition;
      }
 
      return testRecord;
-   };
+   }
 
    /**
     * Normalizes the properties of testRecord to be the canonical
@@ -186,11 +213,6 @@
     * runners.
     */
    function normalizeProps(testRecord) {
-     if (!testRecord.id && testRecord.name) {
-       testRecord.id = testRecord.name;
-       delete testRecord.name;
-     }
-
      if (!('strict_only' in testRecord) && testRecord.strict === 1) {
        testRecord.strict_only = '';
        delete testRecord.strict;
@@ -206,6 +228,8 @@
        }
      }
 
+     // Note that testRecord.negative is falsy whether negative is
+     // absent or empty.
      if (!testRecord.negative && 'errortype' in testRecord) {
        testRecord.negative = testRecord.errortype;
        delete testRecord.errortype;
@@ -219,19 +243,22 @@
        testRecord.comment = testRecord.assertion;
        delete testRecord.assertion;
      }
-   };
+   }
    t262.normalizeProps = normalizeProps;
 
    /**
     * Parses the source of a test262 test case file into a normalized
     * JSON test record.
     */
-   function parseTestRecord(path, name) {
-     var nextPath = path.concat([name]);
+   function parseTestRecord(inBase, relPath, name) {
+     var nextRelPath = relPath.concat([name]);
+     var nextPath = inBase.concat(nextRelPath);
 
      var src = platform.read(nextPath);
      var testRecord;
-     if (!src) { throw new Error('no src: ' + nextPath.join('/')); }
+     if (!src) {
+       throw new Error('no src: ' + toPathStr(nextPath));
+     }
      var envelope = parseTestEnvelope(src, name);
 
      if (envelope.registerExpr) {
@@ -242,16 +269,19 @@
          testRecord.test = envelope.rest;
        }
      }
+     delete testRecord.id;
+     delete testRecord.name;
+     testRecord.path = toRelPathStr(nextRelPath);
      testRecord.header = envelope.header;
      testRecord.comment = envelope.comment;
 
      normalizeProps(testRecord);
      return testRecord;
-   };
+   }
    t262.parseTestRecord = parseTestRecord;
 
    // The known ones will be rendered first, and in this order.
-   var KNOWN_PROPS = ['id', 'section', 'path', 'description',
+   var KNOWN_PROPS = ['section', 'path', 'description',
                       'strict_only', 'negative'];
 
    /**
@@ -283,30 +313,31 @@
        result += ' * ' + testRecord.comment.replace(/\n/g, '\n * ') + '\n *\n';
      }
      delete testRecord.comment;
-     KNOWN_PROPS.concat(['precondition']).forEach(addProp);
+     KNOWN_PROPS.forEach(addProp);
      Object.keys(testRecord).forEach(addProp);
      result += ' */\n\n' + test;
      return result;
-   };
+   }
    t262.formatTestRecord = formatTestRecord;
 
    /**
     * Reads the test case at pathStr and returns the source of that
     * test case converted to canonical test262 style.
     */
-   function convertTest(pathStr) {
-     var path = platform.toPath(pathStr);
-     var name = path.pop();
-     var testRecord = parseTestRecord(path, name);
+   function convertTest(inBaseStr, relPathStr) {
+     var inBase = toPath(inBaseStr);
+     var relPath = platform.toRelPath(relPathStr);
+     var name = relPath.pop();
+     var testRecord = parseTestRecord(inBase, relPath, name);
      var result = formatTestRecord(testRecord);
      return result;
-   };
+   }
    t262.convertTest = convertTest;
 
    var SRC_DIRS = [
      ['test', 'suite', 'other'],
-     ['test', 'suite', 'sputnik', 'Conformance'],
-     ['test', 'suite', 'ietestcenter']
+     ['test', 'suite', 'ietestcenter'],
+     ['test', 'suite', 'sputnik', 'Conformance']
    ];
 
    var CONV_DIR = ['test', 'suite', 'converted'];
@@ -315,6 +346,8 @@
 
    var ME_PATH = platform.CONVERTER_PATH.concat('convert.js');
 
+   var writeSpawnFailures = [];
+
    /**
     * Convert all the testcases found at inBase+relDir to test cases
     * in canonical test262 style, to be stored at corresponding
@@ -329,27 +362,43 @@
        if (platform.isDirectory(inBase.concat(nextRelPath))) {
          convertAll(inBase, outBase, nextRelPath);
        } else if (/\.js$/.test(name)) {
-         var inFilePath = inPath.concat([name]);
          var outFilePath = outPath.concat([name]);
-         platform.writeSpawn(
-           [ME_PATH],
-           't262.convertTest("' + platform.toPathStr(inFilePath) + '")',
-           void 0,
-           outFilePath);
+         try {
+           platform.writeSpawn(
+             [ME_PATH],
+             't262.convertTest("' + toPathStr(inBase) +
+               '", "' + toRelPathStr(nextRelPath) + '")',
+             void 0,
+             outFilePath);
+         } catch (err) {
+           writeSpawnFailures.push({
+             error: err,
+             relPath: relPath
+           });
+         }
        }
      });
-   };
+   }
    t262.convertAll = convertAll;
 
    /**
     * Do all the conversions (from sputnik style, ietestcenter style,
     * or other to canonical test262 style) matching relPath.
     */
-   function convert(opt_relPath) {
+   function convert(opt_relPathStr) {
+     var relPath = opt_relPathStr ? toRelPath(opt_relPathStr) : [];
+     writeSpawnFailures = [];
      SRC_DIRS.forEach(function(srcDir) {
-       convertAll(srcDir, CONV_DIR, opt_relPath || []);
+       convertAll(srcDir, CONV_DIR, relPath);
      });
-   };
+     if (writeSpawnFailures.length >= 1) {
+       print('********* failures **********');
+       writeSpawnFailures.forEach(function(failure) {
+         print(failure.error + ': ' + toRelPathStr(failure.relPath));
+       });
+       throw writeSpawnFailures[0].error;
+     }
+   }
    t262.convert = convert;
 
    /**
@@ -359,7 +408,7 @@
     * runner.
     */
    function buildSection(pathStr) {
-     var path = platform.toPath(pathStr);
+     var path = toPath(pathStr);
      if (!platform.isDirectory(path)) { throw new Error('not dir: ' + path); }
 
      var jsFiles = platform.ls(path).filter(function(name) {
@@ -382,7 +431,7 @@
          tests: testRecords
        }
      };
-   };
+   }
    t262.buildSection = buildSection;
 
    /**
@@ -403,14 +452,21 @@
      if (hasJS) {
        var name = relPath[relPath.length -1] + '.json';
        var outFilePath = outBase.concat([name]);
-       platform.writeSpawn(
-         [ME_PATH],
-         't262.asJSONTxt(t262.buildSection("' +
-           platform.toPathStr(inPath) + '"))',
-         void 0,
-         outFilePath);
+       try {
+         platform.writeSpawn(
+           [ME_PATH],
+           't262.asJSONTxt(t262.buildSection("' +
+             toPathStr(inPath) + '"))',
+           void 0,
+           outFilePath);
+       } catch (err) {
+         writeSpawnFailures.push({
+           error: err,
+           path: relPath
+         });
+       }
      }
-   };
+   }
    t262.buildAll = buildAll;
 
    /**
@@ -421,12 +477,13 @@
     * files. Once we switch over to converted as the maintained
     * sources, we should change this.
     */
-   function buildWebSite(opt_relPath) {
+   function buildWebSite(opt_relPathStr) {
+     var relPath = opt_relPathStr ? toRelPath(opt_relPathStr) : [];
      SRC_DIRS.forEach(function(srcDir) {
-       buildAll(srcDir, OUT_DIR, opt_relPath || []);
+       buildAll(srcDir, OUT_DIR, relPath);
      });
-//     buildAll(CONV_DIR, OUT_DIR, opt_relPath || []);
-   };
+//     buildAll(CONV_DIR, OUT_DIR, relPath);
+   }
    t262.buildWebSite = buildWebSite;
 
  })(this);
diff --git a/tools/converter/v8PosixPlatform.js b/tools/converter/v8PosixPlatform.js
index 069deb59c1e21ba96898515b3aa7499d66a266c0..f9b01645d88baa1a003235b7ee989577ad99b823 100644
--- a/tools/converter/v8PosixPlatform.js
+++ b/tools/converter/v8PosixPlatform.js
@@ -34,11 +34,16 @@
    /**
     * Appends a bunch of RegExps together into a single RegExp,
     * solving both the RegExp-one-liner problem and the doubled
-    * backslash problem when composing literal string.
+    * backslash problem when composing literal strings.
     *
-    * <p>The arguments can be any mixture of RegExps and strings. The
-    * strings are added as is without escaping -- BEWARE. If
-    * arguments[0] is a RegExp, we use its flag on the resuting RegExp.
+    * <p>The arguments can be any mixture of RegExps and strings. By
+    * expressing the portions that should be well formed regexps as
+    * regexps, we catch well-formedness errors within such a portion
+    * separately. The strings are added as is without escaping --
+    * BEWARE. By not escaping the strings, we can use them to
+    * represent the individually unbalanced fragments, like capturing
+    * parens, around other regexps. If arguments[0] is a RegExp, we
+    * use its flags on the resuting RegExp.
     *
     * <p>Not platform dependent, so does not really belong in this
     * file.
@@ -95,23 +100,39 @@
      return path;
    }
 
+   /**
+    * Converts a relPath to a relPathStr.
+    *
+    * A relPath is an array of filenames relative to some base onto
+    * which it will be concatenated before use.
+    */
+   function toRelPathStr(relPath) {
+     validatePath(relPath);
+     return relPath.join('/');
+   }
+   platform.toRelPathStr = toRelPathStr;
+
    /**
     * Converts a path to a pathStr.
     *
     * A path is an array of filenames relative to TEST262_ROOT. A
     * pathStr is a (possibly fully qualified string) for referring to
-    * that string on the current platform, according to the operations
+    * that file on the current platform, according to the operations
     * in this *Platform.js file.
     */
    function toPathStr(path) {
      validatePath(path);
      return TEST262_ROOT.concat(path).join('/');
-   };
+   }
    platform.toPathStr = toPathStr;
 
    /**
     * Returns the text found at path, with newlines normalized and
     * any initial BOM (Unicode Byte Order Mark) removed.
+    *
+    * Note: Don't simply revise this (without renamings) to follow the
+    * general pattern of also defining a local 'read' function, as it
+    * will mask the v8 shell's read function, which we use.
     */
    platform.read = function(path) {
      var text = read(toPathStr(path)).
@@ -153,12 +174,12 @@
     * @returns If there is a target, then the null string. Otherwise,
     * the string result of evaluating opt_exprSrc.
     */
-   platform.writeSpawn = function(scriptPaths,
-                                  opt_exprSrc,
-                                  opt_args,
-                                  opt_targetPath,
-                                  opt_spawn_required,
-                                  opt_forceNonStrict) {
+   function writeSpawn(scriptPaths,
+                       opt_exprSrc,
+                       opt_args,
+                       opt_targetPath,
+                       opt_spawn_required,
+                       opt_forceNonStrict) {
      if (opt_exprSrc && !opt_targetPath && !opt_spawn_required) {
        var str = '(function(/*var_args*/) {';
        if (opt_forceNonStrict !== 'forceNonStrict') {
@@ -182,8 +203,21 @@
      }
      if (VERBOSE || DRY_RUN) { print(cmd); }
      if (DRY_RUN) { return ''; }
-     return os.system('bash', ['-c', cmd]);
-   };
+     try {
+       return os.system('bash', ['-c', cmd]);
+     } catch (err) {
+       if (opt_targetPath) {
+         // The error we catch is almost certainly less interesting
+         // than the one unfortunately written to the target file.
+         var message = 'failed: ' + cmd + '\n' +
+           platform.read(opt_targetPath);
+         os.system('rm', [toPathStr(opt_targetPath)]);
+         throw new Error(message);
+       }
+       throw err;
+     }
+   }
+   platform.writeSpawn = writeSpawn;
 
    ////////////////// Only needed for building /////////////////////
 
@@ -193,7 +227,7 @@
     * On platforms (like SES) where this can be a safely confining
     * evaluation, it should be. The implementation here is not safe.
     */
-   platform.evalExprIn = function(exprSrc, env, opt_forceNonStrict) {
+   function evalExprIn(exprSrc, env, opt_forceNonStrict) {
      var varNames = Object.getOwnPropertyNames(env);
      var str = '(function(' + varNames.join(',') + ') {';
      if (opt_forceNonStrict !== 'forceNonStrict') {
@@ -203,12 +237,23 @@
      return (1,eval)(str).apply(void 0, varNames.map(function(varName) {
        return env[varName];
      }));
-   };
+   }
+   platform.evalExprIn = evalExprIn;
+
+   /**
+    * Converts a relPathStr to a relPath.
+    *
+    * <p>See toRelPathStr.
+    */
+   function toRelPath(relPathStr) {
+     return validatePath(relPathStr.split('/'));
+   }
+   platform.toRelPath = toRelPath;
 
    /**
     * Converts a pathStr to a path.
     *
-    * See toPathStr.
+    * <p>See toPathStr.
     */
    function toPath(pathStr) {
      if (pathStr[0] === '/') {
@@ -225,24 +270,38 @@
    /**
     * Does path name a directory?
     */
-   platform.isDirectory = function(path) {
-     var fileOut = os.system('file', [toPathStr(path)]);
-     var fileMatch = fileOut.match(/:\s*([^:]*)\s*$/);
-     if (!fileMatch) { return null; }
-     var fileType = fileMatch[1].trim();
-     return fileType === 'directory';
-   };
+   function isDirectory(path) {
+//     var fileOut = os.system('file', [toPathStr(path)]);
+//     var fileMatch = fileOut.match(/:\s*([^:]*)\s*$/);
+//     if (!fileMatch) { return null; }
+//     var fileType = fileMatch[1].trim();
+//     return fileType === 'directory';
+     try {
+       os.system('test', ['-d', toPathStr(path)]);
+       return true;
+     } catch (x) {
+       return false;
+     }
+   }
+   platform.isDirectory = isDirectory;
 
    /**
     * A list of the filenames found in path, which must name a
     * directory.
     */
-   platform.ls = function(path) {
+   function ls(path) {
      var pathStr = toPathStr(path);
-     var lines = os.system('ls', [pathStr]).trim();
+     if (!isDirectory(path)) { return []; }
+     var lines;
+     try {
+       lines = os.system('ls', [pathStr]).trim();
+     } catch (err) {
+       throw err;
+     }
      if (lines === '') { return []; }
      return lines.split('\n');
-   };
+   }
+   platform.ls = ls;
 
    /**
     * Emits the jsonRecord serialized as JSON, either compactly or
@@ -257,7 +316,7 @@
    }
    global.t262.asJSONTxt = platform.asJSONTxt = asJSONTxt;
 
-   platform.mkdir = function(path) {
+   function mkdir(path) {
      var pathStr = toPathStr(path);
      if (DRY_RUN) {
        print('mkdir ' + pathStr);
@@ -269,7 +328,8 @@
        print('***could not mkdir: ' + pathStr);
        throw err;
      }
-   };
+   }
+   platform.mkdir = mkdir;
 
    ////////////////// Only needed for running //////////////////////