Bug 1217077 - Remove for-each from services/. r=gps
authorTooru Fujisawa <arai_a@mac.com>
Mon, 19 Oct 2015 03:52:58 +0900
changeset 306995 1de5ecadcceebb00801baeddabbb76f140a85d66
parent 306994 9aab415d2bd9b8ee29f71e3a7b3bd7616bb006be
child 306996 16d3dd16ef70f798a325b64152aa440c3e1cbd9b
push id7225
push usermjzffr@gmail.com
push dateThu, 05 Nov 2015 20:58:39 +0000
reviewersgps
bugs1217077
milestone45.0a1
Bug 1217077 - Remove for-each from services/. r=gps
services/cloudsync/CloudSyncBookmarks.jsm
services/cloudsync/CloudSyncEventSource.jsm
services/cloudsync/CloudSyncPlacesWrapper.jsm
services/cloudsync/CloudSyncTabs.jsm
services/common/async.js
services/common/modules-testing/storageserver.js
services/common/stringbundle.js
services/common/tests/mach_commands.py
services/common/tests/unit/head_global.js
services/common/tests/unit/test_load_modules.js
services/common/tests/unit/test_tokenserverclient.js
services/common/utils.js
services/crypto/modules/utils.js
services/crypto/tests/unit/test_load_modules.js
services/metrics/providermanager.jsm
services/sync/modules/addonsreconciler.js
services/sync/modules/addonutils.js
services/sync/modules/engines.js
services/sync/modules/engines/addons.js
services/sync/modules/engines/bookmarks.js
services/sync/modules/engines/clients.js
services/sync/modules/engines/history.js
services/sync/modules/engines/passwords.js
services/sync/modules/engines/prefs.js
services/sync/modules/engines/tabs.js
services/sync/modules/identity.js
services/sync/modules/jpakeclient.js
services/sync/modules/record.js
services/sync/modules/service.js
services/sync/modules/stages/declined.js
services/sync/modules/stages/enginesync.js
services/sync/tests/unit/head_appinfo.js
services/sync/tests/unit/head_http_server.js
services/sync/tests/unit/test_addons_reconciler.js
services/sync/tests/unit/test_addons_store.js
services/sync/tests/unit/test_bookmark_store.js
services/sync/tests/unit/test_clients_engine.js
services/sync/tests/unit/test_collections_recovery.js
services/sync/tests/unit/test_jpakeclient.js
services/sync/tests/unit/test_resource.js
services/sync/tests/unit/test_resource_async.js
services/sync/tests/unit/test_service_startup.js
services/sync/tests/unit/test_status.js
services/sync/tests/unit/test_tab_tracker.js
services/sync/tps/extensions/mozmill/resource/driver/controller.js
services/sync/tps/extensions/mozmill/resource/driver/elementslib.js
services/sync/tps/extensions/mozmill/resource/modules/frame.js
services/sync/tps/extensions/mozmill/resource/stdlib/os.js
services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js
services/sync/tps/extensions/mozmill/resource/stdlib/utils.js
services/sync/tps/extensions/tps/resource/modules/history.jsm
services/sync/tps/extensions/tps/resource/modules/tabs.jsm
services/sync/tps/extensions/tps/resource/tps.jsm
--- a/services/cloudsync/CloudSyncBookmarks.jsm
+++ b/services/cloudsync/CloudSyncBookmarks.jsm
@@ -549,44 +549,44 @@ var RootFolder = function (rootId, rootN
           }
         } else if (item.__exists__ && item.deleted) {
           deletedItems.push(item);
         } else if (item.__exists__) {
           updatedItems.push(item);
         }
       }
 
-      for each (let item in items) {
+      for (let item of items) {
         if (!item || 'object' !== typeof(item)) {
           continue;
         }
 
         let promise = exists(item).then(handleSortedItem, Promise.reject);
         promises.push(promise);
       }
 
       return Promise.all(promises);
     }
 
     let processNewFolders = function () {
       let newFolderGuids = Object.keys(newFolders);
       let newFolderRoots = [];
 
-      for each (let guid in newFolderGuids) {
+      for (let guid of newFolderGuids) {
         let item = newFolders[guid];
         if (item.parent && newFolderGuids.indexOf(item.parent) >= 0) {
           let parent = newFolders[item.parent];
           parent._children.push(item.id);
         } else {
           newFolderRoots.push(guid);
         }
       };
 
       let promises = [];
-      for each (let guid in newFolderRoots) {
+      for (let guid of newFolderRoots) {
         let root = newFolders[guid];
         let promise = Promise.resolve();
         promise = promise.then(
           function () {
             return _createItem(root);
           },
           Promise.reject
         );
@@ -606,25 +606,25 @@ var RootFolder = function (rootId, rootN
       }
 
       return Promise.all(promises);
     }
 
     let processItems = function () {
       let promises = [];
 
-      for each (let item in newItems) {
+      for (let item of newItems) {
         promises.push(_createItem(item));
       }
 
-      for each (let item in updatedItems) {
+      for (let item of updatedItems) {
         promises.push(_updateItem(item));
       }
 
-      for each (let item in deletedItems) {
+      for (let item of deletedItems) {
         _deleteItem(item);
       }
 
       return Promise.all(promises);
     }
 
     sortItems().then(processNewFolders)
                .then(processItems)
--- a/services/cloudsync/CloudSyncEventSource.jsm
+++ b/services/cloudsync/CloudSyncEventSource.jsm
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 this.EXPORTED_SYMBOLS = ["EventSource"];
 
 Components.utils.import("resource://services-common/utils.js");
 
 var EventSource = function (types, suspendFunc, resumeFunc) {
   this.listeners = new Map();
-  for each (let type in types) {
+  for (let type of types) {
     this.listeners.set(type, new Set());
   }
 
   this.suspend = suspendFunc || function () {};
   this.resume = resumeFunc || function () {};
 
   this.addEventListener = this.addEventListener.bind(this);
   this.removeEventListener = this.removeEventListener.bind(this);
--- a/services/cloudsync/CloudSyncPlacesWrapper.jsm
+++ b/services/cloudsync/CloudSyncPlacesWrapper.jsm
@@ -135,17 +135,17 @@ PlacesWrapper.prototype = {
 
     query.params.parent_id = folder;
     query.params.item_type = PlacesUtils.bookmarks.TYPE_FOLDER;
 
     this.asyncQuery(query, ["id", "guid"]).then(
       function (items) {
         let previousIds = folderCache.getChildren(folder);
         let currentIds = new Set();
-        for each (let item in items) {
+        for (let item of items) {
           currentIds.add(item.id);
         }
         let newIds = new Set();
         let missingIds = new Set();
 
         for (let currentId of currentIds) {
           if (!previousIds.has(currentId)) {
             newIds.add(currentId);
@@ -183,17 +183,17 @@ PlacesWrapper.prototype = {
                "WHERE n.name = :anno_name";
     let query = this.placesQueries.getQuery(stmt);
 
     query.params.anno_name = anno.toString();
 
     this.asyncQuery(query, ["item_id"])
         .then(function (items) {
                 let results = [];
-                for each(let item in items) {
+                for (let item of items) {
                   results.push(item.item_id);
                 }
                 deferred.resolve(results);
               },
               deferred.reject);
 
     return deferred.promise;
   },
@@ -206,17 +206,17 @@ PlacesWrapper.prototype = {
                "WHERE b.item_id = :item_id";
     let query = this.placesQueries.getQuery(stmt);
 
     query.params.item_id = id;
 
     this.asyncQuery(query, ["name", "content"])
         .then(function (results) {
                 let annos = {};
-                for each(let result in results) {
+                for (let result of results) {
                   annos[result.name] = result.content;
                 }
                 deferred.resolve(annos);
               },
               deferred.reject);
 
     return deferred.promise;
   },
@@ -342,17 +342,17 @@ PlacesWrapper.prototype = {
       handleResult: function (results) {
         if (!names) {
           return;
         }
 
         let row;
         while ((row = results.getNextRow()) != null) {
           let item = {};
-          for each (let name in names) {
+          for (let name of names) {
             item[name] = row.getResultByName(name);
           }
           this.results.push(item);
         }
       },
 
       handleError: function (error) {
         deferred.reject(error);
--- a/services/cloudsync/CloudSyncTabs.jsm
+++ b/services/cloudsync/CloudSyncTabs.jsm
@@ -82,17 +82,17 @@ TabCache.prototype = {
       } catch (e) {
         throw new Error("unable to update client: " + e);
       }
     } else {
       cRecord = new ClientRecord(client);
       this.clients.set(cRecord.id, cRecord);
     }
 
-    for each (let tab in tabs) {
+    for (let tab of tabs) {
       if (!tab || 'object' !== typeof(tab)) {
         continue;
       }
 
       let tRecord;
       if (this.tabs.has(tab.url)) {
         tRecord = this.tabs.get(tab.url);
         try {
@@ -153,25 +153,25 @@ this.Tabs = function () {
         return;
       }
     }
 
     eventSource.emit("change");
   };
 
   let registerListenersForWindow = function (window) {
-    for each (let topic in topics) {
+    for (let topic of topics) {
       window.addEventListener(topic, update, false);
     }
     window.addEventListener("unload", unregisterListeners, false);
   };
 
   let unregisterListenersForWindow = function (window) {
     window.removeEventListener("unload", unregisterListeners, false);
-    for each (let topic in topics) {
+    for (let topic of topics) {
       window.removeEventListener(topic, update, false);
     }
   };
 
   let unregisterListeners = function (event) {
     unregisterListenersForWindow(event.target);
   };
 
--- a/services/common/async.js
+++ b/services/common/async.js
@@ -172,17 +172,17 @@ this.Async = {
         return;
       }
       if (!this.results) {
         this.results = [];
       }
       let row;
       while ((row = results.getNextRow()) != null) {
         let item = {};
-        for each (let name in this.names) {
+        for (let name of this.names) {
           item[name] = row.getResultByName(name);
         }
         this.results.push(item);
       }
     },
     handleError: function handleError(error) {
       this.syncCb.throw(error);
     },
--- a/services/common/modules-testing/storageserver.js
+++ b/services/common/modules-testing/storageserver.js
@@ -97,17 +97,17 @@ ServerBSO.prototype = {
     "payload",
     "ttl",
     "sortindex",
   ],
 
   toJSON: function toJSON() {
     let obj = {};
 
-    for each (let key in this.FIELDS) {
+    for (let key of this.FIELDS) {
       if (this[key] !== undefined) {
         obj[key] = this[key];
       }
     }
 
     return obj;
   },
 
@@ -301,17 +301,17 @@ StorageServerCollection.prototype = {
 
   set timestamp(timestamp) {
     CommonUtils.ensureMillisecondsTimestamp(timestamp);
     this._timestamp = timestamp;
   },
 
   get totalPayloadSize() {
     let size = 0;
-    for each (let bso in this.bsos()) {
+    for (let bso of this.bsos()) {
       size += bso.payload.length;
     }
 
     return size;
   },
 
   /**
    * Convenience accessor for our BSO keys.
@@ -436,17 +436,18 @@ StorageServerCollection.prototype = {
         c++;
       }
     }
     return c;
   },
 
   get: function get(options) {
     let data = [];
-    for each (let bso in this._bsos) {
+    for (let id in this._bsos) {
+      let bso = this._bsos[id];
       if (!bso.modified) {
         continue;
       }
 
       if (!this._inResultSet(bso, options)) {
         continue;
       }
 
@@ -499,17 +500,17 @@ StorageServerCollection.prototype = {
   post: function post(input, timestamp) {
     let success = [];
     let failed = {};
     let count = 0;
     let size = 0;
 
     // This will count records where we have an existing ServerBSO
     // registered with us as successful and all other records as failed.
-    for each (let record in input) {
+    for (let record of input) {
       count += 1;
       if (count > this.BATCH_MAX_COUNT) {
         failed[record.id] = "Max record count exceeded.";
         continue;
       }
 
       if (typeof(record.payload) != "string") {
         failed[record.id] = "Payload is not a string!";
@@ -597,17 +598,17 @@ StorageServerCollection.prototype = {
       }
     }
     return deleted;
   },
 
   parseOptions: function parseOptions(request) {
     let options = {};
 
-    for each (let chunk in request.queryString.split("&")) {
+    for (let chunk of request.queryString.split("&")) {
       if (!chunk) {
         continue;
       }
       chunk = chunk.split("=");
       let key = decodeURIComponent(chunk[0]);
       if (chunk.length == 1) {
         options[key] = "";
       } else {
@@ -651,17 +652,17 @@ StorageServerCollection.prototype = {
   getHandler: function getHandler(request, response) {
     let options = this.parseOptions(request);
     let data = this.get(options);
 
     if (request.hasHeader("x-if-modified-since")) {
       let requestModified = parseInt(request.getHeader("x-if-modified-since"),
                                      10);
       let newestBSO = 0;
-      for each (let bso in data) {
+      for (let bso of data) {
         if (bso.modified > newestBSO) {
           newestBSO = bso.modified;
         }
       }
 
       if (requestModified >= newestBSO) {
         response.setHeader("X-Last-Modified", "" + newestBSO);
         response.setStatusLine(request.httpVersion, 304, "Not Modified");
@@ -741,17 +742,17 @@ StorageServerCollection.prototype = {
         throw HTTP_400;
       }
 
       if (!Array.isArray(input)) {
         this._log.info("Input JSON type not an array!");
         return sendMozSvcError(request, response, "8");
       }
     } else if (inputMediaType == "application/newlines") {
-      for each (let line in inputBody.split("\n")) {
+      for (let line of inputBody.split("\n")) {
         let record;
         try {
           record = JSON.parse(line);
         } catch (ex) {
           this._log.info("JSON parse error on line!");
           return sendMozSvcError(request, response, "8");
         }
 
@@ -1073,17 +1074,18 @@ StorageServer.prototype = {
    * @param username
    *        The name of the affected user.
    */
   deleteCollections: function deleteCollections(username) {
     if (!(username in this.users)) {
       throw new Error("Unknown user.");
     }
     let userCollections = this.users[username].collections;
-    for each (let [name, coll] in Iterator(userCollections)) {
+    for (let name in userCollections) {
+      let coll = userCollections[name];
       this._log.trace("Bulk deleting " + name + " for " + username + "...");
       coll.delete({});
     }
     this.users[username].collections = {};
   },
 
   getQuota: function getQuota(username) {
     if (!(username in this.users)) {
@@ -1094,17 +1096,18 @@ StorageServer.prototype = {
   },
 
   /**
    * Obtain the newest timestamp of all collections for a user.
    */
   newestCollectionTimestamp: function newestCollectionTimestamp(username) {
     let collections = this.users[username].collections;
     let newest = 0;
-    for each (let collection in collections) {
+    for (let name in collections) {
+      let collection = collections[name];
       if (collection.timestamp > newest) {
         newest = collection.timestamp;
       }
     }
 
     return newest;
   },
 
@@ -1144,17 +1147,19 @@ StorageServer.prototype = {
       data[k] = v.totalPayloadSize;
     }
 
     return data;
   },
 
   infoQuota: function infoQuota(username) {
     let total = 0;
-    for each (let value in this.infoUsage(username)) {
+    let usage = this.infoUsage(username);
+    for (let key in usage) {
+      let value = usage[key];
       total += value;
     }
 
     return {
       quota: this.getQuota(username),
       usage: total
     };
   },
@@ -1186,19 +1191,21 @@ StorageServer.prototype = {
       modified:          modified,
       quota:             quota,
     };
   },
 
   _pruneExpired: function _pruneExpired() {
     let now = Date.now();
 
-    for each (let user in this.users) {
-      for each (let collection in user.collections) {
-        for each (let bso in collection.bsos()) {
+    for (let username in this.users) {
+      let user = this.users[username];
+      for (let name in user.collections) {
+        let collection = user.collections[name];
+        for (let bso of collection.bsos()) {
           // ttl === 0 is a special case, so we can't simply !ttl.
           if (typeof(bso.ttl) != "number") {
             continue;
           }
 
           let ttlDate = bso.modified + (bso.ttl * 1000);
           if (ttlDate < now) {
             this._log.info("Deleting BSO because TTL expired: " + bso.id);
@@ -1235,17 +1242,21 @@ StorageServer.prototype = {
   defaultHeaders: {},
 
   /**
    * HTTP response utility.
    */
   respond: function respond(req, resp, code, status, body, headers, timestamp) {
     this._log.info("Response: " + code + " " + status);
     resp.setStatusLine(req.httpVersion, code, status);
-    for each (let [header, value] in Iterator(headers || this.defaultHeaders)) {
+    if (!headers) {
+      headers = this.defaultHeaders;
+    }
+    for (let header in headers) {
+      let value = headers[header];
       resp.setHeader(header, value, false);
     }
 
     if (timestamp) {
       resp.setHeader("X-Timestamp", "" + timestamp, false);
     }
 
     if (body) {
--- a/services/common/stringbundle.js
+++ b/services/common/stringbundle.js
@@ -19,17 +19,17 @@ var {classes: Cc, interfaces: Ci, result
  * To use this module, import it, create a new instance of StringBundle,
  * and then use the instance's |get| and |getAll| methods to retrieve strings
  * (you can get both plain and formatted strings with |get|):
  *
  *   let strings =
  *     new StringBundle("chrome://example/locale/strings.properties");
  *   let foo = strings.get("foo");
  *   let barFormatted = strings.get("bar", [arg1, arg2]);
- *   for each (let string in strings.getAll())
+ *   for (let string of strings.getAll())
  *     dump (string.key + " = " + string.value + "\n");
  *
  * @param url {String}
  *        the URL of the string bundle
  */
 this.StringBundle = function StringBundle(url) {
   this.url = url;
 }
--- a/services/common/tests/mach_commands.py
+++ b/services/common/tests/mach_commands.py
@@ -82,17 +82,17 @@ class SyncTestCommands(MachCommandBase):
             '-m',
             '-s',
             '-e', 'const _TESTING_MODULES_DIR = "%s/_tests/modules";' % topobjdir,
             '-f', '%s/testing/xpcshell/head.js' % topsrcdir,
             '-e', 'const _SERVER_ADDR = "%s";' % hostname,
             '-e', 'const SERVER_PORT = "%s";' % port,
             '-e', 'const INCLUDE_FILES = [%s];' % ', '.join(head_paths),
             '-e', '_register_protocol_handlers();',
-            '-e', 'for each (let name in INCLUDE_FILES) load(name);',
+            '-e', 'for (let name of INCLUDE_FILES) load(name);',
             '-e', '_fakeIdleService.activate();',
             '-f', js_file
             ]
 
         profile_dir = mkdtemp()
         print 'Created profile directory: %s' % profile_dir
 
         try:
--- a/services/common/tests/unit/head_global.js
+++ b/services/common/tests/unit/head_global.js
@@ -37,15 +37,15 @@ registrar.registerFactory(Components.ID(
                           XULAppInfoFactory);
 
 function addResourceAlias() {
   Cu.import("resource://gre/modules/Services.jsm");
   const handler = Services.io.getProtocolHandler("resource")
                   .QueryInterface(Ci.nsIResProtocolHandler);
 
   let modules = ["common", "crypto"];
-  for each (let module in modules) {
+  for (let module of modules) {
     let uri = Services.io.newURI("resource://gre/modules/services-" + module + "/",
                                  null, null);
     handler.setSubstitution("services-" + module, uri);
   }
 }
 addResourceAlias();
--- a/services/common/tests/unit/test_load_modules.js
+++ b/services/common/tests/unit/test_load_modules.js
@@ -29,32 +29,32 @@ const non_android_test_modules = [
   "storageserver.js",
 ];
 
 const non_android_healthreport_test_modules = [
   "bagheeraserver.js",
 ];
 
 function expectImportsToSucceed(mm, base=MODULE_BASE) {
-  for each (let m in mm) {
+  for (let m of mm) {
     let resource = base + m;
     let succeeded = false;
     try {
       Components.utils.import(resource, {});
       succeeded = true;
     } catch (e) {}
 
     if (!succeeded) {
       throw "Importing " + resource + " should have succeeded!";
     }
   }
 }
 
 function expectImportsToFail(mm, base=MODULE_BASE) {
-  for each (let m in mm) {
+  for (let m of mm) {
     let resource = base + m;
     let succeeded = false;
     try {
       Components.utils.import(resource, {});
       succeeded = true;
     } catch (e) {}
 
     if (succeeded) {
--- a/services/common/tests/unit/test_tokenserverclient.js
+++ b/services/common/tests/unit/test_tokenserverclient.js
@@ -55,17 +55,17 @@ add_test(function test_invalid_arguments
   _("Ensure invalid arguments to APIs are rejected.");
 
   let args = [
     [null, "assertion", function() {}],
     ["http://example.com/", null, function() {}],
     ["http://example.com/", "assertion", null]
   ];
 
-  for each (let arg in args) {
+  for (let arg of args) {
     try {
       let client = new TokenServerClient();
       client.getTokenFromBrowserIDAssertion(arg[0], arg[1], arg[2]);
       do_throw("Should never get here.");
     } catch (ex) {
       do_check_true(ex instanceof TokenServerClientError);
     }
   }
--- a/services/common/utils.js
+++ b/services/common/utils.js
@@ -200,26 +200,25 @@ this.CommonUtils = {
       str = this._utf8Converter.ConvertToUnicode(str);
       return str + this._utf8Converter.Finish();
     } catch (ex) {
       return null;
     }
   },
 
   byteArrayToString: function byteArrayToString(bytes) {
-    return [String.fromCharCode(byte) for each (byte in bytes)].join("");
+    return bytes.map(byte => String.fromCharCode(byte)).join("");
   },
 
   stringToByteArray: function stringToByteArray(bytesString) {
-    return [String.charCodeAt(byte) for each (byte in bytesString)];
+    return Array.prototype.slice.call(bytesString).map(c => c.charCodeAt(0));
   },
 
   bytesAsHex: function bytesAsHex(bytes) {
-    return [("0" + bytes.charCodeAt(byte).toString(16)).slice(-2)
-      for (byte in bytes)].join("");
+    return Array.prototype.slice.call(bytes).map(c => ("0" + c.charCodeAt(0).toString(16)).slice(-2)).join("");
   },
 
   stringAsHex: function stringAsHex(str) {
     return CommonUtils.bytesAsHex(CommonUtils.encodeUTF8(str));
   },
 
   stringToBytes: function stringToBytes(str) {
     return CommonUtils.hexToBytes(CommonUtils.stringAsHex(str));
@@ -251,17 +250,17 @@ this.CommonUtils = {
       for (let i = leftover; i < 5; i++)
         bytes += "\0";
     }
 
     // Chop the string into quanta of 5 bytes (40 bits). Each quantum
     // is turned into 8 characters from the 32 character base.
     let ret = "";
     for (let i = 0; i < bytes.length; i += 5) {
-      let c = [byte.charCodeAt() for each (byte in bytes.slice(i, i + 5))];
+      let c = Array.prototype.slice.call(bytes.slice(i, i + 5)).map(byte => byte.charCodeAt(0));
       ret += key[c[0] >> 3]
            + key[((c[0] << 2) & 0x1f) | (c[1] >> 6)]
            + key[(c[1] >> 1) & 0x1f]
            + key[((c[1] << 4) & 0x1f) | (c[2] >> 4)]
            + key[((c[2] << 1) & 0x1f) | (c[3] >> 7)]
            + key[(c[3] >> 2) & 0x1f]
            + key[((c[3] << 3) & 0x1f) | (c[4] >> 5)]
            + key[c[4] & 0x1f];
--- a/services/crypto/modules/utils.js
+++ b/services/crypto/modules/utils.js
@@ -51,17 +51,17 @@ this.CryptoUtils = {
 
   /**
    * Treat the given message as a bytes string and hash it with the given
    * hasher. Returns a string containing bytes. The hasher is reset if it's
    * an HMAC hasher.
    */
   digestBytes: function digestBytes(message, hasher) {
     // No UTF-8 encoding for you, sunshine.
-    let bytes = [b.charCodeAt() for each (b in message)];
+    let bytes = Array.prototype.slice.call(message).map(b => b.charCodeAt(0));
     hasher.update(bytes, bytes.length);
     let result = hasher.finish(false);
     if (hasher instanceof Ci.nsICryptoHMAC) {
       hasher.reset();
     }
     return result;
   },
 
--- a/services/crypto/tests/unit/test_load_modules.js
+++ b/services/crypto/tests/unit/test_load_modules.js
@@ -2,15 +2,15 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const modules = [
   "utils.js",
   "WeaveCrypto.js",
 ];
 
 function run_test() {
-  for each (let m in modules) {
+  for (let m of modules) {
     let resource = "resource://services-crypto/" + m;
     _("Attempting to import: " + resource);
     Components.utils.import(resource, {});
   }
 }
 
--- a/services/metrics/providermanager.jsm
+++ b/services/metrics/providermanager.jsm
@@ -277,17 +277,18 @@ this.ProviderManager.prototype = Object.
         try {
           yield inFlightPromise;
         } catch (ex) {
           this._log.warn("Error when waiting for existing pull-only promise: " +
                          CommonUtils.exceptionStr(ex));
         }
       }
 
-      for each (let providerType in this._pullOnlyProviders) {
+      for (let name in this._pullOnlyProviders) {
+        let providerType = this._pullOnlyProviders[name];
         // Short-circuit if we're no longer registering.
         if (this._pullOnlyProvidersState != this.PULL_ONLY_REGISTERING) {
           this._log.debug("Aborting pull-only provider registration.");
           break;
         }
 
         try {
           let provider = this._initProviderFromType(providerType);
--- a/services/sync/modules/addonsreconciler.js
+++ b/services/sync/modules/addonsreconciler.js
@@ -213,21 +213,22 @@ AddonsReconciler.prototype = {
         if (callback) {
           callback(null, false);
         }
 
         return;
       }
 
       this._addons = json.addons;
-      for each (let record in this._addons) {
+      for (let id in this._addons) {
+        let record = this._addons[id];
         record.modified = new Date(record.modified);
       }
 
-      for each (let [time, change, id] in json.changes) {
+      for (let [time, change, id] of json.changes) {
         this._changes.push([new Date(time), change, id]);
       }
 
       if (callback) {
         callback(null, true);
       }
     });
   },
@@ -253,17 +254,17 @@ AddonsReconciler.prototype = {
           state.addons[id][k] = v.getTime();
         }
         else {
           state.addons[id][k] = v;
         }
       }
     }
 
-    for each (let [time, change, id] in this._changes) {
+    for (let [time, change, id] of this._changes) {
       state.changes.push([time.getTime(), change, id]);
     }
 
     this._log.info("Saving reconciler state to file: " + file);
     Utils.jsonSave(file, this, state, callback);
   },
 
   /**
@@ -345,17 +346,17 @@ AddonsReconciler.prototype = {
     this._log.info("Refreshing global state from AddonManager.");
     this._ensureStateLoaded();
 
     let installs;
 
     AddonManager.getAllAddons(function (addons) {
       let ids = {};
 
-      for each (let addon in addons) {
+      for (let addon of addons) {
         ids[addon.id] = true;
         this.rectifyStateFromAddon(addon);
       }
 
       // Look for locally-defined add-ons that no longer exist and update their
       // record.
       for (let [id, addon] in Iterator(this._addons)) {
         if (id in ids) {
@@ -368,17 +369,17 @@ AddonsReconciler.prototype = {
 
         if (!installs) {
           let cb = Async.makeSyncCallback();
           AddonManager.getAllInstalls(cb);
           installs = Async.waitForSyncCallback(cb);
         }
 
         let installFound = false;
-        for each (let install in installs) {
+        for (let install of installs) {
           if (install.addon && install.addon.id == id &&
               install.state == AddonManager.STATE_INSTALLED) {
 
             installFound = true;
             break;
           }
         }
 
@@ -478,17 +479,17 @@ AddonsReconciler.prototype = {
    *        The type of the change. A CHANGE_* constant.
    * @param state
    *        The new state of the add-on. From this.addons.
    */
   _addChange: function _addChange(date, change, state) {
     this._log.info("Change recorded for " + state.id);
     this._changes.push([date, change, state.id]);
 
-    for each (let listener in this._listeners) {
+    for (let listener of this._listeners) {
       try {
         listener.changeListener.call(listener, date, change, state);
       } catch (ex) {
         this._log.warn("Exception calling change listener: " +
                        Utils.exceptionStr(ex));
       }
     }
   },
@@ -549,17 +550,18 @@ AddonsReconciler.prototype = {
    *
    * If the add-on could not be found, returns null.
    *
    * @param  guid
    *         Sync GUID of add-on to retrieve.
    * @return Object on success on null on failure.
    */
   getAddonStateFromSyncGUID: function getAddonStateFromSyncGUID(guid) {
-    for each (let addon in this.addons) {
+    for (let id in this.addons) {
+      let addon = this.addons[id];
       if (addon.guid == guid) {
         return addon;
       }
     }
 
     return null;
   },
 
--- a/services/sync/modules/addonutils.js
+++ b/services/sync/modules/addonutils.js
@@ -243,17 +243,17 @@ AddonUtilsInternal.prototype = {
    *        Function to be called when all actions are complete.
    */
   installAddons: function installAddons(installs, cb) {
     if (!cb) {
       throw new Error("Invalid argument: cb is not defined.");
     }
 
     let ids = [];
-    for each (let addon in installs) {
+    for (let addon of installs) {
       ids.push(addon.id);
     }
 
     AddonRepository.getAddonsByIDs(ids, {
       searchSucceeded: function searchSucceeded(addons, addonsLength, total) {
         this._log.info("Found " + addonsLength + "/" + ids.length +
                        " add-ons during repository search.");
 
@@ -293,17 +293,17 @@ AddonUtilsInternal.prototype = {
 
         let toInstall = [];
 
         // Rewrite the "src" query string parameter of the source URI to note
         // that the add-on was installed by Sync and not something else so
         // server-side metrics aren't skewed (bug 708134). The server should
         // ideally send proper URLs, but this solution was deemed too
         // complicated at the time the functionality was implemented.
-        for each (let addon in addons) {
+        for (let addon of addons) {
           // sourceURI presence isn't enforced by AddonRepository. So, we skip
           // add-ons without a sourceURI.
           if (!addon.sourceURI) {
             this._log.info("Skipping install of add-on because missing " +
                            "sourceURI: " + addon.id);
             continue;
           }
 
@@ -337,19 +337,19 @@ AddonUtilsInternal.prototype = {
 
         if (!expectedInstallCount) {
           cb(null, ourResult);
           return;
         }
 
         // Start all the installs asynchronously. They will report back to us
         // as they finish, eventually triggering the global callback.
-        for each (let addon in toInstall) {
+        for (let addon of toInstall) {
           let options = {};
-          for each (let install in installs) {
+          for (let install of installs) {
             if (install.id == addon.id) {
               options = install;
               break;
             }
           }
 
           this.installAddonFromSearchResult(addon, options, installCallback);
         }
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -294,17 +294,17 @@ Store.prototype = {
    * applyIncoming(). Store implementations may overwrite this function
    * if desired.
    *
    * @param  records Array of records to apply
    * @return Array of record IDs which did not apply cleanly
    */
   applyIncomingBatch: function (records) {
     let failed = [];
-    for each (let record in records) {
+    for (let record of records) {
       try {
         this.applyIncoming(record);
       } catch (ex if (ex.code == Engine.prototype.eEngineAbortApplyIncoming)) {
         // This kind of exception should have a 'cause' attribute, which is an
         // originating exception.
         // ex.cause will carry its stack with it when rethrown.
         throw ex.cause;
       } catch (ex if !Async.isShutdownException(ex)) {
@@ -492,17 +492,17 @@ EngineManager.prototype = {
    */
   getEnabled: function () {
     return this.getAll()
                .filter((engine) => engine.enabled)
                .sort((a, b) => a.syncPriority - b.syncPriority);
   },
 
   get enabledEngineNames() {
-    return [e.name for each (e in this.getEnabled())];
+    return this.getEnabled().map(e => e.name);
   },
 
   persistDeclined: function () {
     Svc.Prefs.set("declinedEngines", [...this._declined].join(","));
   },
 
   /**
    * Returns an array.
@@ -1459,24 +1459,25 @@ SyncEngine.prototype = {
 
         let failed_ids = Object.keys(resp.obj.failed);
         if (failed_ids.length)
           this._log.debug("Records that will be uploaded again because "
                           + "the server couldn't store them: "
                           + failed_ids.join(", "));
 
         // Clear successfully uploaded objects.
-        for each (let id in resp.obj.success) {
+        for (let key in resp.obj.success) {
+          let id = resp.obj.success[key];
           delete this._modified[id];
         }
 
         up.clearRecords();
       });
 
-      for each (let id in modifiedIDs) {
+      for (let id of modifiedIDs) {
         try {
           let out = this._createRecord(id);
           if (this._log.level <= Log.Level.Trace)
             this._log.trace("Outgoing: " + out);
 
           out.encrypt(this.service.collectionKeys.keyForCollection(this.name));
           up.pushData(out);
         } catch (ex if !Async.isShutdownException(ex)) {
--- a/services/sync/modules/engines/addons.js
+++ b/services/sync/modules/engines/addons.js
@@ -155,17 +155,17 @@ AddonsEngine.prototype = {
     }
 
     let lastSyncDate = new Date(this.lastSync * 1000);
 
     // The reconciler should have been refreshed at the beginning of a sync and
     // we assume this function is only called from within a sync.
     let reconcilerChanges = this._reconciler.getChangesSinceDate(lastSyncDate);
     let addons = this._reconciler.addons;
-    for each (let change in reconcilerChanges) {
+    for (let change of reconcilerChanges) {
       let changeTime = change[0];
       let id = change[2];
 
       if (!(id in addons)) {
         continue;
       }
 
       // Keep newest modified time.
@@ -294,17 +294,17 @@ AddonsStore.prototype = {
       requireSecureURI: !Svc.Prefs.get("addons.ignoreRepositoryChecking", false),
     }], cb);
 
     // This will throw if there was an error. This will get caught by the sync
     // engine and the record will try to be applied later.
     let results = cb.wait();
 
     let addon;
-    for each (let a in results.addons) {
+    for (let a of results.addons) {
       if (a.id == record.addonID) {
         addon = a;
         break;
       }
     }
 
     // This should never happen, but is present as a fail-safe.
     if (!addon) {
@@ -438,17 +438,18 @@ AddonsStore.prototype = {
    * Obtain the set of all syncable add-on Sync GUIDs.
    *
    * This implements a core Store API.
    */
   getAllIDs: function getAllIDs() {
     let ids = {};
 
     let addons = this.reconciler.addons;
-    for each (let addon in addons) {
+    for (let id in addons) {
+      let addon = addons[id];
       if (this.isAddonSyncable(addon)) {
         ids[addon.guid] = true;
       }
     }
 
     return ids;
   },
 
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -174,17 +174,17 @@ var kSpecialIds = {
     if (guid == "mobile") {
       return this.findMobileRoot(create);
     }
     return this[guid];
   },
 
   // Don't bother creating mobile: if it doesn't exist, this ID can't be it!
   specialGUIDForId: function specialGUIDForId(id) {
-    for each (let guid in this.guids)
+    for (let guid of this.guids)
       if (this.specialIdForGUID(guid, false) == id)
         return guid;
     return null;
   },
 
   get menu() {
     return PlacesUtils.bookmarksMenuFolderId;
   },
@@ -502,17 +502,18 @@ BookmarksEngine.prototype = {
   }
 };
 
 function BookmarksStore(name, engine) {
   Store.call(this, name, engine);
 
   // Explicitly nullify our references to our cached services so we don't leak
   Svc.Obs.add("places-shutdown", function() {
-    for each (let [query, stmt] in Iterator(this._stmts)) {
+    for (let query in this._stmts) {
+      let stmt = this._stmts[query];
       stmt.finalize();
     }
     this._stmts = {};
   }, this);
 }
 BookmarksStore.prototype = {
   __proto__: Store.prototype,
 
@@ -559,17 +560,17 @@ BookmarksStore.prototype = {
     try {
       for (let i = 0; i < tags.childCount; i++) {
         let child = tags.getChild(i);
         if (child.title == tag) {
           // Found the tag, so fix up the query to use the right id.
           this._log.debug("Tag query folder: " + tag + " = " + child.itemId);
           
           this._log.trace("Replacing folders in: " + uri);
-          for each (let q in queriesRef.value)
+          for (let q of queriesRef.value)
             q.setFolders([child.itemId], 1);
           
           record.bmkUri = PlacesUtils.history.queriesToQueryString(
             queriesRef.value, queryCountRef.value, optionsRef.value);
           return;
         }
       }
     }
@@ -1356,29 +1357,29 @@ BookmarksStore.prototype = {
                  "unfiled": true,
                 };
     // We also want "mobile" but only if a local mobile folder already exists
     // (otherwise we'll later end up creating it, which we want to avoid until
     // we actually need it.)
     if (kSpecialIds.findMobileRoot(false)) {
       items["mobile"] = true;
     }
-    for each (let guid in kSpecialIds.guids) {
+    for (let guid of kSpecialIds.guids) {
       if (guid != "places" && guid != "tags")
         this._getChildren(guid, items);
     }
     return items;
   },
 
   wipe: function BStore_wipe() {
     let cb = Async.makeSpinningCallback();
     Task.spawn(function() {
       // Save a backup before clearing out all bookmarks.
       yield PlacesBackups.create(null, true);
-      for each (let guid in kSpecialIds.guids)
+      for (let guid of kSpecialIds.guids)
         if (guid != "places") {
           let id = kSpecialIds.specialIdForGUID(guid);
           if (id)
             PlacesUtils.bookmarks.removeFolderChildren(id);
         }
       cb();
     });
     cb.wait();
--- a/services/sync/modules/engines/clients.js
+++ b/services/sync/modules/engines/clients.js
@@ -63,17 +63,18 @@ ClientEngine.prototype = {
   // Aggregate some stats on the composition of clients on this account
   get stats() {
     let stats = {
       hasMobile: this.localType == "mobile",
       names: [this.localName],
       numClients: 1,
     };
 
-    for each (let {name, type} in this._store._remoteClients) {
+    for (let id in this._store._remoteClients) {
+      let {name, type} = this._store._remoteClients[id];
       stats.hasMobile = stats.hasMobile || type == "mobile";
       stats.names.push(name);
       stats.numClients++;
     }
 
     return stats;
   },
 
@@ -82,17 +83,18 @@ ClientEngine.prototype = {
    *
    * Returns a Map of device types to integer counts.
    */
   get deviceTypes() {
     let counts = new Map();
 
     counts.set(this.localType, 1);
 
-    for each (let record in this._store._remoteClients) {
+    for (let id in this._store._remoteClients) {
+      let record = this._store._remoteClients[id];
       let type = record.type;
       if (!counts.has(type)) {
         counts.set(type, 0);
       }
 
       counts.set(type, counts.get(type) + 1);
     }
 
@@ -253,17 +255,21 @@ ClientEngine.prototype = {
   processIncomingCommands: function processIncomingCommands() {
     return this._notify("clients:process-commands", "", function() {
       let commands = this.localCommands;
 
       // Immediately clear out the commands as we've got them locally.
       this.clearCommands();
 
       // Process each command in order.
-      for each (let {command, args} in commands) {
+      if (!commands) {
+        return true;
+      }
+      for (let key in commands) {
+        let {command, args} = commands[key];
         this._log.debug("Processing command: " + command + "(" + args + ")");
 
         let engines = [args[0]];
         switch (command) {
           case "resetAll":
             engines = null;
             // Fallthrough
           case "resetEngine":
--- a/services/sync/modules/engines/history.js
+++ b/services/sync/modules/engines/history.js
@@ -65,17 +65,18 @@ HistoryEngine.prototype = {
   },
 };
 
 function HistoryStore(name, engine) {
   Store.call(this, name, engine);
 
   // Explicitly nullify our references to our cached services so we don't leak
   Svc.Obs.add("places-shutdown", function() {
-    for each ([query, stmt] in Iterator(this._stmts)) {
+    for (let query in this._stmts) {
+      let stmt = this._stmts;
       stmt.finalize();
     }
     this._stmts = {};
   }, this);
 }
 HistoryStore.prototype = {
   __proto__: Store.prototype,
 
--- a/services/sync/modules/engines/passwords.js
+++ b/services/sync/modules/engines/passwords.js
@@ -80,17 +80,17 @@ PasswordEngine.prototype = {
       return;
     }
 
     let logins = Services.logins.findLogins({}, login.hostname, login.formSubmitURL, login.httpRealm);
 
     this._store._sleep(0); // Yield back to main thread after synchronous operation.
 
     // Look for existing logins that match the hostname, but ignore the password.
-    for each (let local in logins) {
+    for (let local of logins) {
       if (login.matches(local, true) && local instanceof Ci.nsILoginMetaInfo) {
         return local.guid;
       }
     }
   },
 };
 
 function PasswordStore(name, engine) {
--- a/services/sync/modules/engines/prefs.js
+++ b/services/sync/modules/engines/prefs.js
@@ -96,17 +96,17 @@ PrefStore.prototype = {
 
   _isSynced: function (pref) {
     return pref.startsWith(PREF_SYNC_PREFS_PREFIX) ||
            this._prefs.get(PREF_SYNC_PREFS_PREFIX + pref, false);
   },
 
   _getAllPrefs: function () {
     let values = {};
-    for each (let pref in this._getSyncPrefs()) {
+    for (let pref of this._getSyncPrefs()) {
       if (this._isSynced(pref)) {
         // Missing prefs get the null value.
         values[pref] = this._prefs.get(pref, null);
       }
     }
     return values;
   },
 
--- a/services/sync/modules/engines/tabs.js
+++ b/services/sync/modules/engines/tabs.js
@@ -297,30 +297,30 @@ TabTracker.prototype = {
   clearChangedIDs: function () {
     this.modified = false;
   },
 
   _topics: ["pageshow", "TabOpen", "TabClose", "TabSelect"],
 
   _registerListenersForWindow: function (window) {
     this._log.trace("Registering tab listeners in window");
-    for each (let topic in this._topics) {
+    for (let topic of this._topics) {
       window.addEventListener(topic, this.onTab, false);
     }
     window.addEventListener("unload", this._unregisterListeners, false);
   },
 
   _unregisterListeners: function (event) {
     this._unregisterListenersForWindow(event.target);
   },
 
   _unregisterListenersForWindow: function (window) {
     this._log.trace("Removing tab listeners in window");
     window.removeEventListener("unload", this._unregisterListeners, false);
-    for each (let topic in this._topics) {
+    for (let topic of this._topics) {
       window.removeEventListener(topic, this.onTab, false);
     }
   },
 
   startTracking: function () {
     Svc.Obs.add("domwindowopened", this);
     let wins = Services.wm.getEnumerator("navigator:browser");
     while (wins.hasMoreElements()) {
--- a/services/sync/modules/identity.js
+++ b/services/sync/modules/identity.js
@@ -190,17 +190,17 @@ IdentityManager.prototype = {
   get basicPassword() {
     if (this._basicPasswordAllowLookup) {
       // We need a username to find the credentials.
       let username = this.username;
       if (!username) {
         return null;
       }
 
-      for each (let login in this._getLogins(PWDMGR_PASSWORD_REALM)) {
+      for (let login of this._getLogins(PWDMGR_PASSWORD_REALM)) {
         if (login.username.toLowerCase() == username) {
           // It should already be UTF-8 encoded, but we don't take any chances.
           this._basicPassword = Utils.encodeUTF8(login.password);
         }
       }
 
       this._basicPasswordAllowLookup = false;
     }
@@ -244,17 +244,17 @@ IdentityManager.prototype = {
    */
   get syncKey() {
     if (this._syncKeyAllowLookup) {
       let username = this.username;
       if (!username) {
         return null;
       }
 
-      for each (let login in this._getLogins(PWDMGR_PASSPHRASE_REALM)) {
+      for (let login of this._getLogins(PWDMGR_PASSPHRASE_REALM)) {
         if (login.username.toLowerCase() == username) {
           this._syncKey = login.password;
         }
       }
 
       this._syncKeyAllowLookup = false;
     }
 
@@ -395,29 +395,29 @@ IdentityManager.prototype = {
    * entered), this could throw an exception.
    */
   persistCredentials: function persistCredentials(force) {
     if (this._basicPasswordUpdated || force) {
       if (this._basicPassword) {
         this._setLogin(PWDMGR_PASSWORD_REALM, this.username,
                        this._basicPassword);
       } else {
-        for each (let login in this._getLogins(PWDMGR_PASSWORD_REALM)) {
+        for (let login of this._getLogins(PWDMGR_PASSWORD_REALM)) {
           Services.logins.removeLogin(login);
         }
       }
 
       this._basicPasswordUpdated = false;
     }
 
     if (this._syncKeyUpdated || force) {
       if (this._syncKey) {
         this._setLogin(PWDMGR_PASSPHRASE_REALM, this.username, this._syncKey);
       } else {
-        for each (let login in this._getLogins(PWDMGR_PASSPHRASE_REALM)) {
+        for (let login of this._getLogins(PWDMGR_PASSPHRASE_REALM)) {
           Services.logins.removeLogin(login);
         }
       }
 
       this._syncKeyUpdated = false;
     }
 
   },
@@ -461,17 +461,17 @@ IdentityManager.prototype = {
   /**
    * Set a login in the password manager.
    *
    * This has the side-effect of deleting any other logins for the specified
    * realm.
    */
   _setLogin: function _setLogin(realm, username, password) {
     let exists = false;
-    for each (let login in this._getLogins(realm)) {
+    for (let login of this._getLogins(realm)) {
       if (login.username == username && login.password == password) {
         exists = true;
       } else {
         this._log.debug("Pruning old login for " + username + " from " + realm);
         Services.logins.removeLogin(login);
       }
     }
 
@@ -497,17 +497,17 @@ IdentityManager.prototype = {
   },
 
   /**
    * Deletes Sync credentials from the password manager.
    */
   deleteSyncCredentials: function deleteSyncCredentials() {
     for (let host of this._getSyncCredentialsHosts()) {
       let logins = Services.logins.findLogins({}, host, "", "");
-      for each (let login in logins) {
+      for (let login of logins) {
         Services.logins.removeLogin(login);
       }
     }
 
     // Wait until after store is updated in case it fails.
     this._basicPassword = null;
     this._basicPasswordAllowLookup = true;
     this._basicPasswordUpdated = false;
--- a/services/sync/modules/jpakeclient.js
+++ b/services/sync/modules/jpakeclient.js
@@ -276,28 +276,26 @@ JPAKEClient.prototype = {
   /*
    * Utilities
    */
 
   _setClientID: function _setClientID() {
     let rng = Cc["@mozilla.org/security/random-generator;1"]
                 .createInstance(Ci.nsIRandomGenerator);
     let bytes = rng.generateRandomBytes(JPAKE_LENGTH_CLIENTID / 2);
-    this._clientID = [("0" + byte.toString(16)).slice(-2)
-                      for each (byte in bytes)].join("");
+    this._clientID = bytes.map(byte => ("0" + byte.toString(16)).slice(-2)).join("");
   },
 
   _createSecret: function _createSecret() {
     // 0-9a-z without 1,l,o,0
     const key = "23456789abcdefghijkmnpqrstuvwxyz";
     let rng = Cc["@mozilla.org/security/random-generator;1"]
                 .createInstance(Ci.nsIRandomGenerator);
     let bytes = rng.generateRandomBytes(JPAKE_LENGTH_SECRET);
-    return [key[Math.floor(byte * key.length / 256)]
-            for each (byte in bytes)].join("");
+    return bytes.map(byte => key[Math.floor(byte * key.length / 256)]).join("");
   },
 
   _newRequest: function _newRequest(uri) {
     let request = new RESTRequest(uri);
     request.setHeader("X-KeyExchange-Id", this._clientID);
     request.timeout = REQUEST_TIMEOUT;
     return request;
   },
--- a/services/sync/modules/record.js
+++ b/services/sync/modules/record.js
@@ -307,17 +307,17 @@ CollectionKeyManager.prototype = {
 
     // Diffs both ways.
     process(m1, m2);
     process(m2, m1);
 
     // Return a sorted, unique array.
     changed.sort();
     let last;
-    changed = [x for each (x in changed) if ((x != last) && (last = x))];
+    changed = changed.filter(x => (x != last) && (last = x));
     return {same: changed.length == 0,
             changed: changed};
   },
 
   get isClear() {
    return !this._default;
   },
 
--- a/services/sync/modules/service.js
+++ b/services/sync/modules/service.js
@@ -437,17 +437,17 @@ Sync11Service.prototype = {
     let oldPrefBranch = "extensions.weave.";
     let oldPrefNames = Cc["@mozilla.org/preferences-service;1"].
                        getService(Ci.nsIPrefService).
                        getBranch(oldPrefBranch).
                        getChildList("", {});
 
     // Map each old pref to the current pref branch
     let oldPref = new Preferences(oldPrefBranch);
-    for each (let pref in oldPrefNames)
+    for (let pref of oldPrefNames)
       Svc.Prefs.set(pref, oldPref.get(pref));
 
     // Remove all the old prefs and remember that we've migrated
     oldPref.resetBranch("");
     Svc.Prefs.set("migrated", true);
   },
 
   /**
@@ -896,17 +896,17 @@ Sync11Service.prototype = {
   startOver: function startOver() {
     this._log.trace("Invoking Service.startOver.");
     Svc.Obs.notify("weave:engine:stop-tracking");
     this.status.resetSync();
 
     // Deletion doesn't make sense if we aren't set up yet!
     if (this.clusterURL != "") {
       // Clear client-specific data from the server, including disabled engines.
-      for each (let engine in [this.clientsEngine].concat(this.engineManager.getAll())) {
+      for (let engine of [this.clientsEngine].concat(this.engineManager.getAll())) {
         try {
           engine.removeClientData();
         } catch(ex) {
           this._log.warn("Deleting client data for " + engine.name + " failed:"
                          + Utils.exceptionStr(ex));
         }
       }
       this._log.debug("Finished deleting client data.");
@@ -1506,17 +1506,17 @@ Sync11Service.prototype = {
     // uploadMetaGlobal throws on failure -- including race conditions.
     // If we got into a race condition, we'll abort the sync this way, too.
     // That's fine. We'll just wait till the next sync. The client that we're
     // racing is probably busy uploading stuff right now anyway.
     this.uploadMetaGlobal(meta);
 
     // Wipe everything we know about except meta because we just uploaded it
     let engines = [this.clientsEngine].concat(this.engineManager.getAll());
-    let collections = [engine.name for each (engine in engines)];
+    let collections = engines.map(engine => engine.name);
     // TODO: there's a bug here. We should be calling resetClient, no?
 
     // Generate, upload, and download new keys. Do this last so we don't wipe
     // them...
     this.generateNewSymmetricKeys();
   },
 
   /**
@@ -1588,17 +1588,17 @@ Sync11Service.prototype = {
       engines = [this.clientsEngine].concat(this.engineManager.getAll());
     }
     // Convert the array of names into engines
     else {
       engines = this.engineManager.get(engines);
     }
 
     // Fully wipe each engine if it's able to decrypt data
-    for each (let engine in engines) {
+    for (let engine of engines) {
       if (engine.canDecrypt()) {
         engine.wipeClient();
       }
     }
 
     // Save the password/passphrase just in-case they aren't restored by sync
     this.persistLogin();
   },
@@ -1666,17 +1666,17 @@ Sync11Service.prototype = {
         engines = [this.clientsEngine].concat(this.engineManager.getAll());
       }
       // Convert the array of names into engines
       else {
         engines = this.engineManager.get(engines);
       }
 
       // Have each engine drop any temporary meta data
-      for each (let engine in engines) {
+      for (let engine of engines) {
         engine.resetClient();
       }
     })();
   },
 
   /**
    * Fetch storage info from the server.
    *
--- a/services/sync/modules/stages/declined.js
+++ b/services/sync/modules/stages/declined.js
@@ -24,18 +24,18 @@ Cu.import("resource://gre/modules/Prefer
 this.DeclinedEngines = function (service) {
   this._log = Log.repository.getLogger("Sync.Declined");
   this._log.level = Log.Level[new Preferences(PREFS_BRANCH).get("log.logger.declined")];
 
   this.service = service;
 }
 this.DeclinedEngines.prototype = {
   updateDeclined: function (meta, engineManager=this.service.engineManager) {
-    let enabled = new Set([e.name for each (e in engineManager.getEnabled())]);
-    let known = new Set([e.name for each (e in engineManager.getAll())]);
+    let enabled = new Set(engineManager.getEnabled().map(e => e.name));
+    let known = new Set(engineManager.getAll().map(e => e.name));
     let remoteDeclined = new Set(meta.payload.declined || []);
     let localDeclined = new Set(engineManager.getDeclined());
 
     this._log.debug("Handling remote declined: " + JSON.stringify([...remoteDeclined]));
     this._log.debug("Handling local declined: " + JSON.stringify([...localDeclined]));
 
     // Any engines that are locally enabled should be removed from the remote
     // declined list.
--- a/services/sync/modules/stages/enginesync.js
+++ b/services/sync/modules/stages/enginesync.js
@@ -284,17 +284,17 @@ EngineSynchronizer.prototype = {
           // This will be reflected in meta/global in the next stage.
           this._log.trace("Engine " + engineName + " was disabled locally. Marking as declined.");
           toDecline.add(engineName);
         }
       }
     }
 
     // Any remaining engines were either enabled locally or disabled remotely.
-    for each (let engineName in enabled) {
+    for (let engineName of enabled) {
       let engine = engineManager.get(engineName);
       if (Svc.Prefs.get("engineStatusChanged." + engine.prefName, false)) {
         this._log.trace("The " + engineName + " engine was enabled locally.");
         toUndecline.add(engineName);
       } else {
         this._log.trace("The " + engineName + " engine was disabled remotely.");
 
         // Don't automatically mark it as declined!
--- a/services/sync/tests/unit/head_appinfo.js
+++ b/services/sync/tests/unit/head_appinfo.js
@@ -55,15 +55,15 @@ registrar.registerFactory(Components.ID(
                           "XULAppInfo", "@mozilla.org/xre/app-info;1",
                           XULAppInfoFactory);
 
 
 // Register resource aliases. Normally done in SyncComponents.manifest.
 function addResourceAlias() {
   const resProt = Services.io.getProtocolHandler("resource")
                           .QueryInterface(Ci.nsIResProtocolHandler);
-  for each (let s in ["common", "sync", "crypto"]) {
+  for (let s of ["common", "sync", "crypto"]) {
     let uri = Services.io.newURI("resource://gre/modules/services-" + s + "/", null,
                                  null);
     resProt.setSubstitution("services-" + s, uri);
   }
 }
 addResourceAlias();
--- a/services/sync/tests/unit/head_http_server.js
+++ b/services/sync/tests/unit/head_http_server.js
@@ -304,17 +304,18 @@ ServerCollection.prototype = {
 
   post: function(input) {
     input = JSON.parse(input);
     let success = [];
     let failed = {};
 
     // This will count records where we have an existing ServerWBO
     // registered with us as successful and all other records as failed.
-    for each (let record in input) {
+    for (let key in input) {
+      let record = input[key];
       let wbo = this.wbo(record.id);
       if (!wbo && this.acceptNew) {
         this._log.debug("Creating WBO " + JSON.stringify(record.id) +
                         " on the fly.");
         wbo = new ServerWBO(record.id);
         this.insertWBO(wbo);
       }
       if (wbo) {
@@ -349,17 +350,17 @@ ServerCollection.prototype = {
 
     return function(request, response) {
       var statusCode = 200;
       var status = "OK";
       var body;
 
       // Parse queryString
       let options = {};
-      for each (let chunk in request.queryString.split("&")) {
+      for (let chunk of request.queryString.split("&")) {
         if (!chunk) {
           continue;
         }
         chunk = chunk.split("=");
         if (chunk.length == 1) {
           options[chunk[0]] = "";
         } else {
           options[chunk[0]] = chunk[1];
@@ -699,17 +700,18 @@ SyncServer.prototype = {
    *
    * @return a timestamp.
    */
   deleteCollections: function deleteCollections(username) {
     if (!(username in this.users)) {
       throw new Error("Unknown user.");
     }
     let userCollections = this.users[username].collections;
-    for each (let [name, coll] in Iterator(userCollections)) {
+    for (let name in userCollections) {
+      let coll = userCollections[name];
       this._log.trace("Bulk deleting " + name + " for " + username + "...");
       coll.delete({});
     }
     this.users[username].collections = {};
     return this.timestamp();
   },
 
   /**
@@ -763,17 +765,20 @@ SyncServer.prototype = {
 
   defaultHeaders: {},
 
   /**
    * HTTP response utility.
    */
   respond: function respond(req, resp, code, status, body, headers) {
     resp.setStatusLine(req.httpVersion, code, status);
-    for each (let [header, value] in Iterator(headers || this.defaultHeaders)) {
+    if (!headers)
+      headers = this.defaultHeaders;
+    for (let header in headers) {
+      let value = headers[header];
       resp.setHeader(header, value);
     }
     resp.setHeader("X-Weave-Timestamp", "" + this.timestamp(), false);
     resp.bodyOutputStream.write(body, body.length);
   },
 
   /**
    * This is invoked by the HttpServer. `this` is bound to the SyncServer;
--- a/services/sync/tests/unit/test_addons_reconciler.js
+++ b/services/sync/tests/unit/test_addons_reconciler.js
@@ -66,17 +66,17 @@ add_test(function test_install_detection
   let after = new Date();
 
   do_check_eq(1, Object.keys(reconciler.addons).length);
   do_check_true(addon.id in reconciler.addons);
   let record = reconciler.addons[addon.id];
 
   const KEYS = ["id", "guid", "enabled", "installed", "modified", "type",
                 "scope", "foreignInstall"];
-  for each (let key in KEYS) {
+  for (let key of KEYS) {
     do_check_true(key in record);
     do_check_neq(null, record[key]);
   }
 
   do_check_eq(addon.id, record.id);
   do_check_eq(addon.syncGUID, record.guid);
   do_check_true(record.enabled);
   do_check_true(record.installed);
--- a/services/sync/tests/unit/test_addons_store.js
+++ b/services/sync/tests/unit/test_addons_store.js
@@ -199,17 +199,17 @@ add_test(function test_addon_syncability
 
   do_check_false(store.isAddonSyncable(null));
 
   let addon = installAddon("test_bootstrap1_1");
   do_check_true(store.isAddonSyncable(addon));
 
   let dummy = {};
   const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall"];
-  for each (let k in KEYS) {
+  for (let k of KEYS) {
     dummy[k] = addon[k];
   }
 
   do_check_true(store.isAddonSyncable(dummy));
 
   dummy.type = "UNSUPPORTED";
   do_check_false(store.isAddonSyncable(dummy));
   dummy.type = addon.type;
@@ -238,26 +238,26 @@ add_test(function test_addon_syncability
   ];
 
   let untrusted = [
     "http://addons.mozilla.org/foo",     // non-https
     "ftps://addons.mozilla.org/foo",     // non-https
     "https://untrusted.example.com/foo", // non-trusted hostname`
   ];
 
-  for each (let uri in trusted) {
+  for (let uri of trusted) {
     do_check_true(store.isSourceURITrusted(createURI(uri)));
   }
 
-  for each (let uri in untrusted) {
+  for (let uri of untrusted) {
     do_check_false(store.isSourceURITrusted(createURI(uri)));
   }
 
   Svc.Prefs.set("addons.trustedSourceHostnames", "");
-  for each (let uri in trusted) {
+  for (let uri of trusted) {
     do_check_false(store.isSourceURITrusted(createURI(uri)));
   }
 
   Svc.Prefs.set("addons.trustedSourceHostnames", "addons.mozilla.org");
   do_check_true(store.isSourceURITrusted(createURI("https://addons.mozilla.org/foo")));
 
   Svc.Prefs.reset("addons.trustedSourceHostnames");
 
@@ -273,17 +273,17 @@ add_test(function test_ignore_hotfixes()
   // extensions.hotfix.id pref.
   let prefs = new Preferences("extensions.");
 
   let addon = installAddon("test_bootstrap1_1");
   do_check_true(store.isAddonSyncable(addon));
 
   let dummy = {};
   const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall"];
-  for each (let k in KEYS) {
+  for (let k of KEYS) {
     dummy[k] = addon[k];
   }
 
   // Basic sanity check.
   do_check_true(store.isAddonSyncable(dummy));
 
   prefs.set("hotfix.id", dummy.id);
   do_check_false(store.isAddonSyncable(dummy));
--- a/services/sync/tests/unit/test_bookmark_store.js
+++ b/services/sync/tests/unit/test_bookmark_store.js
@@ -75,18 +75,18 @@ add_test(function test_bookmark_create()
                 fxrecord.description);
     do_check_eq(PlacesUtils.bookmarks.getFolderIdForItem(id),
                 PlacesUtils.bookmarks.toolbarFolder);
     do_check_eq(PlacesUtils.bookmarks.getKeywordForBookmark(id), fxrecord.keyword);
 
     _("Have the store create a new record object. Verify that it has the same data.");
     let newrecord = store.createRecord(fxrecord.id);
     do_check_true(newrecord instanceof Bookmark);
-    for each (let property in ["type", "bmkUri", "description", "title",
-                               "keyword", "parentName", "parentid"]) {
+    for (let property of ["type", "bmkUri", "description", "title",
+                          "keyword", "parentName", "parentid"]) {
       do_check_eq(newrecord[property], fxrecord[property]);
     }
     do_check_true(Utils.deepEquals(newrecord.tags.sort(),
                                    fxrecord.tags.sort()));
 
     _("The calculated sort index is based on frecency data.");
     do_check_true(newrecord.sortindex >= 150);
 
@@ -192,17 +192,17 @@ add_test(function test_folder_create() {
                 PlacesUtils.bookmarks.TYPE_FOLDER);
     do_check_eq(PlacesUtils.bookmarks.getItemTitle(id), folder.title);
     do_check_eq(PlacesUtils.bookmarks.getFolderIdForItem(id),
                 PlacesUtils.bookmarks.toolbarFolder);
 
     _("Have the store create a new record object. Verify that it has the same data.");
     let newrecord = store.createRecord(folder.id);
     do_check_true(newrecord instanceof BookmarkFolder);
-    for each (let property in ["title", "parentName", "parentid"])
+    for (let property of ["title", "parentName", "parentid"])
       do_check_eq(newrecord[property], folder[property]);
 
     _("Folders have high sort index to ensure they're synced first.");
     do_check_eq(newrecord.sortindex, 1000000);
   } finally {
     _("Clean up.");
     store.wipe();
     run_next_test();
--- a/services/sync/tests/unit/test_clients_engine.js
+++ b/services/sync/tests/unit/test_clients_engine.js
@@ -323,17 +323,17 @@ add_test(function test_command_validatio
     ["wipeAll",     ["foo"],  false],
     ["wipeEngine",  ["tabs"], true ],
     ["wipeEngine",  [],       false],
     ["logout",      [],       true ],
     ["logout",      ["foo"],  false],
     ["__UNKNOWN__", [],       false]
   ];
 
-  for each (let [action, args, expectedResult] in testCommands) {
+  for (let [action, args, expectedResult] of testCommands) {
     let remoteId = Utils.makeGUID();
     let rec = new ClientsRec("clients", remoteId);
 
     store.create(rec);
     store.createRecord(remoteId, "clients");
 
     engine.sendCommand(action, args, remoteId);
 
--- a/services/sync/tests/unit/test_collections_recovery.js
+++ b/services/sync/tests/unit/test_collections_recovery.js
@@ -28,17 +28,17 @@ add_identity_test(this, function test_mi
 
   let handlers = {
     "/1.1/johndoe/info/collections": maybe_empty(johnHelper.handler),
     "/1.1/johndoe/storage/crypto/keys": johnU("crypto", new ServerWBO("keys").handler()),
     "/1.1/johndoe/storage/meta/global": johnU("meta",   new ServerWBO("global").handler())
   };
   let collections = ["clients", "bookmarks", "forms", "history",
                      "passwords", "prefs", "tabs"];
-  for each (let coll in collections) {
+  for (let coll of collections) {
     handlers["/1.1/johndoe/storage/" + coll] =
       johnU(coll, new ServerCollection({}, true).handler());
   }
   let server = httpd_setup(handlers);
   Service.serverURL = server.baseURI;
 
   try {
     let fresh = 0;
--- a/services/sync/tests/unit/test_jpakeclient.js
+++ b/services/sync/tests/unit/test_jpakeclient.js
@@ -364,17 +364,17 @@ add_test(function test_wrongPIN() {
   });
 
   let pairingStartCalledOnReceiver = false;
   let rec = new JPAKEClient({
     __proto__: BaseController,
     displayPIN: function displayPIN(pin) {
       this.cid = pin.slice(JPAKE_LENGTH_SECRET);
       let secret = pin.slice(0, JPAKE_LENGTH_SECRET);
-      secret = [char for each (char in secret)].reverse().join("");
+      secret = Array.prototype.slice.call(secret).reverse().join("");
       let new_pin = secret + this.cid;
       _("Received PIN " + pin + ", but I'm entering " + new_pin);
 
       Utils.nextTick(function() { snd.pairWithPIN(new_pin, false); });
     },
     onPairingStart: function onPairingStart() {
       pairingStartCalledOnReceiver = true;
     },
--- a/services/sync/tests/unit/test_resource.js
+++ b/services/sync/tests/unit/test_resource.js
@@ -135,17 +135,17 @@ function server_headers(metadata, respon
     let header = headers.getNext().toString();
     if (ignore_headers.indexOf(header) == -1) {
       header_names.push(header);
     }
   }
   header_names = header_names.sort();
 
   headers = {};
-  for each (let header in header_names) {
+  for (let header of header_names) {
     headers[header] = metadata.getHeader(header);
   }
   let body = JSON.stringify(headers);
   response.setStatusLine(metadata.httpVersion, 200, "OK");
   response.bodyOutputStream.write(body, body.length);
 }
 
 function run_test() {
--- a/services/sync/tests/unit/test_resource_async.js
+++ b/services/sync/tests/unit/test_resource_async.js
@@ -135,17 +135,17 @@ function server_headers(metadata, respon
     let header = headers.getNext().toString();
     if (ignore_headers.indexOf(header) == -1) {
       header_names.push(header);
     }
   }
   header_names = header_names.sort();
 
   headers = {};
-  for each (let header in header_names) {
+  for (let header of header_names) {
     headers[header] = metadata.getHeader(header);
   }
   let body = JSON.stringify(headers);
   response.setStatusLine(metadata.httpVersion, 200, "OK");
   response.bodyOutputStream.write(body, body.length);
 }
 
 var quotaValue;
--- a/services/sync/tests/unit/test_service_startup.js
+++ b/services/sync/tests/unit/test_service_startup.js
@@ -24,17 +24,17 @@ function run_test() {
 
   Cu.import("resource://services-sync/service.js");
 
   _("Service is enabled.");
   do_check_eq(Service.enabled, true);
 
   _("Engines are registered.");
   let engines = Service.engineManager.getAll();
-  do_check_true(Utils.deepEquals([engine.name for each (engine in engines)],
+  do_check_true(Utils.deepEquals(engines.map(engine => engine.name),
                                  ['tabs', 'bookmarks', 'forms', 'history']));
 
   _("Observers are notified of startup");
   do_test_pending();
 
   do_check_false(Service.status.ready);
   do_check_false(xps.ready);
   Observers.add("weave:service:ready", function (subject, data) {
--- a/services/sync/tests/unit/test_status.js
+++ b/services/sync/tests/unit/test_status.js
@@ -13,19 +13,19 @@ function run_test() {
   do_check_eq(Status.login, LOGIN_SUCCEEDED);
   for (let name in Status.engines) {
     do_throw('Status.engines should be empty.');
   }
   do_check_eq(Status.partial, false);
 
 
   // Check login status
-  for each (let code in [LOGIN_FAILED_NO_USERNAME,
-                         LOGIN_FAILED_NO_PASSWORD,
-                         LOGIN_FAILED_NO_PASSPHRASE]) {
+  for (let code of [LOGIN_FAILED_NO_USERNAME,
+                    LOGIN_FAILED_NO_PASSWORD,
+                    LOGIN_FAILED_NO_PASSPHRASE]) {
     Status.login = code;
     do_check_eq(Status.login, code);
     do_check_eq(Status.service, CLIENT_NOT_CONFIGURED);
     Status.resetSync();
   }
 
   Status.login = LOGIN_FAILED;
   do_check_eq(Status.login, LOGIN_FAILED);
--- a/services/sync/tests/unit/test_tab_tracker.js
+++ b/services/sync/tests/unit/test_tab_tracker.js
@@ -48,42 +48,42 @@ function run_test() {
                                  [clientsEngine.localID]));
 
   let logs;
 
   _("Test listeners are registered on windows");
   logs = fakeSvcWinMediator();
   Svc.Obs.notify("weave:engine:start-tracking");
   do_check_eq(logs.length, 2);
-  for each (let log in logs) {
+  for (let log of logs) {
     do_check_eq(log.addTopics.length, 5);
     do_check_true(log.addTopics.indexOf("pageshow") >= 0);
     do_check_true(log.addTopics.indexOf("TabOpen") >= 0);
     do_check_true(log.addTopics.indexOf("TabClose") >= 0);
     do_check_true(log.addTopics.indexOf("TabSelect") >= 0);
     do_check_true(log.addTopics.indexOf("unload") >= 0);
     do_check_eq(log.remTopics.length, 0);
   }
 
   _("Test listeners are unregistered on windows");
   logs = fakeSvcWinMediator();
   Svc.Obs.notify("weave:engine:stop-tracking");
   do_check_eq(logs.length, 2);
-  for each (let log in logs) {
+  for (let log of logs) {
     do_check_eq(log.addTopics.length, 0);
     do_check_eq(log.remTopics.length, 5);
     do_check_true(log.remTopics.indexOf("pageshow") >= 0);
     do_check_true(log.remTopics.indexOf("TabOpen") >= 0);
     do_check_true(log.remTopics.indexOf("TabClose") >= 0);
     do_check_true(log.remTopics.indexOf("TabSelect") >= 0);
     do_check_true(log.remTopics.indexOf("unload") >= 0);
   }
 
   _("Test tab listener");
-  for each (let evttype in ["TabOpen", "TabClose", "TabSelect"]) {
+  for (let evttype of ["TabOpen", "TabClose", "TabSelect"]) {
     // Pretend we just synced.
     tracker.clearChangedIDs();
     do_check_false(tracker.modified);
 
     // Send a fake tab event
     tracker.onTab({type: evttype , originalTarget: evttype});
     do_check_true(tracker.modified);
     do_check_true(Utils.deepEquals(Object.keys(engine.getChangedIDs()),
--- a/services/sync/tps/extensions/mozmill/resource/driver/controller.js
+++ b/services/sync/tps/extensions/mozmill/resource/driver/controller.js
@@ -39,17 +39,21 @@ waitForEvents.prototype = {
     if (node.getNode != undefined)
       node = node.getNode();
 
     this.events = events;
     this.node = node;
     node.firedEvents = {};
     this.registry = {};
 
-    for each (var e in events) {
+    if (!events) {
+      return;
+    }
+    for (var key in events) {
+      var e = events[key];
       var listener = function (event) {
         this.firedEvents[event.type] = true;
       }
 
       this.registry[e] = listener;
       this.registry[e].result = false;
       this.node.addEventListener(e, this.registry[e], true);
     }
--- a/services/sync/tps/extensions/mozmill/resource/driver/elementslib.js
+++ b/services/sync/tps/extensions/mozmill/resource/driver/elementslib.js
@@ -299,31 +299,31 @@ var _returnResult = function (results) {
     return results[0];
   } else {
     return results;
   }
 }
 
 var _forChildren = function (element, name, value) {
   var results = [];
-  var nodes = [e for each (e in element.childNodes) if (e)]
+  var nodes = Array.from(element.childNodes).filter(e => e);
 
   for (var i in nodes) {
     var n = nodes[i];
     if (n[name] == value) {
       results.push(n);
     }
   }
 
   return results;
 }
 
 var _forAnonChildren = function (_document, element, name, value) {
   var results = [];
-  var nodes = [e for each (e in _document.getAnoymousNodes(element)) if (e)];
+  var nodes = Array.from(_document.getAnoymousNodes(element)).filter(e => e);
 
   for (var i in nodes ) {
     var n = nodes[i];
     if (n[name] == value) {
       results.push(n);
     }
   }
 
@@ -376,17 +376,17 @@ var _byAnonAttrib = function (_document,
     }
 
     var result = _document.getAnonymousElementByAttribute(parent, k, v);
     if (result) {
       return result;
     }
   }
 
-  var nodes = [n for each (n in _document.getAnonymousNodes(parent)) if (n.getAttribute)];
+  var nodes = Array.from(_document.getAnonymousNodes(parent)).filter(n => n.getAttribute);
 
   function resultsForNodes (nodes) {
     for (var i in nodes) {
       var n = nodes[i];
       requirementPass = 0;
       requirementLength = 0;
 
       for (var a in attributes) {
@@ -399,17 +399,17 @@ var _byAnonAttrib = function (_document,
       if (requirementPass == requirementLength) {
         results.push(n);
       }
     }
   }
 
   resultsForNodes(nodes);
   if (results.length == 0) {
-    resultsForNodes([n for each (n in parent.childNodes) if (n != undefined && n.getAttribute)])
+    resultsForNodes(Array.from(parent.childNodes).filter(n => n != undefined && n.getAttribute));
   }
 
   return _returnResult(results)
 }
 
 var _byIndex = function (_document, parent, i) {
   if (parent instanceof Array) {
     return parent[i];
@@ -435,17 +435,17 @@ var _anonByIndex = function (_document, 
  *
  * Finds an element by Lookup expression
  */
 function Lookup(_document, expression) {
   if (expression == undefined) {
     throw new Error('Lookup constructor did not recieve enough arguments.');
   }
 
-  var expSplit = [e for each (e in smartSplit(expression) ) if (e != '')];
+  var expSplit = smartSplit(expression).filter(e => e != '');
   expSplit.unshift(_document);
 
   var nCases = {'id':_byID, 'name':_byName, 'attrib':_byAttrib, 'index':_byIndex};
   var aCases = {'name':_anonByName, 'attrib':_anonByAttrib, 'index':_anonByIndex};
 
   /**
    * Reduces the lookup expression
    * @param {Object} parentNode
--- a/services/sync/tps/extensions/mozmill/resource/modules/frame.js
+++ b/services/sync/tps/extensions/mozmill/resource/modules/frame.js
@@ -251,17 +251,17 @@ events.endModule = function (aModule) {
 }
 
 events.pass = function (obj) {
   // a low level event, such as a keystroke, succeeds
   if (events.currentTest) {
     events.currentTest.__passes__.push(obj);
   }
 
-  for each (var timer in timers) {
+  for (var timer of timers) {
     timer.actions.push(
       {"currentTest": events.currentModule.__file__ + "::" + events.currentTest.__name__,
        "obj": obj,
        "result": "pass"}
     );
   }
 
   events.fireEvent('pass', obj);
@@ -281,17 +281,17 @@ events.fail = function (obj) {
     };
   }
 
   // a low level event, such as a keystroke, fails
   if (events.currentTest) {
     events.currentTest.__fails__.push(obj);
   }
 
-  for each (var time in timers) {
+  for (var time of timers) {
     timer.actions.push(
       {"currentTest": events.currentModule.__file__ + "::" + events.currentTest.__name__,
        "obj": obj,
        "result": "fail"}
     );
   }
 
   events.fireEvent('fail', obj);
@@ -320,17 +320,17 @@ events.fireEvent = function (name, obj) 
   }
 
   if (this.listeners[name]) {
     for (var i in this.listeners[name]) {
       this.listeners[name][i](obj);
     }
   }
 
-  for each(var listener in this.globalListeners) {
+  for (var listener of this.globalListeners) {
     listener(name, obj);
   }
 }
 
 events.addListener = function (name, listener) {
   if (this.listeners[name]) {
     this.listeners[name].push(listener);
   } else if (name == '') {
--- a/services/sync/tps/extensions/mozmill/resource/stdlib/os.js
+++ b/services/sync/tps/extensions/mozmill/resource/stdlib/os.js
@@ -32,17 +32,17 @@ function getFileForPath(path) {
 
 function abspath(rel, file) {
   var relSplit = rel.split('/');
 
   if (relSplit[0] == '..' && !file.isDirectory()) {
     file = file.parent;
   }
 
-  for each(var p in relSplit) {
+  for (var p of relSplit) {
     if (p == '..') {
       file = file.parent;
     } else if (p == '.') {
       if (!file.isDirectory()) {
         file = file.parent;
       }
     } else {
       file.append(p);
--- a/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js
+++ b/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js
@@ -163,18 +163,17 @@
 
    exports.Loader = function Loader(options) {
      options = {__proto__: options};
      if (options.fs === undefined) {
        var rootPaths = options.rootPath || options.rootPaths;
        if (rootPaths) {
          if (rootPaths.constructor.name != "Array")
            rootPaths = [rootPaths];
-         var fses = [new exports.LocalFileSystem(path)
-                     for each (path in rootPaths)];
+         var fses = rootPaths.map(path => new exports.LocalFileSystem(path));
          options.fs = new exports.CompositeFileSystem(fses);
        } else
          options.fs = new exports.LocalFileSystem();
      }
      if (options.sandboxFactory === undefined)
        options.sandboxFactory = new exports.SandboxFactory(
          options.defaultPrincipal
        );
--- a/services/sync/tps/extensions/mozmill/resource/stdlib/utils.js
+++ b/services/sync/tps/extensions/mozmill/resource/stdlib/utils.js
@@ -78,27 +78,27 @@ function getWindows(type) {
   if (type == "") {
     windows.push(hwindow);
   }
 
   return windows;
 }
 
 function getMethodInWindows(methodName) {
-  for each (var w in getWindows()) {
+  for (var w of getWindows()) {
     if (w[methodName] != undefined) {
       return w[methodName];
     }
   }
 
   throw new Error("Method with name: '" + methodName + "' is not in any open window.");
 }
 
 function getWindowByTitle(title) {
-  for each (var w in getWindows()) {
+  for (var w of getWindows()) {
     if (w.document.title && w.document.title == title) {
       return w;
     }
   }
 
   throw new Error("Window with title: '" + title + "' not found.");
 }
 
--- a/services/sync/tps/extensions/tps/resource/modules/history.jsm
+++ b/services/sync/tps/extensions/tps/resource/modules/history.jsm
@@ -28,17 +28,17 @@ var DumpHistory = function TPS_History__
   let options = PlacesUtils.history.getNewQueryOptions();
   let root = PlacesUtils.history.executeQuery(query, options).root;
   root.containerOpen = true;
   Logger.logInfo("\n\ndumping history\n", true);
   for (var i = 0; i < root.childCount; i++) {
     let node = root.getChild(i);
     let uri = node.uri;
     let curvisits = HistoryEntry._getVisits(uri);
-    for each (var visit in curvisits) {
+    for (var visit of curvisits) {
       Logger.logInfo("URI: " + uri + ", type=" + visit.type + ", date=" + visit.date, true);
     }
   }
   root.containerOpen = false;
   Logger.logInfo("\nend history dump\n", true);
 };
 
 /**
@@ -105,17 +105,17 @@ var HistoryEntry = {
     Logger.AssertTrue("visits" in item && "uri" in item,
       "History entry in test file must have both 'visits' " +
       "and 'uri' properties");
     let uri = Services.io.newURI(item.uri, null, null);
     let place = {
       uri: uri,
       visits: []
     };
-    for each (visit in item.visits) {
+    for (let visit of item.visits) {
       place.visits.push({
         visitDate: usSinceEpoch + (visit.date * 60 * 60 * 1000 * 1000),
         transitionType: visit.type
       });
     }
     if ("title" in item) {
       place.title = item.title;
     }
@@ -145,28 +145,28 @@ var HistoryEntry = {
    *        the time the current Crossweave run was started
    * @return true if all the visits for the uri are found, otherwise false
    */
   Find: function(item, usSinceEpoch) {
     Logger.AssertTrue("visits" in item && "uri" in item,
       "History entry in test file must have both 'visits' " +
       "and 'uri' properties");
     let curvisits = this._getVisits(item.uri);
-    for each (visit in curvisits) {
-      for each (itemvisit in item.visits) {
+    for (let visit of curvisits) {
+      for (let itemvisit of item.visits) {
         let expectedDate = itemvisit.date * 60 * 60 * 1000 * 1000
             + usSinceEpoch;
         if (visit.type == itemvisit.type && visit.date == expectedDate) {
           itemvisit.found = true;
         }
       }
     }
 
     let all_items_found = true;
-    for each (itemvisit in item.visits) {
+    for (let itemvisit in item.visits) {
       all_items_found = all_items_found && "found" in itemvisit;
       Logger.logInfo("History entry for " + item.uri + ", type:" +
               itemvisit.type + ", date:" + itemvisit.date +
               ("found" in itemvisit ? " is present" : " is not present"));
     }
     return all_items_found;
   },
 
--- a/services/sync/tps/extensions/tps/resource/modules/tabs.jsm
+++ b/services/sync/tps/extensions/tps/resource/modules/tabs.jsm
@@ -45,17 +45,21 @@ var BrowserTabs = {
    * @param title The page title of the tab to find
    * @param profile The profile to search for tabs
    * @return true if the specified tab could be found, otherwise false
    */
   Find: function(uri, title, profile) {
     // Find the uri in Weave's list of tabs for the given profile.
     let engine = Weave.Service.engineManager.get("tabs");
     for (let [guid, client] in Iterator(engine.getAllClients())) {
-      for each (tab in client.tabs) {
+      if (!client.tabs) {
+        continue;
+      }
+      for (let key in client.tabs) {
+        let tab = client.tabs[key];
         let weaveTabUrl = tab.urlHistory[0];
         if (uri == weaveTabUrl && profile == client.clientName)
           if (title == undefined || title == tab.title)
             return true;
       }
     }
     return false;
   },
--- a/services/sync/tps/extensions/tps/resource/tps.jsm
+++ b/services/sync/tps/extensions/tps/resource/tps.jsm
@@ -280,17 +280,17 @@ var TPS = {
         break;
     }
     Logger.logPass("executing action " + action.toUpperCase() + " on windows");
   },
 
   HandleTabs: function (tabs, action) {
     this._tabsAdded = tabs.length;
     this._tabsFinished = 0;
-    for each (let tab in tabs) {
+    for (let tab of tabs) {
       Logger.logInfo("executing action " + action.toUpperCase() +
                      " on tab " + JSON.stringify(tab));
       switch(action) {
         case ACTION_ADD:
           // When adding tabs, we keep track of how many tabs we're adding,
           // and wait until we've received that many onload events from our
           // new tabs before continuing
           let that = this;
@@ -325,17 +325,17 @@ var TPS = {
         default:
           Logger.AssertTrue(false, "invalid action: " + action);
       }
     }
     Logger.logPass("executing action " + action.toUpperCase() + " on tabs");
   },
 
   HandlePrefs: function (prefs, action) {
-    for each (pref in prefs) {
+    for (let pref of prefs) {
       Logger.logInfo("executing action " + action.toUpperCase() +
                      " on pref " + JSON.stringify(pref));
       let preference = new Preference(pref);
       switch(action) {
         case ACTION_MODIFY:
           preference.Modify();
           break;
         case ACTION_VERIFY:
@@ -344,17 +344,17 @@ var TPS = {
         default:
           Logger.AssertTrue(false, "invalid action: " + action);
       }
     }
     Logger.logPass("executing action " + action.toUpperCase() + " on pref");
   },
 
   HandleForms: function (data, action) {
-    for each (datum in data) {
+    for (let datum of data) {
       Logger.logInfo("executing action " + action.toUpperCase() +
                      " on form entry " + JSON.stringify(datum));
       let formdata = new FormData(datum, this._usSinceEpoch);
       switch(action) {
         case ACTION_ADD:
           formdata.Create();
           break;
         case ACTION_DELETE:
@@ -372,17 +372,17 @@ var TPS = {
       }
     }
     Logger.logPass("executing action " + action.toUpperCase() +
                    " on formdata");
   },
 
   HandleHistory: function (entries, action) {
     try {
-      for each (entry in entries) {
+      for (let entry of entries) {
         Logger.logInfo("executing action " + action.toUpperCase() +
                        " on history entry " + JSON.stringify(entry));
         switch(action) {
           case ACTION_ADD:
             HistoryEntry.Add(entry, this._usSinceEpoch);
             break;
           case ACTION_DELETE:
             HistoryEntry.Delete(entry, this._usSinceEpoch);
@@ -405,17 +405,17 @@ var TPS = {
     catch(e) {
       DumpHistory();
       throw(e);
     }
   },
 
   HandlePasswords: function (passwords, action) {
     try {
-      for each (password in passwords) {
+      for (let password of passwords) {
         let password_id = -1;
         Logger.logInfo("executing action " + action.toUpperCase() +
                       " on password " + JSON.stringify(password));
         var password = new Password(password);
         switch (action) {
           case ACTION_ADD:
             Logger.AssertTrue(password.Create() > -1, "error adding password");
             break;
@@ -445,17 +445,17 @@ var TPS = {
     }
     catch(e) {
       DumpPasswords();
       throw(e);
     }
   },
 
   HandleAddons: function (addons, action, state) {
-    for each (let entry in addons) {
+    for (let entry of addons) {
       Logger.logInfo("executing action " + action.toUpperCase() +
                      " on addon " + JSON.stringify(entry));
       let addon = new Addon(this, entry);
       switch(action) {
         case ACTION_ADD:
           addon.install();
           break;
         case ACTION_DELETE:
@@ -476,19 +476,19 @@ var TPS = {
     }
     Logger.logPass("executing action " + action.toUpperCase() +
                    " on addons");
   },
 
   HandleBookmarks: function (bookmarks, action) {
     try {
       let items = [];
-      for (folder in bookmarks) {
+      for (let folder in bookmarks) {
         let last_item_pos = -1;
-        for each (bookmark in bookmarks[folder]) {
+        for (let bookmark of bookmarks[folder]) {
           Logger.clearPotentialError();
           let placesItem;
           bookmark['location'] = folder;
 
           if (last_item_pos != -1)
             bookmark['last_item_pos'] = last_item_pos;
           let item_id = -1;
 
@@ -520,17 +520,17 @@ var TPS = {
           }
 
           last_item_pos = placesItem.GetItemIndex();
           items.push(placesItem);
         }
       }
 
       if (action == ACTION_DELETE || action == ACTION_MODIFY) {
-        for each (item in items) {
+        for (let item of items) {
           Logger.logInfo("executing action " + action.toUpperCase() +
                          " on bookmark " + JSON.stringify(item));
           switch(action) {
             case ACTION_DELETE:
               item.Remove();
               break;
             case ACTION_MODIFY:
               if (item.updateProps != null)
@@ -684,17 +684,17 @@ var TPS = {
         this.DumpError("no profile defined for phase " + this._currentPhase);
         return;
       }
 
       // If we have restricted the active engines, unregister engines we don't
       // care about.
       if (settings.ignoreUnusedEngines && Array.isArray(this._enabledEngines)) {
         let names = {};
-        for each (let name in this._enabledEngines) {
+        for (let name of this._enabledEngines) {
           names[name] = true;
         }
 
         for (let engine of Weave.Service.engineManager.getEnabled()) {
           if (!(engine.name in names)) {
             Logger.logInfo("Unregistering unused engine: " + engine.name);
             Weave.Service.engineManager.unregister(engine);
           }