Backed out non-test part of changeset 635dddf89443 (bug 1515877) for breaking Gloda facet search. a=backout
authorJorg K <jorgk@jorgk.com>
Mon, 29 Apr 2019 20:37:15 +0200
changeset 34372 d26bb5a3349ffceaffc8409f32f2f3023b873385
parent 34371 2344f942f3852f1aafed52d9179f472f2282b987
child 34373 4192b7f68d5876f356b9191bf0a269ee3a9690a3
push id2407
push userclokep@gmail.com
push dateMon, 20 May 2019 17:11:26 +0000
treeherdercomm-beta@193428fd6fd4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1515877
Backed out non-test part of changeset 635dddf89443 (bug 1515877) for breaking Gloda facet search. a=backout
.eslintignore
mail/base/content/searchBar.js
mailnews/db/gloda/components/glautocomp.js
mailnews/db/gloda/components/jsmimeemitter.js
mailnews/db/gloda/content/autocomplete-richlistitem.js
mailnews/db/gloda/content/glodacomplete.xml
mailnews/db/gloda/modules/collection.js
mailnews/db/gloda/modules/connotent.js
mailnews/db/gloda/modules/databind.js
mailnews/db/gloda/modules/datamodel.js
mailnews/db/gloda/modules/datastore.js
mailnews/db/gloda/modules/dbview.js
mailnews/db/gloda/modules/explattr.js
mailnews/db/gloda/modules/facet.js
mailnews/db/gloda/modules/fundattr.js
mailnews/db/gloda/modules/gloda.js
mailnews/db/gloda/modules/index_ab.js
mailnews/db/gloda/modules/index_msg.js
mailnews/db/gloda/modules/indexer.js
mailnews/db/gloda/modules/log4moz.js
mailnews/db/gloda/modules/mimeTypeCategories.js
mailnews/db/gloda/modules/mimemsg.js
mailnews/db/gloda/modules/msg_search.js
mailnews/db/gloda/modules/noun_freetag.js
mailnews/db/gloda/modules/noun_mimetype.js
mailnews/db/gloda/modules/noun_tag.js
mailnews/db/gloda/modules/query.js
mailnews/db/gloda/modules/suffixtree.js
mailnews/db/gloda/modules/utils.js
--- a/.eslintignore
+++ b/.eslintignore
@@ -57,16 +57,17 @@ editor/ui/dialogs/content/EditorSaveAsCh
 editor/ui/dialogs/content/EdLinkChecker.js
 editor/ui/dialogs/content/EdLinkChecker.xul
 editor/ui/dialogs/content/EdSnapToGrid.js
 editor/ui/dialogs/content/EdSnapToGrid.xul
 editor/ui/texzilla/**
 
 # mailnews exclusions
 mailnews/mailnews.js
+mailnews/db/*
 mailnews/imap/*
 mailnews/import/*
 mailnews/intl/*
 mailnews/jsaccount/*
 mailnews/mime/*
 
 # mailnews/extensions exclusions
 mailnews/extensions/*
--- a/mail/base/content/searchBar.js
+++ b/mail/base/content/searchBar.js
@@ -3,16 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var {StringBundle} = ChromeUtils.import("resource:///modules/StringBundle.js");
 
 var gSearchBundle;
 
 var gStatusBar = document.getElementById("statusbar-icon");
 
+var gGlodaCompleteStrings = new StringBundle("chrome://messenger/locale/glodaComplete.properties");
+
 /**
  * The glodasearch widget is a UI widget (the #searchInput textbox) which is
  * outside of the mailTabType's display panel, but acts as though it were within
  * it..  This means we need to use a tab monitor so that we can appropriately
  * update the contents of the textbox.
  *
  * Every time a tab is changed, we save the state of the text box and restore
  *  its previous value for the tab we are switching to, as well as whether this
--- a/mailnews/db/gloda/components/glautocomp.js
+++ b/mailnews/db/gloda/components/glautocomp.js
@@ -20,58 +20,58 @@ var FreeTagNoun = null;
 
 function ResultRowFullText(aItem, words, typeForStyle) {
   this.item = aItem;
   this.words = words;
   this.typeForStyle = "gloda-fulltext-" + typeForStyle;
 }
 ResultRowFullText.prototype = {
   multi: false,
-  fullText: true,
+  fullText: true
 };
 
 function ResultRowSingle(aItem, aCriteriaType, aCriteria, aExplicitNounID) {
   this.nounID = aExplicitNounID || aItem.NOUN_ID;
   this.nounDef = Gloda._nounIDToDef[this.nounID];
   this.criteriaType = aCriteriaType;
   this.criteria = aCriteria;
   this.item = aItem;
   this.typeForStyle = "gloda-single-" + this.nounDef.name;
 }
 ResultRowSingle.prototype = {
   multi: false,
-  fullText: false,
+  fullText: false
 };
 
 function ResultRowMulti(aNounID, aCriteriaType, aCriteria, aQuery) {
   this.nounID = aNounID;
   this.nounDef = Gloda._nounIDToDef[aNounID];
   this.criteriaType = aCriteriaType;
   this.criteria = aCriteria;
   this.collection = aQuery.getCollection(this);
   this.collection.becomeExplicit();
   this.renderer = null;
 }
 ResultRowMulti.prototype = {
   multi: true,
   typeForStyle: "gloda-multi",
   fullText: false,
-  onItemsAdded(aItems) {
+  onItemsAdded: function(aItems) {
     if (this.renderer) {
-      for (let [, item] of aItems.entries()) {
+      for (let [iItem, item] of aItems.entries()) {
         this.renderer.renderItem(item);
       }
     }
   },
-  onItemsModified(aItems) {
+  onItemsModified: function(aItems) {
   },
-  onItemsRemoved(aItems) {
+  onItemsRemoved: function(aItems) {
   },
-  onQueryCompleted() {
-  },
+  onQueryCompleted: function() {
+  }
 };
 
 function nsAutoCompleteGlodaResult(aListener, aCompleter, aString) {
   this.listener = aListener;
   this.completer = aCompleter;
   this.searchString = aString;
   this._results = [];
   this._pendingCount = 0;
@@ -79,97 +79,101 @@ function nsAutoCompleteGlodaResult(aList
   // Track whether we have reported anything to the complete controller so
   //  that we know not to send notifications to it during calls to addRows
   //  prior to that point.
   this._initiallyReported = false;
 
   this.wrappedJSObject = this;
 }
 nsAutoCompleteGlodaResult.prototype = {
-  getObjectAt(aIndex) {
+  getObjectAt: function(aIndex) {
     return this._results[aIndex] || null;
   },
-  markPending(aCompleter) {
+  markPending: function ACGR_markPending(aCompleter) {
     this._pendingCount++;
   },
-  markCompleted(aCompleter) {
+  markCompleted: function ACGR_markCompleted(aCompleter) {
     if (--this._pendingCount == 0 && this.active) {
       this.listener.onSearchResult(this.completer, this);
     }
   },
-  announceYourself() {
+  announceYourself: function ACGR_announceYourself() {
     this._initiallyReported = true;
     this.listener.onSearchResult(this.completer, this);
   },
-  addRows(aRows) {
+  addRows: function ACGR_addRows(aRows) {
     if (!aRows.length)
       return;
     this._results.push.apply(this._results, aRows);
     if (this._initiallyReported && this.active) {
       this.listener.onSearchResult(this.completer, this);
     }
   },
   // ==== nsIAutoCompleteResult
   searchString: null,
   get searchResult() {
     if (this._problem)
       return Ci.nsIAutoCompleteResult.RESULT_FAILURE;
     if (this._results.length)
       return (!this._pendingCount) ? Ci.nsIAutoCompleteResult.RESULT_SUCCESS
                           : Ci.nsIAutoCompleteResult.RESULT_SUCCESS_ONGOING;
-    return (!this._pendingCount) ? Ci.nsIAutoCompleteResult.RESULT_NOMATCH
+    else
+      return (!this._pendingCount) ? Ci.nsIAutoCompleteResult.RESULT_NOMATCH
                           : Ci.nsIAutoCompleteResult.RESULT_NOMATCH_ONGOING;
   },
   active: false,
   defaultIndex: -1,
   errorDescription: null,
   get matchCount() {
     return (this._results === null) ? 0 : this._results.length;
   },
   // this is the lower text, (shows the url in firefox)
   // we try and show the contact's name here.
-  getValueAt(aIndex) {
+  getValueAt: function(aIndex) {
     let thing = this._results[aIndex];
     return thing.name || thing.value || thing.subject || null;
   },
-  getLabelAt(aIndex) {
+  getLabelAt: function(aIndex) {
     return this.getValueAt(aIndex);
   },
   // rich uses this to be the "title".  it is the upper text
   // we try and show the identity here.
-  getCommentAt(aIndex) {
+  getCommentAt: function(aIndex) {
     let thing = this._results[aIndex];
     if (thing.value) // identity
       return thing.contact.name;
-    return thing.name || thing.subject;
+    else
+      return thing.name || thing.subject;
   },
   // rich uses this to be the "type"
-  getStyleAt(aIndex) {
+  getStyleAt: function(aIndex) {
     let row = this._results[aIndex];
     return row.typeForStyle;
   },
   // rich uses this to be the icon
-  getImageAt(aIndex) {
+  getImageAt: function(aIndex) {
     let thing = this._results[aIndex];
     if (!thing.value)
       return null;
 
     return ""; // we don't want to use gravatars as is.
     /*
     let md5hash = GlodaUtils.md5HashString(thing.value);
     let gravURL = "http://www.gravatar.com/avatar/" + md5hash +
                                 "?d=identicon&s=32&r=g";
     return gravURL;
     */
   },
-  getFinalCompleteValueAt(aIndex) {
+  getFinalCompleteValueAt: function(aIndex) {
     return this.getValueAt(aIndex);
   },
-  removeValueAt() {},
-  _stop() {},
+  removeValueAt: function() {},
+
+  _stop: function() {
+  }
 };
 
 var MAX_POPULAR_CONTACTS = 200;
 
 /**
  * Complete contacts/identities based on name/email.  Instant phase is based on
  *  a suffix-tree built of popular contacts/identities.  Delayed phase relies
  *  on a LIKE search of all known contacts.
@@ -177,36 +181,36 @@ var MAX_POPULAR_CONTACTS = 200;
 function ContactIdentityCompleter() {
   // get all the contacts
   let contactQuery = Gloda.newQuery(Gloda.NOUN_CONTACT);
   contactQuery.orderBy("-popularity").limit(MAX_POPULAR_CONTACTS);
   this.contactCollection = contactQuery.getCollection(this, null);
   this.contactCollection.becomeExplicit();
 }
 ContactIdentityCompleter.prototype = {
-  _popularitySorter(a, b) { return b.popularity - a.popularity; },
-  complete(aResult, aString) {
+  _popularitySorter: function(a, b){ return b.popularity - a.popularity; },
+  complete: function ContactIdentityCompleter_complete(aResult, aString) {
     if (aString.length < 3) {
       // In CJK, first name or last name is sometime used as 1 character only.
       // So we allow autocompleted search even if 1 character.
       //
       // [U+3041 - U+9FFF ... Full-width Katakana, Hiragana
       //                      and CJK Ideograph
       // [U+AC00 - U+D7FF ... Hangul
       // [U+F900 - U+FFDC ... CJK compatibility ideograph
       if (!aString.match(/[\u3041-\u9fff\uac00-\ud7ff\uf900-\uffdc]/))
         return false;
     }
 
     let matches;
     if (this.suffixTree) {
       matches = this.suffixTree.findMatches(aString.toLowerCase());
-    } else {
+    }
+    else
       matches = [];
-    }
 
     // let's filter out duplicates due to identity/contact double-hits by
     //  establishing a map based on the contact id for these guys.
     // let's also favor identities as we do it, because that gets us the
     //  most accurate gravat, potentially
     let contactToThing = {};
     for (let iMatch = 0; iMatch < matches.length; iMatch++) {
       let thing = matches[iMatch];
@@ -220,17 +224,17 @@ ContactIdentityCompleter.prototype = {
     matches = Object.keys(contactToThing).map(id => contactToThing[id]).
       map(val => val.NOUN_ID == Gloda.NOUN_IDENTITY ? val : val.identities[0]);
 
     let rows = matches.
       map(match => new ResultRowSingle(match, "text", aResult.searchString));
     aResult.addRows(rows);
 
     // - match against database contacts / identities
-    let pending = {contactToThing, pendingCount: 2};
+    let pending = {contactToThing: contactToThing, pendingCount: 2};
 
     let contactQuery = Gloda.newQuery(Gloda.NOUN_CONTACT);
     contactQuery.nameLike(contactQuery.WILDCARD, aString,
                           contactQuery.WILDCARD);
     pending.contactColl = contactQuery.getCollection(this, aResult);
     pending.contactColl.becomeExplicit();
 
     let identityQuery = Gloda.newQuery(Gloda.NOUN_IDENTITY);
@@ -238,23 +242,23 @@ ContactIdentityCompleter.prototype = {
         identityQuery.WILDCARD);
     pending.identityColl = identityQuery.getCollection(this, aResult);
     pending.identityColl.becomeExplicit();
 
     aResult._contactCompleterPending = pending;
 
     return true;
   },
-  onItemsAdded(aItems, aCollection) {
+  onItemsAdded: function(aItems, aCollection) {
   },
-  onItemsModified(aItems, aCollection) {
+  onItemsModified: function(aItems, aCollection) {
   },
-  onItemsRemoved(aItems, aCollection) {
+  onItemsRemoved: function(aItems, aCollection) {
   },
-  onQueryCompleted(aCollection) {
+  onQueryCompleted: function(aCollection) {
     // handle the initial setup case...
     if (aCollection.data == null) {
       // cheat and explicitly add our own contact...
       if (Gloda.myContact &&
           !(Gloda.myContact.id in this.contactCollection._idMap))
         this.contactCollection._onItemsAdded([Gloda.myContact]);
 
       // the set of identities owned by the contacts is automatically loaded as part
@@ -294,17 +298,17 @@ ContactIdentityCompleter.prototype = {
 
       let contactToThing = pending.contactToThing;
 
       let items;
 
       // check identities first because they are better than contacts in terms
       //  of display
       items = pending.identityColl.items;
-      for (let iIdentity = 0; iIdentity < items.length; iIdentity++) {
+      for (let iIdentity = 0; iIdentity < items.length; iIdentity++){
         let identity = items[iIdentity];
         if (!(identity.contactID in contactToThing)) {
           contactToThing[identity.contactID] = identity;
           possibleDudes.push(identity);
           // augment the identity with its contact's popularity
           identity.popularity = identity.contact.popularity;
         }
       }
@@ -325,41 +329,41 @@ ContactIdentityCompleter.prototype = {
       result.markCompleted(this);
 
       // the collections no longer care about the result, make it clear.
       delete pending.identityColl.data;
       delete pending.contactColl.data;
       // the result object no longer needs us or our data
       delete result._contactCompleterPending;
     }
-  },
+  }
 };
 
 /**
  * Complete tags that are used on contacts.
  */
 function ContactTagCompleter() {
   FreeTagNoun.populateKnownFreeTags();
   this._buildSuffixTree();
   FreeTagNoun.addListener(this);
 }
 ContactTagCompleter.prototype = {
-  _buildSuffixTree() {
+  _buildSuffixTree: function() {
     let tagNames = [], tags = [];
     for (let [tagName, tag] of Object.entries(FreeTagNoun.knownFreeTags)) {
       tagNames.push(tagName.toLowerCase());
       tags.push(tag);
     }
     this._suffixTree = new MultiSuffixTree(tagNames, tags);
     this._suffixTreeDirty = false;
   },
-  onFreeTagAdded(aTag) {
+  onFreeTagAdded: function(aTag) {
     this._suffixTreeDirty = true;
   },
-  complete(aResult, aString) {
+  complete: function ContactTagCompleter_complete(aResult, aString) {
     // now is not the best time to do this; have onFreeTagAdded use a timer.
     if (this._suffixTreeDirty)
       this._buildSuffixTree();
 
     if (aString.length < 2)
       return false; // no async mechanism that will add new rows
 
     let tags = this._suffixTree.findMatches(aString.toLowerCase());
@@ -369,60 +373,60 @@ ContactTagCompleter.prototype = {
       query.freeTags(tag);
       let resRow = new ResultRowMulti(Gloda.NOUN_CONTACT, "tag", tag.name,
                                       query);
       rows.push(resRow);
     }
     aResult.addRows(rows);
 
     return false; // no async mechanism that will add new rows
-  },
+  }
 };
 
 /**
  * Complete tags that are used on messages
  */
 function MessageTagCompleter() {
   this._buildSuffixTree();
 }
 MessageTagCompleter.prototype = {
-  _buildSuffixTree() {
+  _buildSuffixTree: function MessageTagCompleter__buildSufficeTree() {
     let tagNames = [], tags = [];
     let tagArray = TagNoun.getAllTags();
     for (let iTag = 0; iTag < tagArray.length; iTag++) {
       let tag = tagArray[iTag];
       tagNames.push(tag.tag.toLowerCase());
       tags.push(tag);
     }
     this._suffixTree = new MultiSuffixTree(tagNames, tags);
     this._suffixTreeDirty = false;
   },
-  complete(aResult, aString) {
+  complete: function MessageTagCompleter_complete(aResult, aString) {
     if (aString.length < 2)
       return false;
 
     let tags = this._suffixTree.findMatches(aString.toLowerCase());
     let rows = [];
     for (let tag of tags) {
       let resRow = new ResultRowSingle(tag, "tag", tag.tag, TagNoun.id);
       rows.push(resRow);
     }
     aResult.addRows(rows);
 
     return false; // no async mechanism that will add new rows
-  },
+  }
 };
 
 /**
  * Complete with helpful hints about full-text search
  */
 function FullTextCompleter() {
 }
 FullTextCompleter.prototype = {
-  complete(aResult, aSearchString) {
+  complete: function FullTextCompleter_complete(aResult, aSearchString) {
     if (aSearchString.length < 4)
       return false;
     // We use code very similar to that in msg_search.js, except that we
     // need to detect when we found phrases, as well as strip commas.
     aSearchString = aSearchString.trim();
     let terms = [];
     let phraseFound = false;
     while (aSearchString) {
@@ -446,26 +450,26 @@ FullTextCompleter.prototype = {
       if (spaceIndex == -1) {
         terms.push(aSearchString.replace(/,/g, ""));
         break;
       }
 
       term = aSearchString.substring(0, spaceIndex).replace(/,/g, "");
       if (term)
         terms.push(term);
-      aSearchString = aSearchString.substring(spaceIndex + 1);
+      aSearchString = aSearchString.substring(spaceIndex+1);
     }
 
     if (terms.length == 1 && !phraseFound)
       aResult.addRows([new ResultRowFullText(aSearchString, terms, "single")]);
     else
       aResult.addRows([new ResultRowFullText(aSearchString, terms, "all")]);
 
     return false; // no async mechanism that will add new rows
-  },
+  }
 };
 
 var LOG;
 
 function nsAutoCompleteGloda() {
   this.wrappedJSObject = this;
   try {
     // set up our awesome globals!
@@ -478,17 +482,17 @@ function nsAutoCompleteGloda() {
       loadNS = ChromeUtils.import("resource:///modules/gloda/suffixtree.js");
       MultiSuffixTree = loadNS.MultiSuffixTree;
       loadNS = ChromeUtils.import("resource:///modules/gloda/noun_tag.js");
       TagNoun = loadNS.TagNoun;
       loadNS = ChromeUtils.import("resource:///modules/gloda/noun_freetag.js");
       FreeTagNoun = loadNS.FreeTagNoun;
 
       loadNS = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
-      LOG = loadNS.Log4Moz.repository.getLogger("gloda.autocomp");
+      LOG = loadNS["Log4Moz"].repository.getLogger("gloda.autocomp");
     }
 
     this.completers = [];
     this.curResult = null;
 
     this.completers.push(new FullTextCompleter());        // not async.
     this.completers.push(new ContactIdentityCompleter()); // potentially async.
     this.completers.push(new ContactTagCompleter());      // not async.
@@ -498,44 +502,44 @@ function nsAutoCompleteGloda() {
   }
 }
 
 nsAutoCompleteGloda.prototype = {
   classID: Components.ID("{3bbe4d77-3f70-4252-9500-bc00c26f476d}"),
   QueryInterface: ChromeUtils.generateQI([
       Ci.nsIAutoCompleteSearch]),
 
-  startSearch(aString, aParam, aResult, aListener) {
+  startSearch: function(aString, aParam, aResult, aListener) {
     try {
       let result = new nsAutoCompleteGlodaResult(aListener, this, aString);
       // save this for hacky access to the search.  I somewhat suspect we simply
       //  should not be using the formal autocomplete mechanism at all.
       // Used in glodacomplete.xml.
       this.curResult = result;
 
       // Guard against late async results being sent.
       this.curResult.active = true;
 
       if (aParam == "global") {
         for (let completer of this.completers) {
           // they will return true if they have something pending.
           if (completer.complete(result, aString))
             result.markPending(completer);
         }
-      // } else {
+      //} else {
       //   It'd be nice to do autocomplete in the quicksearch modes based
       //   on the specific values for that mode in the current view.
       //   But we don't do that yet.
       }
 
       result.announceYourself();
     } catch (e) {
       logException(e);
     }
   },
 
-  stopSearch() {
+  stopSearch: function() {
     this.curResult.active = false;
-  },
+  }
 };
 
 var components = [nsAutoCompleteGloda];
 var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/mailnews/db/gloda/components/jsmimeemitter.js
+++ b/mailnews/db/gloda/components/jsmimeemitter.js
@@ -65,82 +65,85 @@ function MimeMessageEmitter() {
 
 var deathToNewlines = /\n/g;
 
 MimeMessageEmitter.prototype = {
   classID: Components.ID("{8cddbbbc-7ced-46b0-a936-8cddd1928c24}"),
 
   QueryInterface: ChromeUtils.generateQI([Ci.nsIMimeEmitter]),
 
-  initialize(aUrl, aChannel, aFormat) {
+  initialize: function mime_emitter_initialize(aUrl, aChannel, aFormat) {
     this._url = aUrl;
     this._curPart = new this._mimeMsg.MimeMessage();
     // the partName is intentionally ""!  not a place-holder!
     this._curPart.partName = "";
     this._curAttachment = "";
     this._partMap[""] = this._curPart;
 
     // pull options across...
     let options = this._mimeMsg.MsgHdrToMimeMessage.OPTION_TUNNEL;
     this._saneBodySize = (options && ("saneBodySize" in options)) ?
                            options.saneBodySize : false;
 
     this._mimeMsg.MsgHdrToMimeMessage.RESULT_RENDEVOUZ[aUrl.spec] =
       this._curPart;
   },
 
-  complete() {
+  complete: function mime_emitter_complete() {
     this._url = null;
 
     this._outputListener = null;
 
     this._curPart = null;
     this._curAttachment = null;
     this._partMap = null;
     this._bogusPartTranslation = null;
   },
 
-  setPipe(aInputStream, aOutputStream) {
+  setPipe: function mime_emitter_setPipe(aInputStream, aOutputStream) {
     // we do not care about these
   },
   set outputListener(aListener) {
     this._outputListener = aListener;
   },
   get outputListener() {
     return this._outputListener;
   },
 
-  _stripParams(aValue) {
+  _stripParams: function mime_emitter__stripParams(aValue) {
     let indexSemi = aValue.indexOf(";");
     if (indexSemi >= 0)
         aValue = aValue.substring(0, indexSemi);
     return aValue;
   },
 
-  _beginPayload(aContentType) {
+  _beginPayload: function mime_emitter__beginPayload(aContentType) {
     let contentTypeNoParams = this._stripParams(aContentType).toLowerCase();
     if (contentTypeNoParams == "text/plain" ||
         contentTypeNoParams == "text/html" ||
         contentTypeNoParams == "text/enriched") {
       this._curPart = new this._mimeMsg.MimeBody(contentTypeNoParams);
       this._writeBody = true;
-    } else if (contentTypeNoParams == "message/rfc822") {
+    }
+    else if (contentTypeNoParams == "message/rfc822") {
       // startHeader will take care of this
       this._curPart = new this._mimeMsg.MimeMessage();
       // do not fall through into the content-type setting case; this
       //  content-type needs to get clobbered by the actual content-type of
       //  the enclosed message.
       this._writeBody = false;
       return;
-    } else if (contentTypeNoParams.startsWith("multipart/")) {
-      // this is going to fall-down with TNEF encapsulation and such, we really
-      // need to just be consuming the object model.
+    }
+    // this is going to fall-down with TNEF encapsulation and such, we really
+    //  need to just be consuming the object model.
+    else if (contentTypeNoParams.startsWith("multipart/")) {
       this._curPart = new this._mimeMsg.MimeContainer(contentTypeNoParams);
       this._writeBody = false;
-    } else {
+    }
+    else {
       this._curPart = new this._mimeMsg.MimeUnknown(contentTypeNoParams);
       this._writeBody = false;
     }
     // put the full content-type in the headers and normalize out any newlines
     this._curPart.headers["content-type"] =
       [aContentType.replace(deathToNewlines, "")];
   },
 
@@ -156,17 +159,18 @@ MimeMessageEmitter.prototype = {
    *  addHeaderFields for the content-type and the x-jsemitter-part-path
    *  prior to the startHeader call.  This is because the MIME multipart
    *  container that holds the message is the one generating the notification.
    *  For that reason, we do not process them here, but instead in
    *  addHeaderField and _beginPayload.
    *
    * We do need to track our state for addHeaderField's benefit though.
    */
-  startHeader(aIsRootMailHeader, aIsHeaderOnly, aMsgID, aOutputCharset) {
+  startHeader: function mime_emitter_startHeader(aIsRootMailHeader,
+      aIsHeaderOnly, aMsgID, aOutputCharset) {
     this._state = kStateInHeaders;
   },
   /**
    * Receives a header field name and value for the current MIME part, which
    *  can be an rfc822/message or one of its sub-parts.
    *
    * The emitter architecture treats rfc822/messages as special because it was
    *  architected around presentation.  In that case, the organizing concept
@@ -179,63 +183,67 @@ MimeMessageEmitter.prototype = {
    *  odd pseudo-mime-part.  Because it has only one child, its headers are,
    *  in a way, its payload, but they also serve as the description of its
    *  MIME child part.  This introduces a complication in that we see the
    *  content-type for the message's "body" part before we actually see any
    *  of the headers.  To deal with this, we punt on the construction of the
    *  body part to the call to startBody() and predicate our logic on the
    *  _state field.
    */
-  addHeaderField(aField, aValue) {
+  addHeaderField: function mime_emitter_addHeaderField(aField, aValue) {
     if (this._state == kStateInBody) {
       aField = aField.toLowerCase();
-      if (aField == "content-type") {
+      if (aField == "content-type")
         this._beginPayload(aValue, true);
-      } else if (aField == "x-jsemitter-part-path") {
+      else if (aField == "x-jsemitter-part-path") {
         // This is either naming the current part, or referring to an already
         //  existing part (in the case of multipart/related on its second pass).
         // As such, check if the name already exists in our part map.
         let partName = this._stripParams(aValue);
         // if it does, then make the already-existing part at that path current
         if (partName in this._partMap) {
           this._curPart = this._partMap[partName];
           this._writeBody = "body" in this._curPart;
-        } else { // otherwise, name the part we are holding onto and place it.
+        }
+        // otherwise, name the part we are holding onto and place it.
+        else {
           this._curPart.partName = partName;
           this._placePart(this._curPart);
         }
-      } else if (aField == "x-jsemitter-encrypted" && aValue == "1") {
+      }
+      else if (aField == "x-jsemitter-encrypted" && aValue == "1") {
         this._curPart.isEncrypted = true;
       }
       // There is no other field to be emitted in the body case other than the
       //  ones we just handled.  (They were explicitly added for the js
       //  emitter.)
-    } else if (this._state == kStateInHeaders) {
+    }
+    else if (this._state == kStateInHeaders) {
       let lowerField = aField.toLowerCase();
       if (lowerField in this._curPart.headers)
         this._curPart.headers[lowerField].push(aValue);
       else
         this._curPart.headers[lowerField] = [aValue];
     }
   },
-  addAllHeaders(aAllHeaders, aHeaderSize) {
+  addAllHeaders: function mime_emitter_addAllHeaders(aAllHeaders, aHeaderSize) {
     // This is called by the parsing code after the calls to AddHeaderField (or
     //  AddAttachmentField if the part is an attachment), and seems to serve
     //  a specialized, quasi-redundant purpose.  (nsMimeBaseEmitter creates a
     //  nsIMimeHeaders instance and hands it to the nsIMsgMailNewsUrl.)
     // nop
   },
-  writeHTMLHeaders(aName) {
+  writeHTMLHeaders: function mime_emitter_writeHTMLHeaders(aName) {
     // It doesn't look like this should even be part of the interface; I think
     //  only the nsMimeHtmlDisplayEmitter::EndHeader call calls this signature.
     // nop
   },
-  endHeader(aName) {
+  endHeader: function mime_emitter_endHeader(aName) {
   },
-  updateCharacterSet(aCharset) {
+  updateCharacterSet: function mime_emitter_updateCharacterSet(aCharset) {
     // we do not need to worry about this.  it turns out this notification is
     //  exclusively for the benefit of the UI.  libmime, believe it or not,
     //  is actually doing the right thing under the hood and handles all the
     //  encoding issues for us.
     // so, get ready for the only time you will ever hear this:
     //  three cheers for libmime!
   },
 
@@ -246,28 +254,28 @@ MimeMessageEmitter.prototype = {
    *  motivating use-case is multipart/related which actually does generate
    *  everything in order on its first pass, but has a wacky second pass. It
    *  does not actually trigger the out-of-order code because we have
    *  augmented the libmime code to generate its x-jsemitter-part-path info
    *  a second time, in which case we reuse the part we already created.)
    *
    * @param aPart Part to place.
    */
-  _placePart(aPart) {
+  _placePart: function(aPart) {
     let partName = aPart.partName;
     this._partMap[partName] = aPart;
 
-    let [storagePartName, , parentPart] = this._findOrCreateParent(partName);
+    let [storagePartName, parentName, parentPart] = this._findOrCreateParent(partName);
     let lastDotIndex = storagePartName.lastIndexOf(".");
     if (parentPart !== undefined) {
-      let indexInParent = parseInt(storagePartName.substring(lastDotIndex + 1)) - 1;
+      let indexInParent = parseInt(storagePartName.substring(lastDotIndex+1)) - 1;
       // handle out-of-order notification...
-      if (indexInParent < parentPart.parts.length) {
+      if (indexInParent < parentPart.parts.length)
         parentPart.parts[indexInParent] = aPart;
-      } else {
+      else {
         while (indexInParent > parentPart.parts.length)
           parentPart.parts.push(null);
         parentPart.parts.push(aPart);
       }
     }
   },
 
   /**
@@ -277,77 +285,78 @@ MimeMessageEmitter.prototype = {
    * What happens in the case of encrypted emails (mimecryp.cpp):
    *  1. is the message
    *  1.1 doesn't exist
    *  1.1.1 is the multipart/alternative that holds the text/plain and text/html
    *  1.1.1.1 is text/plain
    *  1.1.1.2 is text/html
    * This function fills the missing bits.
    */
-  _findOrCreateParent(aPartName) {
+  _findOrCreateParent: function (aPartName) {
     let partName = aPartName + "";
     let parentName = partName.substring(0, partName.lastIndexOf("."));
     let parentPart;
     if (parentName in this._partMap) {
-      parentPart = this._partMap[parentName];
+      parentPart = this._partMap[parentName]
       let lastDotIndex = partName.lastIndexOf(".");
-      let indexInParent = parseInt(partName.substring(lastDotIndex + 1)) - 1;
+      let indexInParent = parseInt(partName.substring(lastDotIndex+1)) - 1;
       if ("parts" in parentPart && indexInParent == parentPart.parts.length - 1)
         return [partName, parentName, parentPart];
-      return this._findAnotherContainer(aPartName);
+      else
+        return this._findAnotherContainer(aPartName);
+    } else {
+      // Find the grandparent
+      let [, grandParentName, grandParentPart] = this._findOrCreateParent(parentName);
+      // Create the missing part.
+      let parentPart = new this._mimeMsg.MimeContainer("multipart/fake-container");
+      // Add it to the grandparent, remember we added it in the hierarchy.
+      grandParentPart.parts.push(parentPart);
+      this._partMap[parentName] = parentPart;
+      return [partName, parentName, parentPart];
     }
-
-    // Find the grandparent
-    let [, , grandParentPart] = this._findOrCreateParent(parentName);
-    // Create the missing part.
-    parentPart = new this._mimeMsg.MimeContainer("multipart/fake-container");
-    // Add it to the grandparent, remember we added it in the hierarchy.
-    grandParentPart.parts.push(parentPart);
-    this._partMap[parentName] = parentPart;
-    return [partName, parentName, parentPart];
   },
 
   /**
    * In the case of UUEncoded attachments, libmime tells us about the attachment
    *  as a child of a MimeBody. This obviously doesn't make us happy, so in case
    *  libmime wants us to attach an attachment to something that's not a
    *  container, we walk up the mime tree to find a suitable container to hold
    *  the attachment.
    * The results are cached so that they're consistent across calls — this
    *  ensures the call to _replacePart works fine.
    */
-  _findAnotherContainer(aPartName) {
+  _findAnotherContainer: function(aPartName) {
     if (aPartName in this._bogusPartTranslation)
       return this._bogusPartTranslation[aPartName];
 
     let parentName = aPartName + "";
     let parentPart;
     while (!(parentPart && "parts" in parentPart) && parentName.length) {
       parentName = parentName.substring(0, parentName.lastIndexOf("."));
       parentPart = this._partMap[parentName];
     }
     let childIndex = parentPart.parts.length;
-    let fallbackPartName = (parentName ? parentName + "." : "") + (childIndex + 1);
+    let fallbackPartName = (parentName ? parentName +"." : "")+(childIndex+1);
     return (this._bogusPartTranslation[aPartName] = [fallbackPartName, parentName, parentPart]);
   },
 
   /**
    * In the case of attachments, we need to replace an existing part with a
    *  more representative part...
    *
    * @param aPart Part to place.
    */
-  _replacePart(aPart) {
+  _replacePart: function(aPart) {
     // _partMap always maps the libmime names to parts
     let partName = aPart.partName;
     this._partMap[partName] = aPart;
 
-    let [storagePartName, , parentPart] = this._findOrCreateParent(partName);
+    let [storagePartName, parentName, parentPart] = this._findOrCreateParent(partName);
 
-    let childNamePart = storagePartName.substring(storagePartName.lastIndexOf(".") + 1);
+    let childNamePart = storagePartName.substring(storagePartName.lastIndexOf(".")+1);
     let childIndex = parseInt(childNamePart) - 1;
 
     // The attachment has been encapsulated properly in a MIME part (most of
     // the cases). This does not hold for UUencoded-parts for instance (see
     // test_mime_attachments_size.js for instance).
     if (childIndex < parentPart.parts.length) {
       let oldPart = parentPart.parts[childIndex];
       parentPart.parts[childIndex] = aPart;
@@ -360,34 +369,36 @@ MimeMessageEmitter.prototype = {
     }
   },
 
   // ----- Attachment Routines
   // The attachment processing happens after the initial streaming phase (during
   //  which time we receive the messages, both bodies and headers).  Our caller
   //  traverses the libmime child object hierarchy, emitting an attachment for
   //  each leaf object or sub-message.
-  startAttachment(aName, aContentType, aUrl, aIsExternalAttachment) {
+  startAttachment: function mime_emitter_startAttachment(aName, aContentType,
+      aUrl, aIsExternalAttachment) {
     this._state = kStateInAttachment;
 
     // we need to strip our magic flags from the URL; this regexp matches all
     // the specific flags that the jsmimeemitter understands (we abuse the URL
     // parameters to pass information all the way to here)
     aUrl = aUrl.replace(/((header=filter|emitter=js|fetchCompleteMessage=(true|false)|examineEncryptedParts=(true|false)))&?/g, "");
     // the url should contain a part= piece that tells us the part name, which
     // we then use to figure out where to place that part if it's a real
     // attachment.
     let partMatch, partName;
     if (aUrl.startsWith("http") || aUrl.startsWith("file")) {
       // if we have a remote url, unlike non external mail part urls, it may also
       // contain query strings starting with ?; PART_RE does not handle this.
       partMatch = aUrl.match(/[?&]part=[^&]+$/);
       partMatch = partMatch && partMatch[0];
       partName = partMatch && partMatch.split("part=")[1];
-    } else {
+    }
+    else {
       partMatch = this._partRE.exec(aUrl);
       partName = partMatch && partMatch[1];
     }
     this._curAttachment = partName;
 
     if (aContentType == "message/rfc822") {
       // we want to offer extension authors a way to see attachments as the
       // message readers sees them, which means attaching an extra url property
@@ -395,80 +406,81 @@ MimeMessageEmitter.prototype = {
       if (partName) {
         // we disguise this MimeMessage into something that can be used as a
         // MimeAttachment so that it is transparent for the user code
         this._partMap[partName].url = aUrl;
         this._partMap[partName].isExternal = aIsExternalAttachment;
         this._partMap[partName].name = aName;
         this._partMap[partName].isRealAttachment = true;
       }
-    } else if (partName) {
+    }
+    else if (partName) {
       let part = new this._mimeMsg.MimeMessageAttachment(partName,
           aName, aContentType, aUrl, aIsExternalAttachment);
       // replace the existing part with the attachment...
       this._replacePart(part);
     }
   },
-  addAttachmentField(aField, aValue) {
+  addAttachmentField: function mime_emitter_addAttachmentField(aField, aValue) {
     // What gets passed in here is X-Mozilla-PartURL with a value that
     //  is completely identical to aUrl from the call to startAttachment.
     //  (it's the same variable they use in each case).  As such, there is
     //  no reason to handle that here.
     // However, we also pass information about the size of the attachment, and
     //  that we want to handle
     if (aField == "X-Mozilla-PartSize" && (this._curAttachment in this._partMap))
       this._partMap[this._curAttachment].size = parseInt(aValue);
   },
-  endAttachment() {
+  endAttachment: function mime_emitter_endAttachment() {
     // don't need to do anything here, since we don't care about the headers.
   },
-  endAllAttachments() {
+  endAllAttachments: function mime_emitter_endAllAttachments() {
     // nop
   },
 
   // ----- Body Routines
   /**
    * We don't get an x-jsemitter-part-path for the message body, and we ignored
    *  our body part's content-type in addHeaderField, so this serves as our
    *  notice to set up the part (giving it a name).
    */
-  startBody(aIsBodyOnly, aMsgID, aOutCharset) {
+  startBody: function mime_emitter_startBody(aIsBodyOnly, aMsgID, aOutCharset) {
     this._state = kStateInBody;
 
     let subPartName = (this._curPart.partName == "") ?
                         "1" :
                         this._curPart.partName + ".1";
     this._beginPayload(this._curPart.get("content-type", "text/plain"));
     this._curPart.partName = subPartName;
     this._placePart(this._curPart);
   },
 
   /**
    * Write to the body.  When saneBodySize is active, we stop adding if we are
    *  already at the limit for this body part.
    */
-  writeBody(aBuf, aSize, aOutAmountWritten) {
+  writeBody: function mime_emitter_writeBody(aBuf, aSize, aOutAmountWritten) {
     if (this._writeBody &&
         (!this._saneBodySize ||
          this._curPart.size < MAX_SANE_BODY_PART_SIZE))
       this._curPart.appendBody(aBuf);
   },
 
-  endBody() {
+  endBody: function mime_emitter_endBody() {
   },
 
   // ----- Generic Write (confusing)
   // (binary data writing...)
-  write(aBuf, aSize, aOutAmountWritten) {
+  write: function mime_emitter_write(aBuf, aSize, aOutAmountWritten) {
     // we don't actually ever get called because we don't have the attachment
     //  binary payloads pass through us, but we do the following just in case
     //  we did get called (otherwise the caller gets mad and throws exceptions).
     aOutAmountWritten.value = aSize;
   },
 
   // (string writing)
-  utilityWrite(aBuf) {
+  utilityWrite: function mime_emitter_utilityWrite(aBuf) {
     this.write(aBuf, aBuf.length, {});
   },
 };
 
 var components = [MimeMessageEmitter];
 var NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
--- a/mailnews/db/gloda/content/autocomplete-richlistitem.js
+++ b/mailnews/db/gloda/content/autocomplete-richlistitem.js
@@ -1,20 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 /* global MozXULElement, MozElements */
 {
-  let {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
-  let {StringBundle} = ChromeUtils.import("resource:///modules/StringBundle.js");
-  let gGlodaCompleteStrings = new StringBundle("chrome://messenger/locale/glodaComplete.properties");
-
   /**
    * The MozGlodacompleteBaseRichlistitem widget is the
    * abstract base class for all the gloda autocomplete items.
    *
    * @abstract
    * @extends {MozElements.MozRichlistitem}
    */
   class MozGlodacompleteBaseRichlistitem extends MozElements.MozRichlistitem {
@@ -51,17 +47,17 @@
         while ((matchIndex = lowerText.indexOf(search, startIndex)) >= 0) {
           // Start the next search from where this one finished.
           startIndex = matchIndex + searchLen;
           regions.push([matchIndex, startIndex]);
         }
       }
 
       // Sort the regions by start position then end position.
-      regions = regions.sort(function(a, b) {
+      regions = regions.sort(function (a, b) {
         let start = a[0] - b[0];
         return (start == 0) ? a[1] - b[1] : start;
       });
 
       // Generate the boundary indices from each region.
       let start = 0;
       let end = 0;
       let boundaries = [];
--- a/mailnews/db/gloda/content/glodacomplete.xml
+++ b/mailnews/db/gloda/content/glodacomplete.xml
@@ -17,31 +17,37 @@
           <![CDATA[
           var controller = this.mInput.controller;
 
           // Process maxRows per chunk to improve performance and user experience
           for (let i = 0; i < this.maxRows; i++) {
             if (this._currentIndex >= this.matchCount)
               return;
 
+            var existingItemsCount = this.richlistbox.childNodes.length;
             var item;
 
             // trim the leading/trailing whitespace
             var trimmedSearchString = controller.searchString.trim();
 
+            // Unescape the URI spec for showing as an entry in the popup
+            let url = Services.textToSubURI
+                              .unEscapeURIForUI("UTF-8", controller.getValueAt(this._currentIndex));
+
             let glodaCompleter = Cc["@mozilla.org/autocomplete/search;1?name=gloda"]
                                    .getService(Ci.nsIAutoCompleteSearch)
                                    .wrappedJSObject;
             var result = glodaCompleter.curResult;
 
             item = document.createElement("richlistitem", { is: result.getStyleAt(this._currentIndex) });
 
             // set these attributes before we set the class
             // so that we can use them from the constructor
             var row = result.getObjectAt(this._currentIndex);
+            var obj = row.item;
             item.setAttribute("text", trimmedSearchString);
             item.setAttribute("type", result.getStyleAt(this._currentIndex));
 
             item.row = row;
 
             // set the class at the end so we can use the attributes
             // in the xbl constructor
             item.className = "autocomplete-richlistitem";
--- a/mailnews/db/gloda/modules/collection.js
+++ b/mailnews/db/gloda/modules/collection.js
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-this.EXPORTED_SYMBOLS = ["GlodaCollection", "GlodaCollectionManager"];
+this.EXPORTED_SYMBOLS = ['GlodaCollection', 'GlodaCollectionManager'];
 
 const {Log4Moz} = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
 
 var LOG = Log4Moz.repository.getLogger("gloda.collection");
 
 /**
  * @namespace Central registry and logic for all collections.
  *
@@ -26,56 +26,57 @@ var GlodaCollectionManager = {
   _collectionsByNoun: {},
   _cachesByNoun: {},
 
   /**
    * Registers the existence of a collection with the collection manager.  This
    *  is done using a weak reference so that the collection can go away if it
    *  wants to.
    */
-  registerCollection(aCollection) {
+  registerCollection: function gloda_colm_registerCollection(aCollection) {
     let collections;
     let nounID = aCollection.query._nounDef.id;
-    if (!(nounID in this._collectionsByNoun)) {
+    if (!(nounID in this._collectionsByNoun))
       collections = this._collectionsByNoun[nounID] = [];
-    } else {
+    else {
       // purge dead weak references while we're at it
-      collections = this._collectionsByNoun[nounID].filter((aRef) => aRef.get());
+      collections = this._collectionsByNoun[nounID].filter(function (aRef) {
+        return aRef.get(); });
       this._collectionsByNoun[nounID] = collections;
     }
     collections.push(Cu.getWeakReference(aCollection));
   },
 
-  getCollectionsForNounID(aNounID) {
+  getCollectionsForNounID: function gloda_colm_getCollectionsForNounID(aNounID){
     if (!(aNounID in this._collectionsByNoun))
       return [];
 
     // generator would be nice, but I suspect get() is too expensive to use
     //  twice (guard/predicate and value)
     let weakCollections = this._collectionsByNoun[aNounID];
     let collections = [];
     for (let iColl = 0; iColl < weakCollections.length; iColl++) {
       let collection = weakCollections[iColl].get();
       if (collection)
         collections.push(collection);
     }
     return collections;
   },
 
-  defineCache(aNounDef, aCacheSize) {
+  defineCache: function gloda_colm_defineCache(aNounDef, aCacheSize) {
     this._cachesByNoun[aNounDef.id] = new GlodaLRUCacheCollection(aNounDef,
                                                                    aCacheSize);
   },
 
   /**
    * Attempt to locate an instance of the object of the given noun type with the
    *  given id.  Counts as a cache hit if found.  (And if it wasn't in a cache,
    *  but rather a collection, it is added to the cache.)
    */
-  cacheLookupOne(aNounID, aID, aDoCache) {
+  cacheLookupOne: function gloda_colm_cacheLookupOne(aNounID, aID, aDoCache) {
     let cache = this._cachesByNoun[aNounID];
 
     if (cache) {
       if (aID in cache._idMap) {
         let item = cache._idMap[aID];
         return cache.hit(item);
       }
     }
@@ -108,28 +109,30 @@ var GlodaCollectionManager = {
    *     in collections that were in memory but not in the cache?  You would
    *     likely want to pass false if you are only updating in-memory
    *     representations rather than performing a new query.
    *
    * @return [The number that were found, the number that were not found,
    *          a dictionary whose keys are the ids of noun instances that
    *          were not found.]
    */
-  cacheLookupMany(aNounID, aIDMap, aTargetMap, aDoCache) {
+  cacheLookupMany: function gloda_colm_cacheLookupMany(aNounID, aIDMap,
+      aTargetMap, aDoCache) {
     let foundCount = 0, notFoundCount = 0, notFound = {};
 
     let cache = this._cachesByNoun[aNounID];
 
     if (cache) {
       for (let key in aIDMap) {
         let cacheValue = cache._idMap[key];
         if (cacheValue === undefined) {
           notFoundCount++;
           notFound[key] = null;
-        } else {
+        }
+        else {
           foundCount++;
           aTargetMap[key] = cacheValue;
           cache.hit(cacheValue);
         }
       }
     }
 
     if (aDoCache === false)
@@ -154,32 +157,34 @@ var GlodaCollectionManager = {
 
   /**
    * Friendlier version of |cacheLookupMany|; takes a list of ids and returns
    *  an object whose keys and values are the gloda id's and instances of the
    *  instances that were found.  We don't tell you who we didn't find.  The
    *  assumption is this is being used for in-memory updates where we only need
    *  to tweak what is in memory.
    */
-  cacheLookupManyList(aNounID, aIds) {
+  cacheLookupManyList: function gloda_colm_cacheLookupManyList(aNounID, aIds) {
     let checkMap = {}, targetMap = {};
     for (let id of aIds) {
       checkMap[id] = null;
     }
     // do not promote found items into the cache
     this.cacheLookupMany(aNounID, checkMap, targetMap, false);
     return targetMap;
   },
 
   /**
    * Attempt to locate an instance of the object of the given noun type with the
    *  given id.  Counts as a cache hit if found.  (And if it wasn't in a cache,
    *  but rather a collection, it is added to the cache.)
    */
-  cacheLookupOneByUniqueValue(aNounID, aUniqueValue, aDoCache) {
+  cacheLookupOneByUniqueValue:
+      function gloda_colm_cacheLookupOneByUniqueValue(aNounID, aUniqueValue,
+                                                      aDoCache) {
     let cache = this._cachesByNoun[aNounID];
 
     if (cache) {
       if (aUniqueValue in cache._uniqueValueMap) {
         let item = cache._uniqueValueMap[aUniqueValue];
         return cache.hit(item);
       }
     }
@@ -200,30 +205,31 @@ var GlodaCollectionManager = {
   },
 
   /**
    * Checks whether the provided item with the given id is actually a duplicate
    *  of an instance that already exists in the cache/a collection.  If it is,
    *  the pre-existing instance is returned and counts as a cache hit.  If it
    *  is not, the passed-in instance is added to the cache and returned.
    */
-  cacheLoadUnifyOne(aItem) {
+  cacheLoadUnifyOne: function gloda_colm_cacheLoadUnifyOne(aItem) {
     let items = [aItem];
     this.cacheLoadUnify(aItem.NOUN_ID, items);
     return items[0];
   },
 
   /**
    * Given a list of items, check if any of them already have duplicate,
    *  canonical, instances in the cache or collections.  Items with pre-existing
    *  instances are replaced by those instances in the provided list, and each
    *  counts as a cache hit.  Items without pre-existing instances are added
    *  to the cache and left intact.
    */
-  cacheLoadUnify(aNounID, aItems, aCacheIfMissing) {
+  cacheLoadUnify: function gloda_colm_cacheLoadUnify(aNounID, aItems,
+      aCacheIfMissing) {
     let cache = this._cachesByNoun[aNounID];
     if (aCacheIfMissing === undefined)
       aCacheIfMissing = true;
 
     // track the items we haven't yet found in a cache/collection (value) and
     //  their index in aItems (key).  We're somewhat abusing the dictionary
     //  metaphor with the intent of storing tuples here.  We also do it because
     //  it allows random-access deletion theoretically without cost.  (Since
@@ -236,26 +242,28 @@ var GlodaCollectionManager = {
       for (let iItem = 0; iItem < aItems.length; iItem++) {
         let item = aItems[iItem];
 
         if (item.id in cache._idMap) {
           let realItem = cache._idMap[item.id];
           // update the caller's array with the reference to the 'real' item
           aItems[iItem] = realItem;
           cache.hit(realItem);
-        } else {
+        }
+        else {
           unresolvedIndexToItem[iItem] = item;
           numUnresolved++;
         }
       }
 
       // we're done if everyone was a hit.
       if (numUnresolved == 0)
         return;
-    } else {
+    }
+    else {
       for (let iItem = 0; iItem < aItems.length; iItem++) {
         unresolvedIndexToItem[iItem] = aItems[iItem];
       }
       numUnresolved = aItems.length;
     }
 
     let needToCache = [];
     // next, let's fall back to our collections
@@ -277,55 +285,57 @@ var GlodaCollectionManager = {
     }
 
     // anything left in unresolvedIndexToItem should be added to the cache
     //  unless !aCacheIfMissing.  plus, we already have 'needToCache'
     if (cache && aCacheIfMissing) {
       cache.add(needToCache.concat(Object.keys(unresolvedIndexToItem).
                                    map(key => unresolvedIndexToItem[key])));
     }
+
+    return aItems;
   },
 
-  cacheCommitDirty() {
+  cacheCommitDirty: function glod_colm_cacheCommitDirty() {
     for (let id in this._cachesByNoun) {
       let cache = this._cachesByNoun[id];
       cache.commitDirty();
     }
   },
 
   /**
    * Notifies the collection manager that an item has been loaded and should
    *  be cached, assuming caching is active.
    */
-  itemLoaded(aItem) {
+  itemLoaded: function gloda_colm_itemsLoaded(aItem) {
     let cache = this._cachesByNoun[aItem.NOUN_ID];
     if (cache) {
       cache.add([aItem]);
     }
   },
 
   /**
    * Notifies the collection manager that multiple items has been loaded and
    *  should be cached, assuming caching is active.
    */
-  itemsLoaded(aNounID, aItems) {
+  itemsLoaded: function gloda_colm_itemsLoaded(aNounID, aItems) {
     let cache = this._cachesByNoun[aNounID];
     if (cache) {
       cache.add(aItems);
     }
   },
 
   /**
    * This should be called when items are added to the global database.  This
    *  should generally mean during indexing by indexers or an attribute
    *  provider.
    * We walk all existing collections for the given noun type and add the items
    *  to the collection if the item meets the query that defines the collection.
    */
-  itemsAdded(aNounID, aItems) {
+  itemsAdded: function gloda_colm_itemsAdded(aNounID, aItems) {
     let cache = this._cachesByNoun[aNounID];
     if (cache) {
       cache.add(aItems);
     }
 
     for (let collection of this.getCollectionsForNounID(aNounID)) {
       let addItems = aItems.filter(item => collection.query.test(item));
       if (addItems.length)
@@ -338,34 +348,33 @@ var GlodaCollectionManager = {
    *  by indexers or by attribute providers.
    * We walk all existing collections for the given noun type.  For items
    *  currently included in each collection but should no longer be (per the
    *  collection's defining query) we generate onItemsRemoved events.  For items
    *  not currently included in the collection but should now be, we generate
    *  onItemsAdded events.  For items included that still match the query, we
    *  generate onItemsModified events.
    */
-  itemsModified(aNounID, aItems) {
+  itemsModified: function gloda_colm_itemsModified(aNounID, aItems) {
     for (let collection of this.getCollectionsForNounID(aNounID)) {
       let added = [], modified = [], removed = [];
       for (let item of aItems) {
         if (item.id in collection._idMap) {
           // currently in... but should it still be there?
-          if (collection.query.test(item)) {
+          if (collection.query.test(item))
             modified.push(item); // yes, keep it
-          } else if (!collection.query.frozen) {
-            // oy, so null queries really don't want any notifications, and they
-            //  sorta fit into our existing model, except for the removal bit.
-            //  so we need a specialized check for them, and we're using the
-            //  frozen attribute to this end.
+          // oy, so null queries really don't want any notifications, and they
+          //  sorta fit into our existing model, except for the removal bit.
+          //  so we need a specialized check for them, and we're using the
+          //  frozen attribute to this end.
+          else if (!collection.query.frozen)
             removed.push(item); // no, bin it
-          }
-        } else if (collection.query.test(item)) { // not in, should it be?
+        }
+        else if (collection.query.test(item)) // not in, should it be?
           added.push(item); // yep, add it
-        }
       }
       if (added.length)
         collection._onItemsAdded(added);
       if (modified.length)
         collection._onItemsModified(modified);
       if (removed.length)
         collection._onItemsRemoved(removed);
     }
@@ -376,17 +385,17 @@ var GlodaCollectionManager = {
    *  involved trash folders or other modified forms of existence.  Deleted
    *  means the data is gone and if it were to come back, it would come back
    *  via an itemsAdded event.)
    * We walk all existing collections for the given noun type.  For items
    *  currently in the collection, we generate onItemsRemoved events.
    *
    * @param aItemIds A list of item ids that are being deleted.
    */
-  itemsDeleted(aNounID, aItemIds) {
+  itemsDeleted: function gloda_colm_itemsDeleted(aNounID, aItemIds) {
     // cache
     let cache = this._cachesByNoun[aNounID];
     if (cache) {
       for (let itemId of aItemIds) {
         if (itemId in cache._idMap)
           cache.deleted(cache._idMap[itemId]);
       }
     }
@@ -411,17 +420,18 @@ var GlodaCollectionManager = {
    *  not going to happen all that frequently.  If these assumptions are wrong,
    *  callers are advised to re-think the whole situation.
    *
    * @param aNounID Type of noun we are talking about here.
    * @param aFilter A filter function that returns true when the item should be
    *     thought of as deleted, or false if the item is still good.  Screw this
    *     up and you will get some seriously wacky bugs, yo.
    */
-  itemsDeletedByAttribute(aNounID, aFilter) {
+  itemsDeletedByAttribute: function gloda_colm_itemsDeletedByAttribute(
+      aNounID, aFilter) {
     // cache
     let cache = this._cachesByNoun[aNounID];
     if (cache) {
       for (let id in cache._idMap) {
         let item = cache._idMap[id];
         if (aFilter(item))
           cache.deleted(item);
       }
@@ -475,17 +485,18 @@ function GlodaCollection(aNounDef, aItem
   }
   this._listener = aListener || null;
 
   this.deferredCount = 0;
   this.resolvedCount = 0;
 
   if (aMasterCollection) {
     this.masterCollection = aMasterCollection.masterCollection;
-  } else {
+  }
+  else {
     this.masterCollection = this;
     /** a dictionary of dictionaries. at the top level, the keys are noun IDs.
      * each of these sub-dictionaries maps the IDs of desired noun instances to
      * the actual instance, or null if it has not yet been loaded.
      */
     this.referencesByNounID = {};
     /**
      * a dictionary of dictionaries. at the top level, the keys are noun IDs.
@@ -511,110 +522,114 @@ GlodaCollection.prototype = {
    *  and replace it with an 'explicit query'.  This means that the Collection
    *  Manager will not attempt to match new items indexed to the system against
    *  our query criteria.
    * Once you call this method, your collection's listener will no longer
    *  receive onItemsAdded notifications that are not the result of your
    *  initial database query.  It will, however, receive onItemsModified
    *  notifications if items in the collection are re-indexed.
    */
-  becomeExplicit() {
+  becomeExplicit: function gloda_coll_becomeExplicit() {
     if (!(this.query instanceof this._nounDef.explicitQueryClass)) {
       this.query = new this._nounDef.explicitQueryClass(this);
     }
   },
 
   /**
    * Clear the contents of this collection.  This only makes sense for explicit
    *  collections or wildcard collections.  (Actual query-based collections
    *  should represent the state of the query, so unless we're going to delete
    *  all the items, clearing the collection would violate that constraint.)
    */
-  clear() {
+  clear: function gloda_coll_clear() {
     this._idMap = {};
     if (this._uniqueValueMap)
       this._uniqueValueMap = {};
     this.items = [];
   },
 
-  _onItemsAdded(aItems) {
+  _onItemsAdded: function gloda_coll_onItemsAdded(aItems) {
     this.items.push.apply(this.items, aItems);
     if (this._uniqueValueMap) {
       for (let item of this.items) {
         this._idMap[item.id] = item;
         this._uniqueValueMap[item.uniqueValue] = item;
       }
-    } else {
+    }
+    else {
       for (let item of this.items) {
         this._idMap[item.id] = item;
       }
     }
     if (this._listener) {
       try {
         this._listener.onItemsAdded(aItems, this);
-      } catch (ex) {
+      }
+      catch (ex) {
         LOG.error("caught exception from listener in onItemsAdded: " +
             ex.fileName + ":" + ex.lineNumber + ": " + ex);
       }
     }
   },
 
-  _onItemsModified(aItems) {
+  _onItemsModified: function gloda_coll_onItemsModified(aItems) {
     if (this._listener) {
       try {
         this._listener.onItemsModified(aItems, this);
-      } catch (ex) {
+      }
+      catch (ex) {
         LOG.error("caught exception from listener in onItemsModified: " +
             ex.fileName + ":" + ex.lineNumber + ": " + ex);
       }
     }
   },
 
   /**
    * Given a list of items that definitely no longer belong in this collection,
    *  remove them from the collection and notify the listener.  The 'tricky'
    *  part is that we need to remove the deleted items from our list of items.
    */
-  _onItemsRemoved(aItems) {
+  _onItemsRemoved: function gloda_coll_onItemsRemoved(aItems) {
     // we want to avoid the O(n^2) deletion performance case, and deletion
     //  should be rare enough that the extra cost of building the deletion map
     //  should never be a real problem.
     let deleteMap = {};
     // build the delete map while also nuking from our id map/unique value map
     for (let item of aItems) {
       deleteMap[item.id] = true;
       delete this._idMap[item.id];
       if (this._uniqueValueMap)
         delete this._uniqueValueMap[item.uniqueValue];
     }
     let items = this.items;
     // in-place filter.  probably needless optimization.
-    let iWrite = 0;
+    let iWrite=0;
     for (let iRead = 0; iRead < items.length; iRead++) {
       let item = items[iRead];
       if (!(item.id in deleteMap))
         items[iWrite++] = item;
     }
     items.splice(iWrite);
 
     if (this._listener) {
       try {
         this._listener.onItemsRemoved(aItems, this);
-      } catch (ex) {
+      }
+      catch (ex) {
         LOG.error("caught exception from listener in onItemsRemoved: " +
             ex.fileName + ":" + ex.lineNumber + ": " + ex);
       }
     }
   },
 
-  _onQueryCompleted() {
+  _onQueryCompleted: function gloda_coll_onQueryCompleted() {
     this.query.completed = true;
     if (this._listener && this._listener.onQueryCompleted)
       this._listener.onQueryCompleted(this);
-  },
+  }
 };
 
 /**
  * Create an LRU cache collection for the given noun with the given size.
  * @constructor
  */
 function GlodaLRUCacheCollection(aNounDef, aCacheSize) {
   GlodaCollection.call(this, aNounDef, null, null, null);
@@ -630,17 +645,17 @@ function GlodaLRUCacheCollection(aNounDe
 /**
  * @class A LRU-discard cache.  We use a doubly linked-list for the eviction
  *  tracking.  Since we require that there is at most one LRU-discard cache per
  *  noun class, we simplify our lives by adding our own attributes to the
  *  cached objects.
  * @augments GlodaCollection
  */
 GlodaLRUCacheCollection.prototype = new GlodaCollection;
-GlodaLRUCacheCollection.prototype.add = function(aItems) {
+GlodaLRUCacheCollection.prototype.add = function cache_add(aItems) {
   for (let item of aItems) {
     if (item.id in this._idMap) {
       // DEBUGME so, we're dealing with this, but it shouldn't happen.  need
       //  trace-debuggage.
       continue;
     }
     this._idMap[item.id] = item;
     if (this._uniqueValueMap)
@@ -681,17 +696,17 @@ GlodaLRUCacheCollection.prototype.add = 
       this._nounDef.objUpdate.call(this._nounDef.datastore, item);
       delete item.dirty;
     }
 
     this._size--;
   }
 };
 
-GlodaLRUCacheCollection.prototype.hit = function(aItem) {
+GlodaLRUCacheCollection.prototype.hit = function cache_hit(aItem) {
   // don't do anything in the 0 or 1 items case, or if we're already
   //  the last item
   if ((this._head === this._tail) || (this._tail === aItem))
     return aItem;
 
   // - unlink the item
   if (aItem._lruPrev !== null)
     aItem._lruPrev._lruNext = aItem._lruNext;
@@ -704,17 +719,17 @@ GlodaLRUCacheCollection.prototype.hit = 
   aItem._lruPrev = this._tail;
   aItem._lruNext = null;
   // update tail tracking
   this._tail = aItem;
 
   return aItem;
 };
 
-GlodaLRUCacheCollection.prototype.deleted = function(aItem) {
+GlodaLRUCacheCollection.prototype.deleted = function cache_deleted(aItem) {
   // unlink the item
   if (aItem._lruPrev !== null)
     aItem._lruPrev._lruNext = aItem._lruNext;
   else
     this._head = aItem._lruNext;
   if (aItem._lruNext !== null)
     aItem._lruNext._lruPrev = aItem._lruPrev;
   else
@@ -731,17 +746,17 @@ GlodaLRUCacheCollection.prototype.delete
 
   this._size--;
 };
 
 /**
  * If any of the cached items are dirty, commit them, and make them no longer
  *  dirty.
  */
-GlodaLRUCacheCollection.prototype.commitDirty = function() {
+GlodaLRUCacheCollection.prototype.commitDirty = function cache_commitDirty() {
   // we can only do this if there is an update method available...
   if (!this._nounDef.objUpdate)
     return;
 
   for (let iItem in this._idMap) {
     let item = this._idMap[iItem];
     if (item.dirty) {
       LOG.debug("flushing dirty: " + item);
--- a/mailnews/db/gloda/modules/connotent.js
+++ b/mailnews/db/gloda/modules/connotent.js
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-this.EXPORTED_SYMBOLS = ["GlodaContent", "whittlerRegistry",
-                         "mimeMsgToContentAndMeta", "mimeMsgToContentSnippetAndMeta"];
+this.EXPORTED_SYMBOLS = ['GlodaContent', 'whittlerRegistry',
+                          'mimeMsgToContentAndMeta', 'mimeMsgToContentSnippetAndMeta'];
 
 const {Log4Moz} = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
 
 var LOG = Log4Moz.repository.getLogger("gloda.connotent");
 
 
 
 /**
@@ -45,17 +45,17 @@ function mimeMsgToContentAndMeta(aMimeMs
  * that the Gloda content providers may have filled with useful data.
  */
 
 function mimeMsgToContentSnippetAndMeta(aMimeMsg, folder, length) {
   let [content, meta] = mimeMsgToContentAndMeta(aMimeMsg, folder);
 
   let text = content.getContentSnippet(length + 1);
   if (length && text.length > length)
-    text = text.substring(0, length - 1) + "\u2026"; // ellipsis
+    text = text.substring(0, length-1) + "\u2026"; // ellipsis
 
   return [text, meta];
 }
 
 
 /**
  * A registry of gloda providers that have contentWhittle() functions.
  * used by mimeMsgToContentSnippet, but populated by the Gloda object as it's
@@ -64,29 +64,29 @@ function mimeMsgToContentSnippetAndMeta(
 function WhittlerRegistry() {
   this._whittlers = [];
 }
 
 WhittlerRegistry.prototype = {
   /**
    * Add a provider as a content whittler.
    */
-  registerWhittler(provider) {
+  registerWhittler: function whittler_registry_registerWhittler(provider) {
     this._whittlers.push(provider);
   },
   /**
    * get the list of content whittlers, sorted from the most specific to
    * the most generic
    */
-  getWhittlers() {
+  getWhittlers: function whittler_registry_getWhittlers() {
     // Use the concat() trick to avoid mutating the internal object and
     // leaking an internal representation.
     return this._whittlers.concat().reverse();
-  },
-};
+  }
+}
 
 this.whittlerRegistry = new WhittlerRegistry();
 
 function GlodaContent() {
   this._contentPriority = null;
   this._producing = false;
   this._hunks = [];
 }
@@ -94,42 +94,42 @@ function GlodaContent() {
 GlodaContent.prototype = {
   kPriorityBase: 0,
   kPriorityPerfect: 100,
 
   kHunkMeta: 1,
   kHunkQuoted: 2,
   kHunkContent: 3,
 
-  _resetContent() {
+  _resetContent: function gloda_content__resetContent() {
     this._keysAndValues = [];
     this._keysAndDeltaValues = [];
     this._hunks = [];
     this._curHunk = null;
   },
 
   /* ===== Consumer API ===== */
-  hasContent() {
+  hasContent: function gloda_content_hasContent() {
     return (this._contentPriority != null);
   },
 
   /**
    * Return content suitable for snippet display.  This means that no quoting
    *  or meta-data should be returned.
    *
    * @param aMaxLength The maximum snippet length desired.
    */
-  getContentSnippet(aMaxLength) {
+  getContentSnippet: function gloda_content_getContentSnippet(aMaxLength) {
     let content = this.getContentString();
     if (aMaxLength)
       content = content.substring(0, aMaxLength);
     return content;
   },
 
-  getContentString(aIndexingPurposes) {
+  getContentString: function gloda_content_getContent(aIndexingPurposes) {
     let data = "";
     for (let hunk of this._hunks) {
       if (hunk.hunkType == this.kHunkContent) {
         if (data)
           data += "\n" + hunk.data;
         else
           data = hunk.data;
       }
@@ -157,34 +157,35 @@ GlodaContent.prototype = {
    *
    * @returns true if we believe the producer's interpretation will be
    *     interesting and they should go ahead and generate events.  We return
    *     false if we don't think they are interesting, in which case they should
    *     probably not issue calls to us, although we don't care.  (We will
    *     ignore their calls if we return false, this allows the simplification
    *     of code that needs to run anyways.)
    */
-  volunteerContent(aPriority) {
+  volunteerContent: function gloda_content_volunteerContent(aPriority) {
     if (this._contentPriority === null || this._contentPriority < aPriority) {
       this._contentPriority = aPriority;
       this._resetContent();
       this._producing = true;
       return true;
     }
     this._producing = false;
     return false;
   },
 
-  keyValue(aKey, aValue) {
+  keyValue: function gloda_content_keyValue(aKey, aValue) {
     if (!this._producing)
       return;
 
     this._keysAndValues.push([aKey, aValue]);
   },
-  keyValueDelta(aKey, aOldValue, aNewValue) {
+  keyValueDelta: function gloda_content_keyValueDelta (aKey, aOldValue,
+      aNewValue) {
     if (!this._producing)
       return;
 
     this._keysAndDeltaValues.push([aKey, aOldValue, aNewValue]);
   },
 
   /**
    * Meta lines are lines that have to do with the content but are not the
@@ -195,72 +196,73 @@ GlodaContent.prototype = {
    *  potentially interesting meta-data.
    *
    * @param aLineOrLines The line or list of lines that are meta-data.
    * @param aAttr The attribute this meta-data is associated with.
    * @param aIndex If the attribute is non-singular, indicate the specific
    *     index of the item in the attribute's bound list that the meta-data
    *     is associated with.
    */
-  meta(aLineOrLines, aAttr, aIndex) {
+  meta: function gloda_content_meta(aLineOrLines, aAttr, aIndex) {
     if (!this._producing)
       return;
 
     let data;
     if (typeof(aLineOrLines) == "string")
       data = aLineOrLines;
     else
       data = aLineOrLines.join("\n");
 
     this._curHunk = {hunkType: this.kHunkMeta, attr: aAttr, index: aIndex,
-                     data};
+                     data: data};
     this._hunks.push(this._curHunk);
   },
   /**
    * Quoted lines reference previous messages or what not.
    *
    * @param aLineOrLiens The line or list of lines that are quoted.
    * @param aDepth The depth of the quoting.
    * @param aOrigin The item that originated the original content, if known.
    *     For example, perhaps a GlodaMessage?
    * @param aTarget A reference to the location in the original content, if
    *     known.  For example, the index of a line in a message or something?
    */
-  quoted(aLineOrLines, aDepth, aOrigin, aTarget) {
+  quoted: function gloda_content_quoted(aLineOrLines, aDepth, aOrigin,
+      aTarget) {
     if (!this._producing)
       return;
 
     let data;
     if (typeof(aLineOrLines) == "string")
       data = aLineOrLines;
     else
       data = aLineOrLines.join("\n");
 
     if (!this._curHunk ||
         this._curHunk.hunkType != this.kHunkQuoted ||
         this._curHunk.depth != aDepth ||
         this._curHunk.origin != aOrigin || this._curHunk.target != aTarget) {
-      this._curHunk = {hunkType: this.kHunkQuoted, data,
+      this._curHunk = {hunkType: this.kHunkQuoted, data: data,
                        depth: aDepth, origin: aOrigin, target: aTarget};
       this._hunks.push(this._curHunk);
-    } else {
+    }
+    else
       this._curHunk.data += "\n" + data;
-    }
   },
 
-  content(aLineOrLines) {
+  content: function gloda_content_content(aLineOrLines) {
     if (!this._producing)
       return;
 
     let data;
     if (typeof(aLineOrLines) == "string")
       data = aLineOrLines;
     else
       data = aLineOrLines.join("\n");
 
     if (!this._curHunk || this._curHunk.hunkType != this.kHunkContent) {
-      this._curHunk = {hunkType: this.kHunkContent, data};
+      this._curHunk = {hunkType: this.kHunkContent, data: data};
       this._hunks.push(this._curHunk);
-    } else {
+    }
+    else
       this._curHunk.data += "\n" + data;
-    }
   },
 };
--- a/mailnews/db/gloda/modules/databind.js
+++ b/mailnews/db/gloda/modules/databind.js
@@ -108,30 +108,30 @@ GlodaDatabind.prototype = {
   /**
    * Perform appropriate binding coercion based on the schema provided to us.
    * Although we end up effectively coercing JS Date objects to numeric values,
    *  we should not be provided with JS Date objects!  There is no way for us
    *  to know to turn them back into JS Date objects on the way out.
    *  Additionally, there is the small matter of storage's bias towards
    *  PRTime representations which may not always be desirable.
    */
-  bindByType(aStmt, aColDef, aValue) {
+  bindByType: function(aStmt, aColDef, aValue) {
     aStmt.bindByIndex(aColDef[3], aValue);
   },
 
-  objFromRow(aRow) {
+  objFromRow: function(aRow) {
     let getVariant = this._datastore._getVariant;
     let obj = new this._nounDef.class();
     for (let [iCol, colDef] of this._tableDef.columns.entries()) {
       obj[colDef[2]] = getVariant(aRow, iCol);
     }
     return obj;
   },
 
-  objInsert(aThing) {
+  objInsert: function(aThing) {
     let bindByType = this.bindByType;
     if (!aThing[this._idAttr])
       aThing[this._idAttr] = this._nextId++;
 
     let stmt = this._insertStmt;
     for (let colDef of this._tableDef.columns) {
       bindByType(stmt, colDef, aThing[colDef[2]]);
     }
@@ -143,17 +143,17 @@ GlodaDatabind.prototype = {
       stmt.bindByIndex(0, aThing[this._idAttr]);
       for (let colDef of this._tableDef.fulltextColumns) {
         bindByType(stmt, colDef, aThing[colDef[2]]);
       }
       stmt.executeAsync(this._datastore.trackAsync());
     }
   },
 
-  objUpdate(aThing) {
+  objUpdate: function(aThing) {
     let bindByType = this.bindByType;
     let stmt = this._updateStmt;
     // note, we specially bound the location of 'id' for the insert, but since
     //  we're using named bindings, there is nothing special about setting it
     for (let colDef of this._tableDef.columns) {
       bindByType(stmt, colDef, aThing[colDef[2]]);
     }
     stmt.executeAsync(this._datastore.trackAsync());
@@ -164,21 +164,21 @@ GlodaDatabind.prototype = {
       stmt.bindByIndex(0, aThing[this._idAttr]);
       for (let colDef of this._tableDef.fulltextColumns) {
         bindByType(stmt, colDef, aThing[colDef[2]]);
       }
       stmt.executeAsync(this._datastore.trackAsync());
     }
   },
 
-  adjustAttributes(...aArgs) {
+  adjustAttributes: function(...aArgs) {
     // just proxy the call over to the datastore... we have to do this for
     //  'this' reasons.  we don't refactor things to avoid this because it does
     //  make some sense to have all the methods exposed from a single object,
     //  even if the implementation does live elsewhere.
     return this._datastore.adjustAttributes(...aArgs);
   },
 
   // also proxied...
-  queryFromQuery(...aArgs) {
+  queryFromQuery: function(...aArgs) {
     return this._datastore.queryFromQuery(...aArgs);
-  },
+  }
 };
--- a/mailnews/db/gloda/modules/datamodel.js
+++ b/mailnews/db/gloda/modules/datamodel.js
@@ -11,17 +11,17 @@ const {MailServices} = ChromeUtils.impor
 
 const {Log4Moz} = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
 var LOG = Log4Moz.repository.getLogger("gloda.datamodel");
 
 const {GlodaUtils} = ChromeUtils.import("resource:///modules/gloda/utils.js");
 
 // Make it lazy.
 var gMessenger;
-function getMessenger() {
+function getMessenger () {
   if (!gMessenger)
     gMessenger = Cc["@mozilla.org/messenger;1"].createInstance(Ci.nsIMessenger);
   return gMessenger;
 }
 
 /**
  * @class Represents a gloda attribute definition's DB form.  This class
  *  stores the information in the database relating to this attribute
@@ -54,17 +54,17 @@ GlodaAttributeDBDef.prototype = {
   get parameterBindings() { return this._parameterBindings; },
 
   /**
    * Bind a parameter value to the attribute definition, allowing use of the
    *  attribute-parameter as an attribute.
    *
    * @return
    */
-  bindParameter(aValue) {
+  bindParameter: function gloda_attr_bindParameter(aValue) {
     // people probably shouldn't call us with null, but handle it
     if (aValue == null) {
       return this._id;
     }
     if (aValue in this._parameterBindings) {
       return this._parameterBindings[aValue];
     }
     // no database entry exists if we are here, so we must create it...
@@ -79,64 +79,71 @@ GlodaAttributeDBDef.prototype = {
    * Given a list of values, return a list (regardless of plurality) of
    *  database-ready [attribute id,  value] tuples.  This is intended to be used
    *  to directly convert the value of a property on an object that corresponds
    *  to a bound attribute.
    *
    * @param {Array} aInstanceValues An array of instance values regardless of
    *     whether or not the attribute is singular.
    */
-  convertValuesToDBAttributes(aInstanceValues) {
+  convertValuesToDBAttributes:
+      function gloda_attr_convertValuesToDBAttributes(aInstanceValues) {
     let nounDef = this.attrDef.objectNounDef;
     let dbAttributes = [];
     if (nounDef.usesParameter) {
       for (let instanceValue of aInstanceValues) {
         let [param, dbValue] = nounDef.toParamAndValue(instanceValue);
         dbAttributes.push([this.bindParameter(param), dbValue]);
       }
-    } else if ("toParamAndValue" in nounDef) {
+    }
+    else {
       // Not generating any attributes is ok. This basically means the noun is
       // just an informative property on the Gloda Message and has no real
       // indexing purposes.
-      for (let instanceValue of aInstanceValues) {
-        dbAttributes.push([this._id,
-                           nounDef.toParamAndValue(instanceValue)[1]]);
+      if ("toParamAndValue" in nounDef) {
+        for (let instanceValue of aInstanceValues) {
+          dbAttributes.push([this._id,
+                             nounDef.toParamAndValue(instanceValue)[1]]);
+        }
       }
     }
     return dbAttributes;
   },
 
-  toString() {
+  toString: function() {
     return this._compoundName;
-  },
+  }
 };
 
 var GlodaHasAttributesMixIn = {
-  * enumerateAttributes() {
+  enumerateAttributes: function* gloda_attrix_enumerateAttributes() {
     let nounDef = this.NOUN_DEF;
     for (let key in this) {
       let value = this[key];
       let attrDef = nounDef.attribsByBoundName[key];
       // we expect to not have attributes for underscore prefixed values (those
       //  are managed by the instance's logic.  we also want to not explode
       //  should someone crap other values in there, we get both birds with this
       //  one stone.
       if (attrDef === undefined)
         continue;
       if (attrDef.singular) {
         // ignore attributes with null values
         if (value != null)
           yield [attrDef, [value]];
-      } else if (value.length) { // ignore attributes with no values
-        yield [attrDef, value];
+      }
+      else {
+        // ignore attributes with no values
+        if (value.length)
+          yield [attrDef, value];
       }
     }
   },
 
-  domContribute(aDomNode) {
+  domContribute: function gloda_attrix_domContribute(aDomNode) {
     let nounDef = this.NOUN_DEF;
     for (let attrName in nounDef.domExposeAttribsByBoundName) {
       let attr = nounDef.domExposeAttribsByBoundName[attrName];
       if (this[attrName])
         aDomNode.setAttribute(attr.domExpose, this[attrName]);
     }
   },
 };
@@ -158,23 +165,23 @@ function GlodaAccount(aIncomingServer) {
   this._incomingServer = aIncomingServer;
 }
 
 GlodaAccount.prototype = {
   NOUN_ID: 106,
   get id() { return this._incomingServer.key; },
   get name() { return this._incomingServer.prettyName; },
   get incomingServer() { return this._incomingServer; },
-  toString() {
+  toString: function gloda_account_toString() {
     return "Account: " + this.id;
   },
 
-  toLocaleString() {
+  toLocaleString: function gloda_account_toLocaleString() {
     return this.name;
-  },
+  }
 };
 
 /**
  * @class A gloda conversation (thread) exists so that messages can belong.
  */
 function GlodaConversation(aDatastore, aID, aSubject, aOldestMessageDate,
                            aNewestMessageDate) {
   // _datastore is now set on the prototype by GlodaDatastore
@@ -188,29 +195,30 @@ GlodaConversation.prototype = {
   NOUN_ID: 101,
   // set by GlodaDatastore
   _datastore: null,
   get id() { return this._id; },
   get subject() { return this._subject; },
   get oldestMessageDate() { return this._oldestMessageDate; },
   get newestMessageDate() { return this._newestMessageDate; },
 
-  getMessagesCollection(aListener, aData) {
+  getMessagesCollection: function gloda_conversation_getMessagesCollection(
+    aListener, aData) {
     let query = new GlodaMessage.prototype.NOUN_DEF.queryClass();
     query.conversation(this._id).orderBy("date");
     return query.getCollection(aListener, aData);
   },
 
-  toString() {
+  toString: function gloda_conversation_toString() {
     return "Conversation:" + this._id;
   },
 
-  toLocaleString() {
+  toLocaleString: function gloda_conversation_toLocaleString() {
     return this._subject;
-  },
+  }
 };
 
 function GlodaFolder(aDatastore, aID, aURI, aDirtyStatus, aPrettyName,
                      aIndexingPriority) {
   // _datastore is now set by GlodaDatastore
   this._id = aID;
   this._uri = aURI;
   this._dirtyStatus = aDirtyStatus;
@@ -269,28 +277,29 @@ GlodaFolder.prototype = {
   get dirtyStatus() {
     return this._dirtyStatus & this._kFolderDirtyStatusMask;
   },
   /**
    * Mark a folder as dirty if it was clean.  Do nothing if it was already dirty
    *  or filthy.  For use by GlodaMsgIndexer only.  And maybe rkent and his
    *  marvelous extensions.
    */
-  _ensureFolderDirty() {
+  _ensureFolderDirty: function gloda_folder__markFolderDirty() {
     if (this.dirtyStatus == this.kFolderClean) {
       this._dirtyStatus = (this.kFolderDirty & this._kFolderDirtyStatusMask) |
                           (this._dirtyStatus & ~this._kFolderDirtyStatusMask);
       this._datastore.updateFolderDirtyStatus(this);
     }
   },
   /**
    * Definitely for use only by GlodaMsgIndexer to downgrade the dirty status of
    *  a folder.
    */
-  _downgradeDirtyStatus(aNewStatus) {
+  _downgradeDirtyStatus: function gloda_folder__downgradeDirtyStatus(
+                           aNewStatus) {
     if (this.dirtyStatus != aNewStatus) {
       this._dirtyStatus = (aNewStatus & this._kFolderDirtyStatusMask) |
                           (this._dirtyStatus & ~this._kFolderDirtyStatusMask);
       this._datastore.updateFolderDirtyStatus(this);
     }
   },
   /**
    * Indicate whether this folder is currently being compacted.  The
@@ -312,32 +321,32 @@ GlodaFolder.prototype = {
    */
   get compacted() {
     return Boolean(this._dirtyStatus & this._kFolderCompactedFlag);
   },
   /**
    * For use only by GlodaMsgIndexer to set/clear the compaction state of this
    *  folder.
    */
-  _setCompactedState(aCompacted) {
+  _setCompactedState: function gloda_folder__clearCompactedState(aCompacted) {
     if (this.compacted != aCompacted) {
       if (aCompacted)
         this._dirtyStatus |= this._kFolderCompactedFlag;
       else
         this._dirtyStatus &= ~this._kFolderCompactedFlag;
       this._datastore.updateFolderDirtyStatus(this);
     }
   },
 
   get name() { return this._prettyName; },
-  toString() {
+  toString: function gloda_folder_toString() {
     return "Folder:" + this._id;
   },
 
-  toLocaleString() {
+  toLocaleString: function gloda_folder_toLocaleString() {
     let xpcomFolder = this.getXPCOMFolder(this.kActivityFolderOnlyNoData);
     if (!xpcomFolder)
       return this._prettyName;
     return xpcomFolder.prettyName +
       " (" + xpcomFolder.rootFolder.prettyName + ")";
   },
 
   get indexingPriority() {
@@ -379,17 +388,17 @@ GlodaFolder.prototype = {
    * Retrieve the nsIMsgFolder instance corresponding to this folder, providing
    *  an explanation of why you are requesting it for tracking/cleanup purposes.
    *
    * @param aActivity One of the kActivity* constants.  If you pass
    *     kActivityIndexing, we will set indexing for you, but you will need to
    *     clear it when you are done.
    * @return The nsIMsgFolder if available, null on failure.
    */
-  getXPCOMFolder(aActivity) {
+  getXPCOMFolder: function gloda_folder_getXPCOMFolder(aActivity) {
     if (!this._xpcomFolder) {
       this._xpcomFolder = MailUtils.getExistingFolder(this.uri);
     }
     switch (aActivity) {
       case this.kActivityIndexing:
         // mark us as indexing, but don't bother with live tracking.  we do
         //  that independently and only for header retrieval.
         this.indexing = true;
@@ -407,17 +416,17 @@ GlodaFolder.prototype = {
     return this._xpcomFolder;
   },
 
   /**
    * Retrieve a GlodaAccount instance corresponding to this folder.
    *
    * @return The GlodaAccount instance.
    */
-  getAccount() {
+  getAccount: function gloda_folder_getAccount() {
     if (!this._account) {
       let msgFolder = this.getXPCOMFolder(this.kActivityFolderOnlyNoData);
       this._account = new GlodaAccount(msgFolder.server);
     }
     return this._account;
   },
 
   /**
@@ -437,17 +446,17 @@ GlodaFolder.prototype = {
    *  idempotent fashion.  (It is possible for disabling indexing's call to us
    *  to cause us to return true but for the datastore's timer call to have not
    *  yet triggered.)
    *
    * @returns true if we are cleaned up and can be considered 'dead', false if
    *     we should still be considered alive and this method should be called
    *     again in the future.
    */
-  forgetFolderIfUnused() {
+  forgetFolderIfUnused: function gloda_folder_forgetFolderIfUnused() {
     // we are not cleaning/cleaned up if we are indexing
     if (this._activeIndexing)
       return false;
 
     // set a point in the past as the threshold.  the timestamp must be older
     //  than this to be eligible for cleanup.
     let acceptablyOld = Date.now() - this.ACCEPTABLY_OLD_THRESHOLD;
     // we are not cleaning/cleaned up if we have retrieved a header more
@@ -462,17 +471,17 @@ GlodaFolder.prototype = {
       this._xpcomFolder.msgDatabase = null;
       this._xpcomFolder = null;
       // since the last retrieval time tracks whether we have marked live or
       //  not, this needs to be reset to 0 too.
       this._activeHeaderRetrievalLastStamp = 0;
     }
 
     return true;
-  },
+  }
 };
 
 /**
  * @class A message representation.
  */
 function GlodaMessage(aDatastore, aID, aFolderID, aMessageKey,
                       aConversationID, aConversation, aDate,
                       aHeaderMessageID, aDeleted, aJsonText,
@@ -520,83 +529,85 @@ GlodaMessage.prototype = {
 
   get folder() {
     // XXX due to a deletion bug it is currently possible to get in a state
     //  where we have an illegal folderID value.  This will result in an
     //  exception.  As a workaround, let's just return null in that case.
     try {
       if (this._folderID != null)
         return this._datastore._mapFolderID(this._folderID);
-    } catch (ex) {
+    }
+    catch (ex) {
     }
     return null;
   },
   get folderURI() {
     // XXX just like for folder, handle mapping failures and return null
     try {
       if (this._folderID != null)
         return this._datastore._mapFolderID(this._folderID).uri;
-    } catch (ex) {
+    }
+    catch (ex) {
     }
     return null;
   },
   get account() {
     // XXX due to a deletion bug it is currently possible to get in a state
     //  where we have an illegal folderID value.  This will result in an
     //  exception.  As a workaround, let's just return null in that case.
     try {
       if (this._folderID == null)
         return null;
       let folder = this._datastore._mapFolderID(this._folderID);
       return folder.getAccount();
-    } catch (ex) {
     }
+    catch (ex) { }
     return null;
   },
   get conversation() {
     return this._conversation;
   },
 
-  toString() {
+  toString: function gloda_message_toString() {
     // uh, this is a tough one...
     return "Message:" + this._id;
   },
 
-  _clone() {
+  _clone: function gloda_message_clone() {
     return new GlodaMessage(/* datastore */ null, this._id, this._folderID,
       this._messageKey, this._conversationID, this._conversation, this._date,
       this._headerMessageID, "_deleted" in this ? this._deleted : undefined,
       "_jsonText" in this ? this._jsonText : undefined, this._notability,
       this._subject, this._indexedBodyText, this._attachmentNames);
   },
 
   /**
    * Provide a means of propagating changed values on our clone back to
    *  ourselves.  This is required because of an object identity trick gloda
    *  does; when indexing an already existing object, all mutations happen on
    *  a clone of the existing object so that
    */
-  _declone(aOther) {
+  _declone: function gloda_message_declone(aOther) {
     if ("_content" in aOther)
       this._content = aOther._content;
 
     // The _indexedAuthor/_indexedRecipients fields don't get updated on
     //  fulltext update so we don't need to propagate.
     this._indexedBodyText = aOther._indexedBodyText;
     this._attachmentNames = aOther._attachmentNames;
   },
 
   /**
    * Mark this message as a ghost.  Ghosts are characterized by having no folder
    *  id and no message key.  They also are not deleted or they would be of
    *  absolutely no use to us.
    *
    * These changes are suitable for persistence.
    */
-  _ghost() {
+  _ghost: function gloda_message_ghost() {
     this._folderID = null;
     this._messageKey = null;
     if ("_deleted" in this)
       delete this._deleted;
   },
 
   /**
    * Are we a ghost (which implies not deleted)?  We are not a ghost if we have
@@ -605,17 +616,17 @@ GlodaMessage.prototype = {
    */
   get _isGhost() {
     return this._folderID == null && !this._isDeleted;
   },
 
   /**
    * If we were dead, un-dead us.
    */
-  _ensureNotDeleted() {
+  _ensureNotDeleted: function gloda_message__ensureNotDeleted() {
     if ("_deleted" in this)
       delete this._deleted;
   },
 
   /**
    * Are we deleted?  This is private because deleted gloda messages are not
    *  visible to non-core-gloda code.
    */
@@ -623,17 +634,17 @@ GlodaMessage.prototype = {
     return ("_deleted" in this) && this._deleted;
   },
 
   /**
    * Trash this message's in-memory representation because it should no longer
    *  be reachable by any code.  The database record is gone, it's not coming
    *  back.
    */
-  _objectPurgedMakeYourselfUnpleasant() {
+  _objectPurgedMakeYourselfUnpleasant: function gloda_message_nuke() {
     this._id = null;
     this._folderID = null;
     this._messageKey = null;
     this._conversationID = null;
     this._conversation = null;
     this.date = null;
     this._headerMessageID = null;
   },
@@ -659,26 +670,28 @@ GlodaMessage.prototype = {
   get folderMessage() {
     if (this._folderID === null || this._messageKey === null)
       return null;
 
     // XXX like for folder and folderURI, return null if we can't map the folder
     let glodaFolder;
     try {
       glodaFolder = this._datastore._mapFolderID(this._folderID);
-    } catch (ex) {
+    }
+    catch (ex) {
       return null;
     }
     let folder = glodaFolder.getXPCOMFolder(
                    glodaFolder.kActivityHeaderRetrieval);
     if (folder) {
       let folderMessage;
       try {
         folderMessage = folder.GetMessageHeader(this._messageKey);
-      } catch (ex) {
+      }
+      catch (ex) {
         folderMessage = null;
       }
       if (folderMessage !== null) {
         // verify the message-id header matches what we expect...
         if (folderMessage.messageId != this._headerMessageID) {
           LOG.info("Message with message key " + this._messageKey +
                    " in folder '" + folder.URI + "' does not match expected " +
                    "header! (" + this._headerMessageID + " expected, got " +
@@ -695,18 +708,19 @@ GlodaMessage.prototype = {
     LOG.info("Unable to locate folder message for: " + this._folderID + ":" +
              this._messageKey);
     return null;
   },
   get folderMessageURI() {
     let folderMessage = this.folderMessage;
     if (folderMessage)
       return folderMessage.folder.getUriForMsg(folderMessage);
-    return null;
-  },
+    else
+      return null;
+  }
 };
 MixIn(GlodaMessage, GlodaHasAttributesMixIn);
 
 /**
  * @class Contacts correspond to people (one per person), and may own multiple
  *  identities (e-mail address, IM account, etc.)
  */
 function GlodaContact(aDatastore, aID, aDirectoryUUID, aContactUUID, aName,
@@ -746,25 +760,25 @@ GlodaContact.prototype = {
     this._frecency = aFrecency;
     this.dirty = true;
   },
 
   get identities() {
     return this._identities;
   },
 
-  toString() {
+  toString: function gloda_contact_toString() {
     return "Contact:" + this._id;
   },
 
   get accessibleLabel() {
     return "Contact: " + this._name;
   },
 
-  _clone() {
+  _clone: function gloda_contact_clone() {
     return new GlodaContact(/* datastore */ null, this._id, this._directoryUUID,
       this._contactUUID, this._name, this._popularity, this._frecency);
   },
 };
 MixIn(GlodaContact, GlodaHasAttributesMixIn);
 
 
 /**
@@ -775,19 +789,19 @@ function GlodaIdentity(aDatastore, aID, 
   // _datastore set on the prototype by GlodaDatastore
   this._id = aID;
   this._contactID = aContactID;
   this._contact = aContact;
   this._kind = aKind;
   this._value = aValue;
   this._description = aDescription;
   this._isRelay = aIsRelay;
-  // Cached indication of whether there is an address book card for this
-  //  identity.  We keep this up-to-date via address book listener
-  //  notifications in |GlodaABIndexer|.
+  /// Cached indication of whether there is an address book card for this
+  ///  identity.  We keep this up-to-date via address book listener
+  ///  notifications in |GlodaABIndexer|.
   this._hasAddressBookCard = undefined;
 }
 
 GlodaIdentity.prototype = {
   NOUN_ID: 104,
   // set by GlodaDatastore
   _datastore: null,
   get id() { return this._id; },
@@ -797,21 +811,21 @@ GlodaIdentity.prototype = {
   get value() { return this._value; },
   get description() { return this._description; },
   get isRelay() { return this._isRelay; },
 
   get uniqueValue() {
     return this._kind + "@" + this._value;
   },
 
-  toString() {
+  toString: function gloda_identity_toString() {
     return "Identity:" + this._kind + ":" + this._value;
   },
 
-  toLocaleString() {
+  toLocaleString: function gloda_identity_toLocaleString() {
     if (this.contact.name == this.value)
       return this.value;
     return this.contact.name + " : " + this.value;
   },
 
   get abCard() {
     // for our purposes, the address book only speaks email
     if (this._kind != "email")
@@ -827,22 +841,22 @@ GlodaIdentity.prototype = {
    *  and its notifications.
    */
   get inAddressBook() {
     if (this._hasAddressBookCard !== undefined)
       return this._hasAddressBookCard;
     return (this.abCard && true) || false;
   },
 
-  pictureURL(aSize) {
+  pictureURL: function(aSize) {
     if (this.inAddressBook) {
       // XXX should get the photo if we have it.
     }
     return "";
-  },
+  }
 };
 
 
 /**
  * An attachment, with as much information as we can gather on it
  */
 function GlodaAttachment(aGlodaMessage, aName, aContentType, aSize, aPart, aExternalUrl, aIsExternal) {
   // _datastore set on the prototype by GlodaDatastore
@@ -859,26 +873,28 @@ GlodaAttachment.prototype = {
   NOUN_ID: 105,
   // set by GlodaDatastore
   get name() { return this._name; },
   get contentType() { return this._contentType; },
   get size() { return this._size; },
   get url() {
     if (this.isExternal)
       return this._externalUrl;
-
-    let uri = this._glodaMessage.folderMessageURI;
-    if (!uri)
-      throw new Error("The message doesn't exist anymore, unable to rebuild attachment URL");
-    let neckoURL = {};
-    let msgService = getMessenger().messageServiceFromURI(uri);
-    msgService.GetUrlForUri(uri, neckoURL, null);
-    let url = neckoURL.value.spec;
-    let hasParamAlready = url.match(/\?[a-z]+=[^\/]+$/);
-    let sep = hasParamAlready ? "&" : "?";
-    return url + sep + "part=" + this._part + "&filename=" + encodeURIComponent(this._name);
+    else {
+      let uri = this._glodaMessage.folderMessageURI;
+      if (!uri)
+        throw new Error("The message doesn't exist anymore, unable to rebuild attachment URL");
+      let neckoURL = {};
+      let msgService = getMessenger().messageServiceFromURI(uri);
+      msgService.GetUrlForUri(uri, neckoURL, null);
+      let url = neckoURL.value.spec;
+      let hasParamAlready = url.match(/\?[a-z]+=[^\/]+$/);
+      let sep = hasParamAlready ? "&" : "?";
+      return url+sep+"part="+this._part+"&filename="+encodeURIComponent(this._name);
+    }
   },
   get isExternal() { return this._isExternal; },
 
-  toString() {
+  toString: function gloda_attachment_toString() {
     return "attachment: " + this._name + ":" + this._contentType;
   },
+
 };
--- a/mailnews/db/gloda/modules/datastore.js
+++ b/mailnews/db/gloda/modules/datastore.js
@@ -36,44 +36,47 @@ var PCH_LOG = Log4Moz.repository.getLogg
  *  |GlodaDatastore._asyncCompleted|.
  */
 function PostCommitHandler(aCallbacks) {
   this.callbacks = aCallbacks;
   GlodaDatastore._pendingAsyncStatements++;
 }
 
 PostCommitHandler.prototype = {
-  handleResult(aResultSet) {
+  handleResult: function gloda_ds_pch_handleResult(aResultSet) {
   },
 
-  handleError(aError) {
+  handleError: function gloda_ds_pch_handleError(aError) {
     PCH_LOG.error("database error:" + aError);
   },
 
-  handleCompletion(aReason) {
+  handleCompletion: function gloda_ds_pch_handleCompletion(aReason) {
     // just outright bail if we are shutdown
     if (GlodaDatastore.datastoreIsShutdown)
       return;
 
     if (aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED) {
       for (let callback of this.callbacks) {
         try {
           callback();
-        } catch (ex) {
+        }
+        catch (ex) {
           PCH_LOG.error("PostCommitHandler callback (" + ex.fileName + ":" +
                ex.lineNumber + ") threw: " + ex);
         }
       }
     }
     try {
       GlodaDatastore._asyncCompleted();
-    } catch (e) {
+    }
+    catch (e) {
       PCH_LOG.error("Exception in handleCompletion:", e);
     }
-  },
+
+  }
 };
 
 var QFQ_LOG = Log4Moz.repository.getLogger("gloda.ds.qfq");
 
 /**
  * Singleton collection listener used by |QueryFromQueryCallback| to assist in
  *  the loading of referenced noun instances.  Which is to say, messages have
  *  identities (specific e-mail addresses) associated with them via attributes.
@@ -81,71 +84,71 @@ var QFQ_LOG = Log4Moz.repository.getLogg
  *  notion of a person).
  *
  * This listener is primarily concerned with fixing up the references in each
  *  noun instance to its referenced instances once they have been loaded.  It
  *  also deals with caching so that our identity invariant is maintained: user
  *  code should only ever see one distinct instance of a thing at a time.
  */
 var QueryFromQueryResolver = {
-  onItemsAdded(aIgnoredItems, aCollection, aFake) {
+  onItemsAdded: function(aIgnoredItems, aCollection, aFake) {
     let originColl = aCollection.dataStack ? aCollection.dataStack.pop()
                                            : aCollection.data;
-    // QFQ_LOG.debug("QFQR: originColl: " + originColl);
+    //QFQ_LOG.debug("QFQR: originColl: " + originColl);
     if (aCollection.completionShifter)
       aCollection.completionShifter.push(originColl);
     else
       aCollection.completionShifter = [originColl];
 
     if (!aFake) {
       originColl.deferredCount--;
       originColl.resolvedCount++;
     }
 
     // bail if we are still pending on some other load completion
     if (originColl.deferredCount > 0) {
-      // QFQ_LOG.debug("QFQR: bailing " + originColl._nounDef.name);
+      //QFQ_LOG.debug("QFQR: bailing " + originColl._nounDef.name);
       return;
     }
 
     let referencesByNounID = originColl.masterCollection.referencesByNounID;
     let inverseReferencesByNounID =
       originColl.masterCollection.inverseReferencesByNounID;
 
     if (originColl.pendingItems) {
       for (let item of originColl.pendingItems) {
-        // QFQ_LOG.debug("QFQR: loading deferred " + item.NOUN_ID + ":" + item.id);
+        //QFQ_LOG.debug("QFQR: loading deferred " + item.NOUN_ID + ":" + item.id);
         GlodaDatastore.loadNounDeferredDeps(item, referencesByNounID,
             inverseReferencesByNounID);
       }
 
       // we need to consider the possibility that we are racing a collection very
       //  much like our own.  as such, this means we need to perform cache
       //  unification as our last step.
       GlodaCollectionManager.cacheLoadUnify(originColl._nounDef.id,
         originColl.pendingItems, false);
 
       // just directly tell the collection about the items.  we know the query
       //  matches (at least until we introduce predicates that we cannot express
       //  in SQL.)
-      // QFQ_LOG.debug(" QFQR: about to trigger listener: " + originColl._listener +
+      //QFQ_LOG.debug(" QFQR: about to trigger listener: " + originColl._listener +
       //    "with collection: " + originColl._nounDef.name);
       originColl._onItemsAdded(originColl.pendingItems);
       delete originColl.pendingItems;
       delete originColl._pendingIdMap;
     }
   },
-  onItemsModified() {
+  onItemsModified: function() {
   },
-  onItemsRemoved() {
+  onItemsRemoved: function() {
   },
-  onQueryCompleted(aCollection) {
+  onQueryCompleted: function(aCollection) {
     let originColl = aCollection.completionShifter ?
       aCollection.completionShifter.shift() : aCollection.data;
-    // QFQ_LOG.debug(" QFQR about to trigger completion with collection: " +
+    //QFQ_LOG.debug(" QFQR about to trigger completion with collection: " +
     //  originColl._nounDef.name);
     if (originColl.deferredCount <= 0) {
       originColl._onQueryCompleted();
     }
   },
 };
 
 /**
@@ -161,17 +164,17 @@ var QueryFromQueryResolver = {
  *  complex.  Some of the logic here 'evolved' a bit and could benefit from
  *  additional documentation and a fresh go-through.
  */
 function QueryFromQueryCallback(aStatement, aNounDef, aCollection) {
   this.statement = aStatement;
   this.nounDef = aNounDef;
   this.collection = aCollection;
 
-  // QFQ_LOG.debug("Creating QFQCallback for noun: " + aNounDef.name);
+  //QFQ_LOG.debug("Creating QFQCallback for noun: " + aNounDef.name);
 
   // the master collection holds the referencesByNounID
   this.referencesByNounID = {};
   this.masterReferencesByNounID =
     this.collection.masterCollection.referencesByNounID;
   this.inverseReferencesByNounID = {};
   this.masterInverseReferencesByNounID =
     this.collection.masterCollection.inverseReferencesByNounID;
@@ -193,17 +196,17 @@ function QueryFromQueryCallback(aStateme
   }
 
   this.needsLoads = false;
 
   GlodaDatastore._pendingAsyncStatements++;
 }
 
 QueryFromQueryCallback.prototype = {
-  handleResult(aResultSet) {
+  handleResult: function gloda_ds_qfq_handleResult(aResultSet) {
     try {
       // just outright bail if we are shutdown
       if (GlodaDatastore.datastoreIsShutdown)
         return;
 
       let pendingItems = this.collection.pendingItems;
       let pendingIdMap = this.collection._pendingIdMap;
       let row;
@@ -220,17 +223,17 @@ QueryFromQueryCallback.prototype = {
         // try and replace the item with one from the cache, if we can
         let cachedItem = GlodaCollectionManager.cacheLookupOne(nounID, item.id,
                                                                false);
 
         // if we already have a copy in the pending id map, skip it
         if (item.id in pendingIdMap)
           continue;
 
-        // QFQ_LOG.debug("loading item " + nounDef.id + ":" + item.id + " existing: " +
+        //QFQ_LOG.debug("loading item " + nounDef.id + ":" + item.id + " existing: " +
         //    this.selfReferences[item.id] + " cached: " + cachedItem);
         if (cachedItem)
           item = cachedItem;
         // we may already have been loaded by this process
         else if (this.selfReferences[item.id] != null)
           item = this.selfReferences[item.id];
         // perform loading logic which may produce reference dependencies
         else
@@ -251,62 +254,63 @@ QueryFromQueryCallback.prototype = {
           if (childrenList === undefined)
             childrenList = this.selfInverseReferences[parentID] = [];
           childrenList.push(item);
         }
 
         pendingItems.push(item);
         pendingIdMap[item.id] = item;
       }
-    } catch (e) {
+    }
+    catch (e) {
       GlodaDatastore._log.error("Exception in handleResult:", e);
     }
   },
 
-  handleError(aError) {
+  handleError: function gloda_ds_qfq_handleError(aError) {
     GlodaDatastore._log.error("Async queryFromQuery error: " +
       aError.result + ": " + aError.message);
   },
 
-  handleCompletion(aReason) {
+  handleCompletion: function gloda_ds_qfq_handleCompletion(aReason) {
     try {
       try {
         this.statement.finalize();
         this.statement = null;
 
         // just outright bail if we are shutdown
         if (GlodaDatastore.datastoreIsShutdown)
           return;
 
-        // QFQ_LOG.debug("handleCompletion: " + this.collection._nounDef.name);
+        //QFQ_LOG.debug("handleCompletion: " + this.collection._nounDef.name);
 
         if (this.needsLoads) {
           for (let nounID in this.referencesByNounID) {
             let references = this.referencesByNounID[nounID];
             if (nounID == this.nounDef.id)
               continue;
             let nounDef = GlodaDatastore._nounIDToDef[nounID];
-            // QFQ_LOG.debug("  have references for noun: " + nounDef.name);
+            //QFQ_LOG.debug("  have references for noun: " + nounDef.name);
             // try and load them out of the cache/existing collections.  items in the
             //  cache will be fully formed, which is nice for us.
             // XXX this mechanism will get dubious when we have multiple paths to a
             //  single noun-type.  For example, a -> b -> c, a-> c; two paths to c
             //  and we're looking at issuing two requests to c, the latter of which
             //  will be a superset of the first one.  This does not currently pose
             //  a problem because we only have a -> b -> c -> b, and sequential
             //  processing means no alarms and no surprises.
             let masterReferences = this.masterReferencesByNounID[nounID];
             if (masterReferences === undefined)
               masterReferences = this.masterReferencesByNounID[nounID] = {};
             let outReferences;
             if (nounDef.parentColumnAttr)
               outReferences = {};
             else
               outReferences = masterReferences;
-            let [, notFoundCount, notFound] =
+            let [foundCount, notFoundCount, notFound] =
               GlodaCollectionManager.cacheLookupMany(nounDef.id, references,
                   outReferences);
 
             if (nounDef.parentColumnAttr) {
               let inverseReferences;
               if (nounDef.id in this.masterInverseReferencesByNounID)
                 inverseReferences =
                   this.masterInverseReferencesByNounID[nounDef.id];
@@ -320,20 +324,21 @@ QueryFromQueryCallback.prototype = {
                 let parentID = item[nounDef.parentColumnAttr.idStorageAttributeName];
                 let childrenList = inverseReferences[parentID];
                 if (childrenList === undefined)
                   childrenList = inverseReferences[parentID] = [];
                 childrenList.push(item);
               }
             }
 
-            // QFQ_LOG.debug("  found: " + foundCount + " not found: " + notFoundCount);
+            //QFQ_LOG.debug("  found: " + foundCount + " not found: " + notFoundCount);
             if (notFoundCount === 0) {
               this.collection.resolvedCount++;
-            } else {
+            }
+            else {
               this.collection.deferredCount++;
               let query = new nounDef.queryClass();
               query.id.apply(query, Object.keys(notFound));
 
               // we fully expect/allow for there being no such subcollection yet.
               let subCollection = (nounDef.id in this.collection.masterCollection.subCollections) ?
                                   this.collection.masterCollection.subCollections[nounDef.id] : undefined;
               this.collection.masterCollection.subCollections[nounDef.id] =
@@ -345,144 +350,147 @@ QueryFromQueryCallback.prototype = {
             }
           }
 
           for (let nounID in this.inverseReferencesByNounID) {
             let inverseReferences = this.inverseReferencesByNounID[nounID];
             this.collection.deferredCount++;
             let nounDef = GlodaDatastore._nounIDToDef[nounID];
 
-            // QFQ_LOG.debug("Want to load inverse via " + nounDef.parentColumnAttr.boundName);
+            //QFQ_LOG.debug("Want to load inverse via " + nounDef.parentColumnAttr.boundName);
 
             let query = new nounDef.queryClass();
             // we want to constrain using the parent column
             let queryConstrainer = query[nounDef.parentColumnAttr.boundName];
             queryConstrainer.apply(query, Object.keys(inverseReferences));
             // we fully expect/allow for there being no such subcollection yet.
             let subCollection = (nounDef.id in this.collection.masterCollection.subCollections) ?
                                 this.collection.masterCollection.subCollections[nounDef.id] : undefined;
             this.collection.masterCollection.subCollections[nounDef.id] =
               GlodaDatastore.queryFromQuery(query, QueryFromQueryResolver,
                 this.collection,
                 subCollection,
                 this.collection.masterCollection,
                 {becomeExplicit: true});
           }
-        } else {
+        }
+        else {
           this.collection.deferredCount--;
           this.collection.resolvedCount++;
         }
 
-        // QFQ_LOG.debug("  defer: " + this.collection.deferredCount +
+        //QFQ_LOG.debug("  defer: " + this.collection.deferredCount +
         //              " resolved: " + this.collection.resolvedCount);
 
         // process immediately and kick-up to the master collection...
         if (this.collection.deferredCount <= 0) {
           // this guy will resolve everyone using referencesByNounID and issue the
           //  call to this.collection._onItemsAdded to propagate things to the
           //  next concerned subCollection or the actual listener if this is the
           //  master collection.  (Also, call _onQueryCompleted).
           QueryFromQueryResolver.onItemsAdded(null, {data: this.collection}, true);
           QueryFromQueryResolver.onQueryCompleted({data: this.collection});
         }
-      } catch (e) {
+      }
+      catch (e) {
         Cu.reportError(e);
         QFQ_LOG.error("Exception:", e);
       }
-    } finally {
+    }
+    finally {
       GlodaDatastore._asyncCompleted();
     }
-  },
+  }
 };
 
 /**
  * Used by |GlodaDatastore.folderCompactionPassBlockFetch| to accumulate the
  *  results and pass them back in to the compaction process in
  *  |GlodaMsgIndexer._worker_folderCompactionPass|.
  */
 function CompactionBlockFetcherHandler(aCallback) {
   this.callback = aCallback;
   this.idsAndMessageKeys = [];
   GlodaDatastore._pendingAsyncStatements++;
 }
 CompactionBlockFetcherHandler.prototype = {
-  handleResult(aResultSet) {
+  handleResult: function gloda_ds_cbfh_handleResult(aResultSet) {
     let row;
     while ((row = aResultSet.getNextRow())) {
       this.idsAndMessageKeys.push([
         row.getInt64(0), // id
         row.getInt64(1), // messageKey
         row.getString(2), // headerMessageID
         ]);
     }
   },
-  handleError(aError) {
+  handleError: function gloda_ds_cbfh_handleError(aError) {
     GlodaDatastore._log.error("CompactionBlockFetcherHandler error: " +
       aError.result + ": " + aError.message);
   },
-  handleCompletion(aReason) {
+  handleCompletion: function gloda_ds_cbfh_handleCompletion(aReason) {
     GlodaDatastore._asyncCompleted();
     this.callback(this.idsAndMessageKeys);
-  },
+  }
 };
 
 /**
  * Use this as the callback handler when you have a SQL query that returns a
  *  single row with a single integer column value, like a COUNT() query.
  */
 function SingletonResultValueHandler(aCallback) {
   this.callback = aCallback;
   this.result = null;
   GlodaDatastore._pendingAsyncStatements++;
 }
 SingletonResultValueHandler.prototype = {
-  handleResult(aResultSet) {
+  handleResult: function gloda_ds_cbfh_handleResult(aResultSet) {
     let row;
     while ((row = aResultSet.getNextRow())) {
       this.result = row.getInt64(0);
     }
   },
-  handleError(aError) {
+  handleError: function gloda_ds_cbfh_handleError(aError) {
     GlodaDatastore._log.error("SingletonResultValueHandler error: " +
       aError.result + ": " + aError.message);
   },
-  handleCompletion(aReason) {
+  handleCompletion: function gloda_ds_cbfh_handleCompletion(aReason) {
     GlodaDatastore._asyncCompleted();
     this.callback(this.result);
-  },
+  }
 };
 
 /**
  * Wrapper that duplicates actions taken on a real statement to an explain
  *  statement.  Currently only fires an explain statement once.
  */
 function ExplainedStatementWrapper(aRealStatement, aExplainStatement,
                                    aSQLString, aExplainHandler) {
   this.real = aRealStatement;
   this.explain = aExplainStatement;
   this.sqlString = aSQLString;
   this.explainHandler = aExplainHandler;
   this.done = false;
 }
 ExplainedStatementWrapper.prototype = {
-  bindByIndex(aColIndex, aValue) {
+  bindByIndex: function(aColIndex, aValue) {
     this.real.bindByIndex(aColIndex, aValue);
     if (!this.done)
       this.explain.bindByIndex(aColIndex, aValue);
   },
-  executeAsync(aCallback) {
+  executeAsync: function wrapped_executeAsync(aCallback) {
     if (!this.done) {
       this.explainHandler.sqlEnRoute(this.sqlString);
       this.explain.executeAsync(this.explainHandler);
       this.explain.finalize();
       this.done = true;
     }
     return this.real.executeAsync(aCallback);
   },
-  finalize() {
+  finalize: function wrapped_finalize() {
     if (!this.done)
       this.explain.finalize();
     this.real.finalize();
   },
 };
 
 /**
  * Writes a single JSON document to the provide file path in a streaming
@@ -503,61 +511,61 @@ function ExplainedStatementProcessor(aDu
   this._ostream = Cc["@mozilla.org/network/file-output-stream;1"]
                  .createInstance(Ci.nsIFileOutputStream);
   this._ostream.init(filePath, -1, -1, 0);
 
   let s = '{"queries": [';
   this._ostream.write(s, s.length);
 }
 ExplainedStatementProcessor.prototype = {
-  sqlEnRoute(aSQLString) {
+  sqlEnRoute: function esp_sqlEnRoute(aSQLString) {
     this._sqlStack.push(aSQLString);
   },
-  handleResult(aResultSet) {
+  handleResult: function esp_handleResult(aResultSet) {
     let row;
     // addr  opcode (s)      p1    p2    p3    p4 (s)   p5   comment (s)
     while ((row = aResultSet.getNextRow())) {
       this._curOps.push([
         row.getInt64(0),  // addr
         row.getString(1), // opcode
         row.getInt64(2),  // p1
         row.getInt64(3),  // p2
         row.getInt64(4),  // p3
         row.getString(5), // p4
         row.getString(6), // p5
-        row.getString(7), // comment
+        row.getString(7)  // comment
       ]);
     }
   },
-  handleError(aError) {
+  handleError: function esp_handleError(aError) {
     Cu.reportError("Unexpected error in EXPLAIN handler: " + aError);
   },
-  handleCompletion(aReason) {
+  handleCompletion: function esp_handleCompletion(aReason) {
     let obj = {
       sql: this._sqlStack.shift(),
       operations: this._curOps,
     };
     let s = (this._objsWritten++ ? ", " : "") + JSON.stringify(obj, null, 2);
     this._ostream.write(s, s.length);
 
     this._curOps = [];
   },
 
-  observe(aSubject, aTopic, aData) {
+  observe: function esp_observe(aSubject, aTopic, aData) {
     if (aTopic == "quit-application")
       this.shutdown();
   },
 
-  shutdown() {
+  shutdown: function esp_shutdown() {
     let s = "]}";
     this._ostream.write(s, s.length);
     this._ostream.close();
 
     Services.obs.removeObserver(this, "quit-application");
-  },
+  }
 };
 
 // See the documentation on GlodaDatastore._schemaVersion to understand these:
 var DB_SCHEMA_ACCEPT_LEAVE_LOW = 31,
       DB_SCHEMA_ACCEPT_LEAVE_HIGH = 34,
       DB_SCHEMA_ACCEPT_DOWNGRADE_LOW = 35,
       DB_SCHEMA_ACCEPT_DOWNGRADE_HIGH = 39,
       DB_SCHEMA_DOWNGRADE_DELTA = 5;
@@ -654,18 +662,18 @@ var DB_SCHEMA_ACCEPT_LEAVE_LOW = 31,
  * @namespace
  */
 var GlodaDatastore = {
   _log: null,
 
   /* see Gloda's documentation for these constants */
   kSpecialNotAtAll: 0,
   kSpecialColumn: 16,
-  kSpecialColumnChildren: 16 | 1,
-  kSpecialColumnParent: 16 | 2,
+  kSpecialColumnChildren: 16|1,
+  kSpecialColumnParent: 16|2,
   kSpecialString: 32,
   kSpecialFulltext: 64,
   IGNORE_FACET: {},
 
   kConstraintIdIn: 0,
   kConstraintIn: 1,
   kConstraintRanges: 2,
   kConstraintEquals: 3,
@@ -777,19 +785,19 @@ var GlodaDatastore = {
         columns: [
           ["id", "INTEGER PRIMARY KEY"],
           ["subject", "TEXT NOT NULL"],
           ["oldestMessageDate", "INTEGER"],
           ["newestMessageDate", "INTEGER"],
         ],
 
         indices: {
-          subject: ["subject"],
-          oldestMessageDate: ["oldestMessageDate"],
-          newestMessageDate: ["newestMessageDate"],
+          subject: ['subject'],
+          oldestMessageDate: ['oldestMessageDate'],
+          newestMessageDate: ['newestMessageDate'],
         },
 
         fulltextColumns: [
           ["subject", "TEXT"],
         ],
 
         triggers: {
           delete: "DELETE from messages WHERE conversationID = OLD.id",
@@ -822,21 +830,21 @@ var GlodaDatastore = {
           // Notability attempts to capture the static 'interestingness' of a
           //  message as a result of being starred/flagged, labeled, read
           //  multiple times, authored by someone in your address book or that
           //  you converse with a lot, etc.
           ["notability", "INTEGER NOT NULL default 0"],
         ],
 
         indices: {
-          messageLocation: ["folderID", "messageKey"],
-          headerMessageID: ["headerMessageID"],
-          conversationID: ["conversationID"],
-          date: ["date"],
-          deleted: ["deleted"],
+          messageLocation: ['folderID', 'messageKey'],
+          headerMessageID: ['headerMessageID'],
+          conversationID: ['conversationID'],
+          date: ['date'],
+          deleted: ['deleted'],
         },
 
         // note: if reordering the columns, you need to change this file's
         //  row-loading logic, msg_search.js's ranking usages and also the
         //  column saturations in nsGlodaRankerFunction
         fulltextColumns: [
           ["body", "TEXT"],
           ["subject", "TEXT"],
@@ -921,24 +929,25 @@ var GlodaDatastore = {
           popularity: ["popularity"],
           frecency: ["frecency"],
         },
       },
 
       contactAttributes: {
         columns: [
           ["contactID", "INTEGER NOT NULL"],
-          ["attributeID", "INTEGER NOT NULL"],
-          ["value", "NUMERIC"],
+          ["attributeID",
+           "INTEGER NOT NULL"],
+          ["value", "NUMERIC"]
         ],
         indices: {
           contactAttribQuery: [
             "attributeID", "value",
             /* covering: */ "contactID"],
-        },
+        }
       },
 
       /**
        * Identities correspond to specific e-mail addresses, IRC nicks, etc.
        */
       identities: {
         columns: [
           ["id", "INTEGER PRIMARY KEY"],
@@ -948,18 +957,18 @@ var GlodaDatastore = {
           ["description", "NOT NULL"], // what makes this identity different
           // from the others? (ex: home, work, etc.)
           ["relay", "INTEGER NOT NULL"], // is the identity just a relay
           // mechanism? (ex: mailing list, twitter 'bouncer', IRC gateway, etc.)
         ],
 
         indices: {
           contactQuery: ["contactID"],
-          valueQuery: ["kind", "value"],
-        },
+          valueQuery: ["kind", "value"]
+        }
       },
     },
   },
 
 
   /* ******************* LOGIC ******************* */
   /**
    * We only have one connection; this name exists for legacy reasons but helps
@@ -985,17 +994,17 @@ var GlodaDatastore = {
    */
   _datastoreID: null,
 
   /**
    * Initialize logging, create the database if it doesn't exist, "upgrade" it
    *  if it does and it's not up-to-date, fill our authoritative folder uri/id
    *  mapping.
    */
-  _init(aNounIDToDef) {
+  _init: function gloda_ds_init(aNounIDToDef) {
     this._log = Log4Moz.repository.getLogger("gloda.datastore");
     this._log.debug("Beginning datastore initialization.");
 
     this._nounIDToDef = aNounIDToDef;
 
     let branch = Services.prefs.getBranch("mailnews.database.global.datastore.");
     this._prefBranch = branch;
 
@@ -1011,61 +1020,67 @@ var GlodaDatastore = {
 
     var dbConnection;
 
     // Report about the size of the database through telemetry (if there's a
     // database, naturally).
     if (dbFile.exists()) {
       try {
         let h = Services.telemetry.getHistogramById("THUNDERBIRD_GLODA_SIZE_MB");
-        h.add(dbFile.fileSize / 1048576);
+        h.add(dbFile.fileSize/1048576);
       } catch (e) {
         this._log.warn("Couldn't report telemetry", e);
       }
     }
 
     // Create the file if it does not exist
     if (!dbFile.exists()) {
       this._log.debug("Creating database because it doesn't exist.");
       dbConnection = this._createDB(dbFile);
-    } else { // It does exist, but we (someday) might need to upgrade the schema
+    }
+    // It does exist, but we (someday) might need to upgrade the schema
+    else {
       // (Exceptions may be thrown if the database is corrupt)
       try {
         dbConnection = Services.storage.openUnsharedDatabase(dbFile);
         let cacheSize = this._determineCachePages(dbConnection);
         // see _createDB...
-        dbConnection.executeSimpleSQL("PRAGMA cache_size = " + cacheSize);
+        dbConnection.executeSimpleSQL("PRAGMA cache_size = "+cacheSize);
         dbConnection.executeSimpleSQL("PRAGMA synchronous = FULL");
 
         // Register custom tokenizer to index all language text
         var tokenizer = Cc["@mozilla.org/messenger/fts3tokenizer;1"].
                           getService(Ci.nsIFts3Tokenizer);
         tokenizer.registerTokenizer(dbConnection);
 
         // -- database schema changes
         let dbSchemaVersion = this._actualSchemaVersion =
           dbConnection.schemaVersion;
         // - database from the future!
         if (dbSchemaVersion > this._schemaVersion) {
           if (dbSchemaVersion >= DB_SCHEMA_ACCEPT_LEAVE_LOW &&
               dbSchemaVersion <= DB_SCHEMA_ACCEPT_LEAVE_HIGH) {
             this._log.debug("db from the future in acceptable range; leaving " +
                             "version at: " + dbSchemaVersion);
-          } else if (dbSchemaVersion >= DB_SCHEMA_ACCEPT_DOWNGRADE_LOW &&
-                     dbSchemaVersion <= DB_SCHEMA_ACCEPT_DOWNGRADE_HIGH) {
+          }
+          else if (dbSchemaVersion >= DB_SCHEMA_ACCEPT_DOWNGRADE_LOW &&
+                   dbSchemaVersion <= DB_SCHEMA_ACCEPT_DOWNGRADE_HIGH) {
             let newVersion = dbSchemaVersion - DB_SCHEMA_DOWNGRADE_DELTA;
             this._log.debug("db from the future in downgrade range; setting " +
                             "version to " + newVersion + " down from " +
                             dbSchemaVersion);
             dbConnection.schemaVersion = this._actualSchemaVersion = newVersion;
-          } else { // too far from the future, nuke it.
+          }
+          // too far from the future, nuke it.
+          else {
             dbConnection = this._nukeMigration(dbFile, dbConnection);
           }
-        } else if (dbSchemaVersion < this._schemaVersion) {
-          // - database from the past!  migrate it, possibly.
+        }
+        // - database from the past!  migrate it, possibly.
+        else if (dbSchemaVersion < this._schemaVersion) {
           this._log.debug("Need to migrate database.  (DB version: " +
             this._actualSchemaVersion + " desired version: " +
             this._schemaVersion);
           dbConnection = this._migrate(dbFile,
                                        dbConnection,
                                        this._actualSchemaVersion,
                                        this._schemaVersion);
           this._log.debug("Migration call completed.");
@@ -1074,23 +1089,26 @@ var GlodaDatastore = {
 
         // If we never had a datastore ID, make sure to create one now.
         if (!this._prefBranch.prefHasUserValue("id")) {
           this._datastoreID = this._generateDatastoreID();
           this._prefBranch.setCharPref("id", this._datastoreID);
         } else {
           this._datastoreID = this._prefBranch.getCharPref("id");
         }
-      } catch (ex) { // Handle corrupt databases, other oddities
+      }
+      // Handle corrupt databases, other oddities
+      catch (ex) {
         if (ex.result == Cr.NS_ERROR_FILE_CORRUPTED) {
           this._log.warn("Database was corrupt, removing the old one.");
           dbFile.remove(false);
           this._log.warn("Removed old database, creating a new one.");
           dbConnection = this._createDB(dbFile);
-        } else {
+        }
+        else {
           this._log.error("Unexpected error when trying to open the database:",
                           ex);
           throw ex;
         }
       }
     }
 
     this.syncConnection = dbConnection;
@@ -1111,53 +1129,55 @@ var GlodaDatastore = {
     //  we no longer need XPCOM references to (or more significantly, their
     //  message databases.)
     this._folderCleanupTimer =
       Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 
     this._log.debug("Completed datastore initialization.");
   },
 
-  observe(aSubject, aTopic, aData) {
-    if (aTopic != "nsPref:changed")
+  observe: function gloda_ds_observe(aSubject, aTopic, aData) {
+    if(aTopic != "nsPref:changed")
       return;
 
     if (aData == "explainToPath") {
       let explainToPath = null;
       try {
         explainToPath = this._prefBranch.getCharPref("explainToPath");
         if (explainToPath.trim() == "")
           explainToPath = null;
-      } catch (ex) {
+      }
+      catch (ex) {
         // don't care if the pref is not there.
       }
 
       // It is conceivable that the name is changing and this isn't a boolean
       // toggle, so always clean out the explain processor.
       if (this._explainProcessor) {
         this._explainProcessor.shutdown();
         this._explainProcessor = null;
       }
 
       if (explainToPath) {
         this._createAsyncStatement = this._createExplainedAsyncStatement;
         this._explainProcessor = new ExplainedStatementProcessor(
                                        explainToPath);
-      } else {
+      }
+      else {
         this._createAsyncStatement = this._realCreateAsyncStatement;
       }
     }
   },
 
   datastoreIsShutdown: false,
 
   /**
    * Perform datastore shutdown.
    */
-  shutdown() {
+  shutdown: function gloda_ds_shutdown() {
     // Clear out any pending transaction by committing it.
     // The indexer has been shutdown by this point; it no longer has any active
     //  indexing logic and it no longer has active event listeners capable of
     //  generating new activity.
     // Semantic consistency of the database is guaranteed by the indexer's
     //  strategy of only yielding control at coherent times.  Although it takes
     //  multiple calls and multiple SQL operations to update the state of our
     //  database representations, the generator does not yield until it has
@@ -1180,17 +1200,18 @@ var GlodaDatastore = {
 
     this._log.info("Closing db connection");
 
     // we do not expect exceptions, but it's a good idea to avoid having our
     //  shutdown process explode.
     try {
       this._cleanupAsyncStatements();
       this._cleanupSyncStatements();
-    } catch (ex) {
+    }
+    catch (ex) {
       this._log.debug("Unexpected exception during statement cleanup: " + ex);
     }
 
     // it's conceivable we might get a spurious exception here, but we really
     //  shouldn't get one.  again, we want to ensure shutdown runs to completion
     //  and doesn't break our caller.
     try {
       // This currently causes all pending asynchronous operations to be run to
@@ -1205,39 +1226,40 @@ var GlodaDatastore = {
       // However, the potential for multiple pending expensive queries does
       //  exist, and it may be advisable to attempt to track and cancel those.
       //  For simplicity we don't currently do this, and I expect this should
       //  not pose a major problem, but those are famous last words.
       // Note: asyncClose does not spin a nested event loop, but the thread
       //  manager shutdown code will spin the async thread's event loop, so it
       //  nets out to be the same.
       this.asyncConnection.asyncClose();
-    } catch (ex) {
+    }
+    catch (ex) {
       this._log.debug("Potentially expected exception during connection " +
                       "closure: " + ex);
     }
 
     this.asyncConnection = null;
     this.syncConnection = null;
   },
 
   /**
    * Generates and returns a UUID.
    *
    * @return a UUID as a string, ex: "c4dd0159-9287-480f-a648-a4613e147fdb"
    */
-  _generateDatastoreID() {
+  _generateDatastoreID: function gloda_ds_generateDatastoreID() {
     let uuidGen = Cc["@mozilla.org/uuid-generator;1"]
                     .getService(Ci.nsIUUIDGenerator);
     let uuid = uuidGen.generateUUID().toString();
     // We snip off the { and } from each end of the UUID.
     return uuid.substring(1, uuid.length - 2);
   },
 
-  _determineCachePages(aDBConn) {
+  _determineCachePages: function gloda_ds_determineCachePages(aDBConn) {
     try {
       // For the details of the computations, one should read
       //  nsNavHistory::InitDB. We're slightly diverging from them in the sense
       //  that we won't allow gloda to use insane amounts of memory cache, and
       //  we start with 1% instead of 6% like them.
       let pageStmt = aDBConn.createStatement("PRAGMA page_size");
       pageStmt.executeStep();
       let pageSize = pageStmt.row.page_size;
@@ -1259,27 +1281,27 @@ var GlodaDatastore = {
       // A little bit lower than on my personal machine, will result in ~40M.
       return 1000;
     }
   },
 
   /**
    * Create our database; basically a wrapper around _createSchema.
    */
-  _createDB(aDBFile) {
+  _createDB: function gloda_ds_createDB(aDBFile) {
     var dbConnection = Services.storage.openUnsharedDatabase(aDBFile);
     // We now follow the Firefox strategy for places, which mainly consists in
     //  picking a default 32k page size, and then figuring out the amount of
     //  cache accordingly. The default 32k come from mozilla/toolkit/storage,
     //  but let's get it directly from sqlite in case they change it.
     let cachePages = this._determineCachePages(dbConnection);
     // This is a maximum number of pages to be used.  If the database does not
     //  get this large, then the memory does not get used.
     // Do not forget to update the code in _init if you change this value.
-    dbConnection.executeSimpleSQL("PRAGMA cache_size = " + cachePages);
+    dbConnection.executeSimpleSQL("PRAGMA cache_size = "+cachePages);
     // The mozStorage default is NORMAL which shaves off some fsyncs in the
     //  interest of performance.  Since everything we do after bootstrap is
     //  async, we do not care about the performance, but we really want the
     //  correctness.  Bug reports and support avenues indicate a non-zero number
     //  of corrupt databases.  Note that this may not fix everything; OS X
     //  also supports an F_FULLSYNC flag enabled by PRAGMA fullfsync that we are
     //  not enabling that is much more comprehensive.  We can think about
     //  turning that on after we've seen how this reduces our corruption count.
@@ -1294,25 +1316,27 @@ var GlodaDatastore = {
     // has been rebuilt in the event that they need to rebuild dependent data.
     this._datastoreID = this._generateDatastoreID();
     this._prefBranch.setCharPref("id", this._datastoreID);
 
     dbConnection.beginTransaction();
     try {
       this._createSchema(dbConnection);
       dbConnection.commitTransaction();
-    } catch (ex) {
+    }
+    catch(ex) {
       dbConnection.rollbackTransaction();
       throw ex;
     }
 
     return dbConnection;
   },
 
-  _createTableSchema(aDBConnection, aTableName, aTableDef) {
+  _createTableSchema: function gloda_ds_createTableSchema(aDBConnection,
+      aTableName, aTableDef) {
     // - Create the table
     this._log.info("Creating table: " + aTableName);
     let columnDefs = [];
     for (let [column, type] of aTableDef.columns) {
       columnDefs.push(column + " " + type);
     }
     aDBConnection.createTable(aTableName, columnDefs.join(", "));
 
@@ -1339,59 +1363,60 @@ var GlodaDatastore = {
     }
 
     // - Create the attributes table if applicable
     if (aTableDef.genericAttributes) {
       aTableDef.genericAttributes = {
         columns: [
           ["nounID", "INTEGER NOT NULL"],
           ["attributeID", "INTEGER NOT NULL"],
-          ["value", "NUMERIC"],
+          ["value", "NUMERIC"]
         ],
-        indices: {},
+        indices: {}
       };
       aTableDef.genericAttributes.indices[aTableName + "AttribQuery"] =
         ["attributeID", "value", /* covering: */ "nounID"];
       // let's use this very function!  (since we created genericAttributes,
       //  explodey recursion is avoided.)
       this._createTableSchema(aDBConnection, aTableName + "Attributes",
                               aTableDef.genericAttributes);
     }
   },
 
   /**
    * Create our database schema assuming a newly created database.  This
    *  comes down to creating normal tables, their full-text variants (if
    *  applicable), and their indices.
    */
-  _createSchema(aDBConnection) {
+  _createSchema: function gloda_ds_createSchema(aDBConnection) {
     // -- For each table...
     for (let tableName in this._schema.tables) {
       let tableDef = this._schema.tables[tableName];
       this._createTableSchema(aDBConnection, tableName, tableDef);
     }
 
     aDBConnection.schemaVersion = this._actualSchemaVersion =
       this._schemaVersion;
   },
 
   /**
    * Create a table for a noun, replete with data binding.
    */
-  createNounTable(aNounDef) {
+  createNounTable: function gloda_ds_createTableIfNotExists(aNounDef) {
     // give it a _jsonText attribute if appropriate...
     if (aNounDef.allowsArbitraryAttrs)
-      aNounDef.schema.columns.push(["jsonAttributes", "STRING", "_jsonText"]);
+      aNounDef.schema.columns.push(['jsonAttributes', 'STRING', '_jsonText']);
     // check if the table exists
     if (!this.asyncConnection.tableExists(aNounDef.tableName)) {
       // it doesn't! create it (and its potentially many variants)
       try {
         this._createTableSchema(this.asyncConnection, aNounDef.tableName,
                                 aNounDef.schema);
-      } catch (ex) {
+      }
+      catch (ex) {
          this._log.error("Problem creating table " + aNounDef.tableName + " " +
            "because: " + ex + " at " + ex.fileName + ":" + ex.lineNumber);
          return;
       }
     }
 
     aNounDef._dataBinder = new GlodaDatabind(aNounDef, this);
     aNounDef.datastore = aNounDef._dataBinder;
@@ -1401,32 +1426,34 @@ var GlodaDatastore = {
     aNounDef.dbAttribAdjuster = aNounDef._dataBinder.adjustAttributes;
 
     if (aNounDef.schema.genericAttributes) {
       aNounDef.attrTableName = aNounDef.tableName + "Attributes";
       aNounDef.attrIDColumnName = "nounID";
     }
   },
 
-  _nukeMigration(aDBFile, aDBConnection) {
+  _nukeMigration: function gloda_ds_nukeMigration(aDBFile, aDBConnection) {
     aDBConnection.close();
     aDBFile.remove(false);
     this._log.warn("Global database has been purged due to schema change.  " +
                    "old version was " + this._actualSchemaVersion +
                    ", new version is: " + this._schemaVersion);
     return this._createDB(aDBFile);
   },
 
   /**
    * Migrate the database _to the latest version_ from an older version.  We
    *  only keep enough logic around to get us to the recent version.  This code
    *  is not a time machine!  If we need to blow away the database to get to the
    *  most recent version, then that's the sum total of the migration!
    */
-  _migrate(aDBFile, aDBConnection, aCurVersion, aNewVersion) {
+  _migrate: function gloda_ds_migrate(aDBFile, aDBConnection,
+                                      aCurVersion, aNewVersion) {
+
     // version 12:
     // - notability column added
     // version 13:
     // - we are adding a new fulltext index column. blow away!
     // - note that I screwed up and failed to mark the schema change; apparently
     //   no database will claim to be version 13...
     // version 14ish, still labeled 13?:
     // - new attributes: forwarded, repliedTo, bcc, recipients
@@ -1479,17 +1506,17 @@ var GlodaDatastore = {
    * Asynchronously update the schema version; only for use by in-tree callers
    *  who asynchronously perform migration work triggered by their initial
    *  indexing sweep and who have properly updated the schema version in all
    *  the appropriate locations in this file.
    *
    * This is done without doing anything about the current transaction state,
    *  which is desired.
    */
-  _updateSchemaVersion(newSchemaVersion) {
+  _updateSchemaVersion: function(newSchemaVersion) {
     this._actualSchemaVersion = newSchemaVersion;
     let stmt = this._createAsyncStatement(
       // we need to concat; pragmas don't like "?1" binds
       "PRAGMA user_version = " + newSchemaVersion, true);
     stmt.executeAsync(this.trackAsync());
     stmt.finalize();
   },
 
@@ -1497,21 +1524,23 @@ var GlodaDatastore = {
 
   /**
    * Unless debugging, this is just _realCreateAsyncStatement, but in some
    *  debugging modes this is instead the helpful wrapper
    *  _createExplainedAsyncStatement.
    */
   _createAsyncStatement: null,
 
-  _realCreateAsyncStatement(aSQLString, aWillFinalize) {
+  _realCreateAsyncStatement: function gloda_ds_createAsyncStatement(aSQLString,
+                                                                aWillFinalize) {
     let statement = null;
     try {
       statement = this.asyncConnection.createAsyncStatement(aSQLString);
-    } catch (ex) {
+    }
+    catch(ex) {
        throw new Error("error creating async statement " + aSQLString + " - " +
              this.asyncConnection.lastError + ": " +
              this.asyncConnection.lastErrorString + " - " + ex);
     }
 
     if (!aWillFinalize)
       this._outstandingAsyncStatements.push(statement);
 
@@ -1526,72 +1555,77 @@ var GlodaDatastore = {
   _explainProcessor: null,
 
   /**
    * Wrapped version of _createAsyncStatement that EXPLAINs the statement.  When
    *  used this decorates _createAsyncStatement, in which case we are found at
    *  that name and the original is at _orig_createAsyncStatement.  This is
    *  controlled by the explainToPath preference (see |_init|).
    */
-  _createExplainedAsyncStatement(aSQLString, aWillFinalize) {
+  _createExplainedAsyncStatement:
+      function gloda_ds__createExplainedAsyncStatement(aSQLString,
+                                                       aWillFinalize) {
     let realStatement = this._realCreateAsyncStatement(aSQLString,
                                                        aWillFinalize);
     // don't wrap transaction control statements.
     if (aSQLString == "COMMIT" ||
         aSQLString == "BEGIN TRANSACTION" ||
         aSQLString == "ROLLBACK")
       return realStatement;
 
     let explainSQL = "EXPLAIN " + aSQLString;
     let explainStatement = this._realCreateAsyncStatement(explainSQL);
 
     return new ExplainedStatementWrapper(realStatement, explainStatement,
                                          aSQLString, this._explainProcessor);
   },
 
-  _cleanupAsyncStatements() {
+  _cleanupAsyncStatements: function gloda_ds_cleanupAsyncStatements() {
     this._outstandingAsyncStatements.forEach(stmt => stmt.finalize());
   },
 
   _outstandingSyncStatements: [],
 
-  _createSyncStatement(aSQLString, aWillFinalize) {
+  _createSyncStatement: function gloda_ds_createSyncStatement(aSQLString,
+                                                              aWillFinalize) {
     let statement = null;
     try {
       statement = this.syncConnection.createStatement(aSQLString);
-    } catch (ex) {
+    }
+    catch(ex) {
        throw new Error("error creating sync statement " + aSQLString + " - " +
              this.syncConnection.lastError + ": " +
              this.syncConnection.lastErrorString + " - " + ex);
     }
 
     if (!aWillFinalize)
       this._outstandingSyncStatements.push(statement);
 
     return statement;
   },
 
-  _cleanupSyncStatements() {
+  _cleanupSyncStatements: function gloda_ds_cleanupSyncStatements() {
     this._outstandingSyncStatements.forEach(stmt => stmt.finalize());
   },
 
   /**
    * Perform a synchronous executeStep on the statement, handling any
    *  SQLITE_BUSY fallout that could conceivably happen from a collision on our
    *  read with the async writes.
    * Basically we keep trying until we succeed or run out of tries.
    * We believe this to be a reasonable course of action because we don't
    *  expect this to happen much.
    */
-  _syncStep(aStatement) {
+  _syncStep: function gloda_ds_syncStep(aStatement) {
     let tries = 0;
     while (tries < 32000) {
       try {
         return aStatement.executeStep();
-      } catch (e) {
+      }
+      catch (e) {
         // SQLITE_BUSY becomes NS_ERROR_FAILURE
         if (e.result == Cr.NS_ERROR_FAILURE) {
           tries++;
           // we really need to delay here, somehow.  unfortunately, we can't
           //  allow event processing to happen, and most of the things we could
           //  do to delay ourselves result in event processing happening.  (Use
           //  of a timer, a synchronous dispatch, etc.)
           // in theory, nsIThreadEventFilter could allow us to stop other events
@@ -1601,38 +1635,37 @@ var GlodaDatastore = {
           //  on makes us more likely to yield to the other thread so it can
           //  finish what it is doing...
         } else {
           throw e;
         }
       }
     }
     this._log.error("Synchronous step gave up after " + tries + " tries.");
-    return false;
   },
 
-  _bindVariant(aStatement, aIndex, aVariant) {
+  _bindVariant: function gloda_ds_bindBlob(aStatement, aIndex, aVariant) {
     aStatement.bindByIndex(aIndex, aVariant);
   },
 
   /**
    * Helper that uses the appropriate getter given the data type; should be
    *  mooted once we move to 1.9.2 and can use built-in variant support.
    */
-  _getVariant(aRow, aIndex) {
+  _getVariant: function gloda_ds_getBlob(aRow, aIndex) {
     let typeOfIndex = aRow.getTypeOfIndex(aIndex);
     if (typeOfIndex == Ci.mozIStorageValueArray.VALUE_TYPE_NULL)
       return null;
     // XPConnect would just end up going through an intermediary double stage
     //  for the int64 case anyways...
     else if (typeOfIndex == Ci.mozIStorageValueArray.VALUE_TYPE_INTEGER ||
              typeOfIndex == Ci.mozIStorageValueArray.VALUE_TYPE_DOUBLE)
       return aRow.getDouble(aIndex);
-    // typeOfIndex == Ci.mozIStorageValueArray.VALUE_TYPE_TEXT
-    return aRow.getString(aIndex);
+    else // typeOfIndex == Ci.mozIStorageValueArray.VALUE_TYPE_TEXT
+      return aRow.getString(aIndex);
   },
 
   /** Simple nested transaction support as a performance optimization. */
   _transactionDepth: 0,
   _transactionGood: false,
 
   /**
    * Self-memoizing BEGIN TRANSACTION statement.
@@ -1661,104 +1694,107 @@ var GlodaDatastore = {
     return this._rollbackTransactionStatement;
   },
 
   _pendingPostCommitCallbacks: null,
   /**
    * Register a callback to be invoked when the current transaction's commit
    *  completes.
    */
-  runPostCommit(aCallback) {
+  runPostCommit: function gloda_ds_runPostCommit(aCallback) {
     this._pendingPostCommitCallbacks.push(aCallback);
   },
 
   /**
    * Begin a potentially nested transaction; only the outermost transaction gets
    *  to be an actual transaction, and the failure of any nested transaction
    *  results in a rollback of the entire outer transaction.  If you really
    *  need an atomic transaction
    */
-  _beginTransaction() {
+  _beginTransaction: function gloda_ds_beginTransaction() {
     if (this._transactionDepth == 0) {
       this._pendingPostCommitCallbacks = [];
       this._beginTransactionStatement.executeAsync(this.trackAsync());
       this._transactionGood = true;
     }
     this._transactionDepth++;
   },
   /**
    * Commit a potentially nested transaction; if we are the outer-most
    *  transaction and no sub-transaction issues a rollback
    *  (via _rollbackTransaction) then we commit, otherwise we rollback.
    */
-  _commitTransaction() {
+  _commitTransaction: function gloda_ds_commitTransaction() {
     this._transactionDepth--;
     if (this._transactionDepth == 0) {
       try {
         if (this._transactionGood)
           this._commitTransactionStatement.executeAsync(
             new PostCommitHandler(this._pendingPostCommitCallbacks));
         else
           this._rollbackTransactionStatement.executeAsync(this.trackAsync());
-      } catch (ex) {
+      }
+      catch (ex) {
         this._log.error("Commit problem:", ex);
       }
       this._pendingPostCommitCallbacks = [];
     }
   },
   /**
    * Abort the commit of the potentially nested transaction.  If we are not the
    *  outermost transaction, we set a flag that tells the outermost transaction
    *  that it must roll back.
    */
-  _rollbackTransaction() {
+  _rollbackTransaction: function gloda_ds_rollbackTransaction() {
     this._transactionDepth--;
     this._transactionGood = false;
     if (this._transactionDepth == 0) {
       try {
         this._rollbackTransactionStatement.executeAsync(this.trackAsync());
-      } catch (ex) {
+      }
+      catch (ex) {
         this._log.error("Rollback problem:", ex);
       }
     }
   },
 
   _pendingAsyncStatements: 0,
   /**
    * The function to call, if any, when we hit 0 pending async statements.
    */
   _pendingAsyncCompletedListener: null,
-  _asyncCompleted() {
+  _asyncCompleted: function () {
     if (--this._pendingAsyncStatements == 0) {
       if (this._pendingAsyncCompletedListener !== null) {
         this._pendingAsyncCompletedListener();
         this._pendingAsyncCompletedListener = null;
       }
     }
   },
   _asyncTrackerListener: {
-    handleResult() {},
-    handleError(aError) {
+    handleResult: function () {},
+    handleError: function(aError) {
         GlodaDatastore._log.error("got error in _asyncTrackerListener.handleError(): " +
                         aError.result + ": " + aError.message);
     },
-    handleCompletion() {
+    handleCompletion: function () {
       try {
         // the helper method exists because the other classes need to call it too
         GlodaDatastore._asyncCompleted();
-      } catch (e) {
+      }
+      catch (e) {
         this._log.error("Exception in handleCompletion:", e);
       }
-    },
+    }
   },
   /**
    * Increments _pendingAsyncStatements and returns a listener that will
    *  decrement the value when the statement completes.
    */
-  trackAsync() {
+  trackAsync: function() {
     this._pendingAsyncStatements++;
     return this._asyncTrackerListener;
   },
 
   /* ********** Attribute Definitions ********** */
   /** Maps (attribute def) compound names to the GlodaAttributeDBDef objects. */
   _attributeDBDefs: {},
   /** Map attribute ID to the definition and parameter value that produce it. */
@@ -1776,17 +1812,17 @@ var GlodaDatastore = {
    *  Since we mediate the access, there's no real risk to doing so, and it
    *  allows us to keep the writes on the async connection without having to
    *  wait for a completion notification.
    *
    * Start from 32 so we can have a number of sentinel values.
    */
   _nextAttributeId: 32,
 
-  _populateAttributeDefManagedId() {
+  _populateAttributeDefManagedId: function () {
     let stmt = this._createSyncStatement(
       "SELECT MAX(id) FROM attributeDefinitions", true);
     if (stmt.executeStep()) { // no chance of this SQLITE_BUSY on this call
       // 0 gets returned even if there are no messages...
       let highestSeen = stmt.getInt64(0);
       if (highestSeen != 0)
         this._nextAttributeId = highestSeen + 1;
     }
@@ -1805,17 +1841,18 @@ var GlodaDatastore = {
   /**
    * Create an attribute definition and return the row ID.  Special/atypical
    *  in that it doesn't directly return a GlodaAttributeDBDef; we leave that up
    *  to the caller since they know much more than actually needs to go in the
    *  database.
    *
    * @return The attribute id allocated to this attribute.
    */
-  _createAttributeDef(aAttrType, aExtensionName, aAttrName, aParameter) {
+  _createAttributeDef: function gloda_ds_createAttributeDef(aAttrType,
+                                    aExtensionName, aAttrName, aParameter) {
     let attributeId = this._nextAttributeId++;
 
     let iads = this._insertAttributeDefStatement;
     iads.bindByIndex(0, attributeId);
     iads.bindByIndex(1, aAttrType);
     iads.bindByIndex(2, aExtensionName);
     iads.bindByIndex(3, aAttrName);
     this._bindVariant(iads, 4, aParameter);
@@ -1826,17 +1863,17 @@ var GlodaDatastore = {
   },
 
   /**
    * Sync-ly look-up all the attribute definitions, populating our authoritative
    *  _attributeDBDefss and _attributeIDToDBDefAndParam maps.  (In other words,
    *  once this method is called, those maps should always be in sync with the
    *  underlying database.)
    */
-  getAllAttributes() {
+  getAllAttributes: function gloda_ds_getAllAttributes() {
     let stmt = this._createSyncStatement(
       "SELECT id, attributeType, extensionName, name, parameter \
          FROM attributeDefinitions", true);
 
     // map compound name to the attribute
     let attribs = {};
     // map the attribute id to [attribute, parameter] where parameter is null
     //  in cases where parameter is unused.
@@ -1883,17 +1920,17 @@ var GlodaDatastore = {
   },
 
   /**
    * Helper method for GlodaAttributeDBDef to tell us when their bindParameter
    *  method is called and they have created a new binding (using
    *  GlodaDatastore._createAttributeDef).  In theory, that method could take
    *  an additional argument and obviate the need for this method.
    */
-  reportBinding(aID, aAttrDef, aParamValue) {
+  reportBinding: function gloda_ds_reportBinding(aID, aAttrDef, aParamValue) {
     this._attributeIDToDBDefAndParam[aID] = [aAttrDef, aParamValue];
   },
 
   /* ********** Folders ********** */
   /** next folder (row) id to issue, populated by _getAllFolderMappings. */
   _nextFolderId: 1,
 
   get _insertFolderLocationStatement() {
@@ -1911,17 +1948,17 @@ var GlodaDatastore = {
    *  sense that this map exactly represents the state of the underlying
    *  database.  If it does not, it's a bug in updating the database.)
    */
   _folderByURI: {},
   /** Authoritative map from folder ID to folder URI */
   _folderByID: {},
 
   /** Initialize our _folderByURI/_folderByID mappings, called by _init(). */
-  _getAllFolderMappings() {
+  _getAllFolderMappings: function gloda_ds_getAllFolderMappings() {
     let stmt = this._createSyncStatement(
       "SELECT id, folderURI, dirtyStatus, name, indexingPriority \
         FROM folderLocations", true);
 
     while (stmt.executeStep()) {  // no chance of this SQLITE_BUSY on this call
       let folderID = stmt.getInt64(0);
       let folderURI = stmt.getString(1);
       let dirtyStatus = stmt.getInt32(2);
@@ -1935,35 +1972,36 @@ var GlodaDatastore = {
       this._folderByID[folderID] = folder;
 
       if (folderID >= this._nextFolderId)
         this._nextFolderId = folderID + 1;
     }
     stmt.finalize();
   },
 
-  _folderKnown(aFolder) {
+  _folderKnown: function gloda_ds_folderKnown(aFolder) {
     let folderURI = aFolder.URI;
     return folderURI in this._folderByURI;
   },
 
-  _folderIdKnown(aFolderID) {
+  _folderIdKnown: function gloda_ds_folderIdKnown(aFolderID) {
     return (aFolderID in this._folderByID);
   },
 
   /**
    * Return the default messaging priority for a folder of this type, based
    * on the folder's flags. If aAllowSpecialFolderIndexing is true, then
    * folders suchs as Trash and Junk will be indexed.
    *
    * @param {nsIMsgFolder} aFolder
    * @param {boolean} aAllowSpecialFolderIndexing
    * @returns {Number}
    */
-  getDefaultIndexingPriority(aFolder, aAllowSpecialFolderIndexing) {
+  getDefaultIndexingPriority: function gloda_ds_getDefaultIndexingPriority(aFolder, aAllowSpecialFolderIndexing) {
+
     let indexingPriority = GlodaFolder.prototype.kIndexingDefaultPriority;
     // Do not walk into trash/junk folders, unless the user is explicitly
     //  telling us to do so.
     let specialFolderFlags = Ci.nsMsgFolderFlags.Trash | Ci.nsMsgFolderFlags.Junk;
     if (aFolder.isSpecialFolder(specialFolderFlags, true))
       indexingPriority = aAllowSpecialFolderIndexing ?
                            GlodaFolder.prototype.kIndexingDefaultPriority :
                            GlodaFolder.prototype.kIndexingNeverPriority;
@@ -1973,18 +2011,18 @@ var GlodaDatastore = {
     // Other user IMAP folders should be ignored because it's not this user's
     //  mail.
     else if (aFolder.flags & (Ci.nsMsgFolderFlags.Queue
                               | Ci.nsMsgFolderFlags.Newsgroup
                               // In unit testing at least folders can be
                               // confusingly labeled ImapPublic when they
                               // should not be.  Or at least I don't think they
                               // should be.  So they're legit for now.
-                              // | Ci.nsMsgFolderFlags.ImapPublic
-                              // | Ci.nsMsgFolderFlags.ImapOtherUser
+                              //| Ci.nsMsgFolderFlags.ImapPublic
+                              //| Ci.nsMsgFolderFlags.ImapOtherUser
                              ))
       indexingPriority = GlodaFolder.prototype.kIndexingNeverPriority;
     else if (aFolder.flags & Ci.nsMsgFolderFlags.Inbox)
       indexingPriority = GlodaFolder.prototype.kIndexingInboxPriority;
     else if (aFolder.flags & Ci.nsMsgFolderFlags.SentMail)
       indexingPriority = GlodaFolder.prototype.kIndexingSentMailPriority;
     else if (aFolder.flags & Ci.nsMsgFolderFlags.Favorite)
       indexingPriority = GlodaFolder.prototype.kIndexingFavoritePriority;
@@ -1997,17 +2035,17 @@ var GlodaDatastore = {
   /**
    * Map a folder URI to a GlodaFolder instance, creating the mapping if it does
    *  not yet exist.
    *
    * @param aFolder The nsIMsgFolder instance you would like the GlodaFolder
    *     instance for.
    * @returns The existing or newly created GlodaFolder instance.
    */
-  _mapFolder(aFolder) {
+  _mapFolder: function gloda_ds_mapFolderURI(aFolder) {
     let folderURI = aFolder.URI;
     if (folderURI in this._folderByURI) {
       return this._folderByURI[folderURI];
     }
 
     let folderID = this._nextFolderId++;
 
     // if there's an indexingPriority stored on the folder, just use that
@@ -2045,63 +2083,64 @@ var GlodaDatastore = {
   /**
    * Map an integer gloda folder ID to the corresponding GlodaFolder instance.
    *
    * @param aFolderID The known valid gloda folder ID for which you would like
    *     a GlodaFolder instance.
    * @return The GlodaFolder instance with the given id.  If no such instance
    *     exists, we will throw an exception.
    */
-  _mapFolderID(aFolderID) {
+  _mapFolderID: function gloda_ds_mapFolderID(aFolderID) {
     if (aFolderID === null)
       return null;
     if (aFolderID in this._folderByID)
       return this._folderByID[aFolderID];
     throw new Error("Got impossible folder ID: " + aFolderID);
   },
 
   /**
    * Mark the gloda folder as deleted for any outstanding references to it and
    *  remove it from our tables so we don't hand out any new references.  The
    *  latter is especially important in the case a folder with the same name
    *  is created afterwards; we don't want to confuse the new one with the old
    *  one!
    */
-  _killGlodaFolderIntoTombstone(aGlodaFolder) {
+  _killGlodaFolderIntoTombstone:
+      function gloda_ds__killGlodaFolderIntoTombstone(aGlodaFolder) {
     aGlodaFolder._deleted = true;
     delete this._folderByURI[aGlodaFolder.uri];
     delete this._folderByID[aGlodaFolder.id];
   },
 
   get _updateFolderDirtyStatusStatement() {
     let statement = this._createAsyncStatement(
       "UPDATE folderLocations SET dirtyStatus = ?1 \
               WHERE id = ?2");
     this.__defineGetter__("_updateFolderDirtyStatusStatement",
       () => statement);
     return this._updateFolderDirtyStatusStatement;
   },
 
-  updateFolderDirtyStatus(aFolder) {
+  updateFolderDirtyStatus: function gloda_ds_updateFolderDirtyStatus(aFolder) {
     let ufds = this._updateFolderDirtyStatusStatement;
     ufds.bindByIndex(1, aFolder.id);
     ufds.bindByIndex(0, aFolder.dirtyStatus);
     ufds.executeAsync(this.trackAsync());
   },
 
   get _updateFolderIndexingPriorityStatement() {
     let statement = this._createAsyncStatement(
       "UPDATE folderLocations SET indexingPriority = ?1 \
               WHERE id = ?2");
     this.__defineGetter__("_updateFolderIndexingPriorityStatement",
       () => statement);
     return this._updateFolderIndexingPriorityStatement;
   },
 
-  updateFolderIndexingPriority(aFolder) {
+  updateFolderIndexingPriority: function gloda_ds_updateFolderIndexingPriority(aFolder) {
     let ufip = this._updateFolderIndexingPriorityStatement;
     ufip.bindByIndex(1, aFolder.id);
     ufip.bindByIndex(0, aFolder.indexingPriority);
     ufip.executeAsync(this.trackAsync());
   },
 
   get _updateFolderLocationStatement() {
     let statement = this._createAsyncStatement(
@@ -2113,17 +2152,17 @@ var GlodaDatastore = {
   },
 
   /**
    * Non-recursive asynchronous folder renaming based on the URI.
    *
    * @TODO provide a mechanism for recursive folder renames or have a higher
    *     layer deal with it and remove this note.
    */
-  renameFolder(aOldFolder, aNewURI) {
+  renameFolder: function gloda_ds_renameFolder(aOldFolder, aNewURI) {
     if (!(aOldFolder.URI in this._folderByURI))
       return;
     let folder = this._mapFolder(aOldFolder); // ensure the folder is mapped
     let oldURI = folder.uri;
     this._folderByURI[aNewURI] = folder;
     folder._uri = aNewURI;
     this._log.info("renaming folder URI " + oldURI + " to " + aNewURI);
     this._updateFolderLocationStatement.bindByIndex(1, folder.id);
@@ -2136,17 +2175,17 @@ var GlodaDatastore = {
   get _deleteFolderByIDStatement() {
     let statement = this._createAsyncStatement(
       "DELETE FROM folderLocations WHERE id = ?1");
     this.__defineGetter__("_deleteFolderByIDStatement",
       () => statement);
     return this._deleteFolderByIDStatement;
   },
 
-  deleteFolderByID(aFolderID) {
+  deleteFolderByID: function gloda_ds_deleteFolder(aFolderID) {
     let dfbis = this._deleteFolderByIDStatement;
     dfbis.bindByIndex(0, aFolderID);
     dfbis.executeAsync(this.trackAsync());
   },
 
   /**
    * This timer drives our folder cleanup logic that is in charge of dropping
    *  our folder references and more importantly the folder's msgDatabase
@@ -2180,32 +2219,32 @@ var GlodaDatastore = {
 
   /**
    * Mark a GlodaFolder as having a live reference to its nsIMsgFolder with an
    *  implied opened associated message database.  GlodaFolder calls this when
    *  it first acquires its reference.  It is removed from the list of live
    *  folders only when our timer check calls the GlodaFolder's
    *  forgetFolderIfUnused method and that method returns true.
    */
-  markFolderLive(aGlodaFolder) {
+  markFolderLive: function gloda_ds_markFolderLive(aGlodaFolder) {
     this._liveGlodaFolders[aGlodaFolder.id] = aGlodaFolder;
     if (!this._folderCleanupActive) {
       this._folderCleanupTimer.initWithCallback(this._performFolderCleanup,
         this._folderCleanupTimerInterval, Ci.nsITimer.TYPE_REPEATING_SLACK);
       this._folderCleanupActive = true;
     }
   },
 
   /**
    * Timer-driven folder cleanup logic.  For every live folder tracked in
    *  _liveGlodaFolders, we call their forgetFolderIfUnused method each time
    *  until they return true indicating they have cleaned themselves up.
    * This method is called without a 'this' context!
    */
-  _performFolderCleanup() {
+  _performFolderCleanup: function gloda_ds_performFolderCleanup() {
     // we only need to keep going if there is at least one folder in the table
     //  that is still alive after this pass.
     let keepGoing = false;
     for (let id in GlodaDatastore._liveGlodaFolders) {
       let glodaFolder = GlodaDatastore._liveGlodaFolders[id];
       // returns true if it is now 'dead' and doesn't need this heartbeat check
       if (glodaFolder.forgetFolderIfUnused())
         delete GlodaDatastore._liveGlodaFolders[glodaFolder.id];
@@ -2218,17 +2257,17 @@ var GlodaDatastore = {
       GlodaDatastore._folderCleanupActive = false;
     }
   },
 
   /* ********** Conversation ********** */
   /** The next conversation id to allocate.  Initialize at startup. */
   _nextConversationId: 1,
 
-  _populateConversationManagedId() {
+  _populateConversationManagedId: function () {
     let stmt = this._createSyncStatement(
       "SELECT MAX(id) FROM conversations", true);
     if (stmt.executeStep()) { // no chance of this SQLITE_BUSY on this call
       this._nextConversationId = stmt.getInt64(0) + 1;
     }
     stmt.finalize();
   },
 
@@ -2248,17 +2287,19 @@ var GlodaDatastore = {
     this.__defineGetter__("_insertConversationTextStatement",
       () => statement);
     return this._insertConversationTextStatement;
   },
 
   /**
    * Asynchronously create a conversation.
    */
-  createConversation(aSubject, aOldestMessageDate, aNewestMessageDate) {
+  createConversation: function gloda_ds_createConversation(aSubject,
+        aOldestMessageDate, aNewestMessageDate) {
+
     // create the data row
     let conversationID = this._nextConversationId++;
     let ics = this._insertConversationStatement;
     ics.bindByIndex(0, conversationID);
     ics.bindByIndex(1, aSubject);
     if (aOldestMessageDate == null)
       ics.bindByIndex(2, null);
     else
@@ -2291,26 +2332,27 @@ var GlodaDatastore = {
     this.__defineGetter__("_deleteConversationByIDStatement",
                           () => statement);
     return this._deleteConversationByIDStatement;
   },
 
   /**
    * Asynchronously delete a conversation given its ID.
    */
-  deleteConversationByID(aConversationID) {
+  deleteConversationByID: function gloda_ds_deleteConversationByID(
+                                      aConversationID) {
     let dcbids = this._deleteConversationByIDStatement;
     dcbids.bindByIndex(0, aConversationID);
     dcbids.executeAsync(this.trackAsync());
 
     GlodaCollectionManager.itemsDeleted(GlodaConversation.prototype.NOUN_ID,
                                         [aConversationID]);
   },
 
-  _conversationFromRow(aStmt) {
+  _conversationFromRow: function gloda_ds_conversationFromRow(aStmt) {
       let oldestMessageDate, newestMessageDate;
       if (aStmt.getTypeOfIndex(2) == Ci.mozIStorageValueArray.VALUE_TYPE_NULL)
         oldestMessageDate = null;
       else
         oldestMessageDate = aStmt.getInt64(2);
       if (aStmt.getTypeOfIndex(3) == Ci.mozIStorageValueArray.VALUE_TYPE_NULL)
         newestMessageDate = null;
       else
@@ -2324,17 +2366,17 @@ var GlodaDatastore = {
    * Next message id, managed because of our use of asynchronous inserts.
    * Initialized by _populateMessageManagedId called by _init.
    *
    * Start from 32 to leave us all kinds of magical sentinel values at the
    *  bottom.
    */
   _nextMessageId: 32,
 
-  _populateMessageManagedId() {
+  _populateMessageManagedId: function () {
     let stmt = this._createSyncStatement(
       "SELECT MAX(id) FROM messages", true);
     if (stmt.executeStep()) { // no chance of this SQLITE_BUSY on this call
       // 0 gets returned even if there are no messages...
       let highestSeen = stmt.getInt64(0);
       if (highestSeen != 0)
         this._nextMessageId = highestSeen + 1;
     }
@@ -2364,21 +2406,23 @@ var GlodaDatastore = {
    *  of the process of creating a message (the attributes still need to be
    *  completed), it's on the caller's head to call GlodaCollectionManager's
    *  itemAdded method once the message is fully created.
    *
    * This method uses the async connection, any downstream logic that depends on
    *  this message actually existing in the database must be done using an
    *  async query.
    */
-  createMessage(aFolder, aMessageKey, aConversationID, aDatePRTime, aHeaderMessageID) {
+  createMessage: function gloda_ds_createMessage(aFolder, aMessageKey,
+                              aConversationID, aDatePRTime, aHeaderMessageID) {
     let folderID;
     if (aFolder != null) {
       folderID = this._mapFolder(aFolder).id;
-    } else {
+    }
+    else {
       folderID = null;
     }
 
     let messageID = this._nextMessageId++;
 
     let message = new GlodaMessage(
       this, messageID, folderID,
       aMessageKey,
@@ -2390,17 +2434,17 @@ var GlodaDatastore = {
     // We would love to notify the collection manager about the message at this
     //  point (at least if it's not a ghost), but we can't yet.  We need to wait
     //  until the attributes have been indexed, which means it's out of our
     //  hands.  (Gloda.processMessage does it.)
 
     return message;
   },
 
-  insertMessage(aMessage) {
+  insertMessage: function gloda_ds_insertMessage(aMessage) {
     let ims = this._insertMessageStatement;
     ims.bindByIndex(0, aMessage.id);
     if (aMessage.folderID == null)
       ims.bindByIndex(1, null);
     else
       ims.bindByIndex(1, aMessage.folderID);
     if (aMessage.messageKey == null)
       ims.bindByIndex(2, null);
@@ -2415,33 +2459,34 @@ var GlodaDatastore = {
     if (aMessage._jsonText)
       ims.bindByIndex(6, aMessage._jsonText);
     else
       ims.bindByIndex(6, null);
     ims.bindByIndex(7, aMessage.notability);
 
     try {
        ims.executeAsync(this.trackAsync());
-    } catch (ex) {
+    }
+    catch(ex) {
        throw new Error("error executing statement... " +
              this.asyncConnection.lastError + ": " +
              this.asyncConnection.lastErrorString + " - " + ex);
     }
 
     // we create the full-text row for any message that isn't a ghost,
     // whether we have the body or not
     if (aMessage.folderID !== null)
       this._insertMessageText(aMessage);
   },
 
   /**
    * Inserts a full-text row. This should only be called if you're sure you want
    * to insert a row into the table.
    */
-  _insertMessageText(aMessage) {
+  _insertMessageText: function gloda_ds__insertMessageText(aMessage) {
     if (aMessage._content && aMessage._content.hasContent())
       aMessage._indexedBodyText = aMessage._content.getContentString(true);
     else if (aMessage._bodyLines)
       aMessage._indexedBodyText = aMessage._bodyLines.join("\n");
     else
       aMessage._indexedBodyText = null;
 
     let imts = this._insertMessageTextStatement;
@@ -2451,24 +2496,25 @@ var GlodaDatastore = {
       imts.bindByIndex(2, null);
     else
       imts.bindByIndex(2, aMessage._indexedBodyText);
     if (aMessage._attachmentNames === null)
       imts.bindByIndex(3, null);
     else
       imts.bindByIndex(3, aMessage._attachmentNames.join("\n"));
 
-    // if (aMessage._indexAuthor)
+//if (aMessage._indexAuthor)
     imts.bindByIndex(4, aMessage._indexAuthor);
-    // if (aMessage._indexRecipients)
+//if (aMessage._indexRecipients)
     imts.bindByIndex(5, aMessage._indexRecipients);
 
     try {
       imts.executeAsync(this.trackAsync());
-    } catch (ex) {
+    }
+    catch(ex) {
       throw new Error("error executing fulltext statement... " +
             this.asyncConnection.lastError + ": " +
             this.asyncConnection.lastErrorString + " - " + ex);
     }
   },
 
   get _updateMessageStatement() {
     let statement = this._createAsyncStatement(
@@ -2499,17 +2545,17 @@ var GlodaDatastore = {
    * Update the database row associated with the message. If the message is
    * not a ghost and has _isNew defined, messagesText is affected.
    *
    * aMessage._isNew is currently equivalent to the fact that there is no
    * full-text row associated with this message, and we work with this
    * assumption here. Note that if aMessage._isNew is not defined, then
    * we don't do anything.
    */
-  updateMessage(aMessage) {
+  updateMessage: function gloda_ds_updateMessage(aMessage) {
     let ums = this._updateMessageStatement;
     ums.bindByIndex(8, aMessage.id);
     if (aMessage.folderID === null)
       ums.bindByIndex(0, null);
     else
       ums.bindByIndex(0, aMessage.folderID);
     if (aMessage.messageKey === null)
       ums.bindByIndex(1, null);
@@ -2538,17 +2584,17 @@ var GlodaDatastore = {
     }
   },
 
   /**
    * Updates the full-text row associated with this message. This only performs
    * the UPDATE query if the indexed body text has changed, which means that if
    * the body hasn't changed but the attachments have, we don't update.
    */
-  _updateMessageText(aMessage) {
+  _updateMessageText: function gloda_ds__updateMessageText(aMessage) {
     let newIndexedBodyText;
     if (aMessage._content && aMessage._content.hasContent())
       newIndexedBodyText = aMessage._content.getContentString(true);
     else if (aMessage._bodyLines)
       newIndexedBodyText = aMessage._bodyLines.join("\n");
     else
       newIndexedBodyText = null;
 
@@ -2569,17 +2615,18 @@ var GlodaDatastore = {
 
     if (aMessage._attachmentNames == null)
       umts.bindByIndex(1, null);
     else
       umts.bindByIndex(1, aMessage._attachmentNames.join("\n"));
 
     try {
       umts.executeAsync(this.trackAsync());
-    } catch (ex) {
+    }
+    catch(ex) {
       throw new Error("error executing fulltext statement... " +
             this.asyncConnection.lastError + ": " +
             this.asyncConnection.lastErrorString + " - " + ex);
     }
   },
 
   get _updateMessageLocationStatement() {
     let statement = this._createAsyncStatement(
@@ -2589,17 +2636,18 @@ var GlodaDatastore = {
     return this._updateMessageLocationStatement;
   },
 
   /**
    * Given a list of gloda message ids, and a list of their new message keys in
    *  the given new folder location, asynchronously update the message's
    *  database locations.  Also, update the in-memory representations.
    */
-  updateMessageLocations(aMessageIds, aNewMessageKeys, aDestFolder, aDoNotNotify) {
+  updateMessageLocations: function gloda_ds_updateMessageLocations(aMessageIds,
+      aNewMessageKeys, aDestFolder, aDoNotNotify) {
     let statement = this._updateMessageLocationStatement;
     let destFolderID = (typeof(aDestFolder) == "number") ? aDestFolder :
                          this._mapFolder(aDestFolder).id;
 
     // map gloda id to the new message key for in-memory rep transform below
     let cacheLookupMap = {};
 
     for (let iMsg = 0; iMsg < aMessageIds.length; iMsg++) {
@@ -2644,17 +2692,17 @@ var GlodaDatastore = {
 
   /**
    * Update the message keys for the gloda messages with the given id's.  This
    *  is to be used in response to msgKeyChanged notifications and is similar to
    *  `updateMessageLocations` except that we do not update the folder and we
    *  do not perform itemsModified notifications (because message keys are not
    *  intended to be relevant to the gloda message abstraction).
    */
-  updateMessageKeys(aMessageIds, aNewMessageKeys) {
+  updateMessageKeys: function(aMessageIds, aNewMessageKeys) {
     let statement = this._updateMessageKeyStatement;
 
     // map gloda id to the new message key for in-memory rep transform below
     let cacheLookupMap = {};
 
     for (let iMsg = 0; iMsg < aMessageIds.length; iMsg++) {
       let id = aMessageIds[iMsg], msgKey = aNewMessageKeys[iMsg];
       statement.bindByIndex(0, msgKey);
@@ -2678,17 +2726,19 @@ var GlodaDatastore = {
 
   /**
    * Asynchronously mutate message folder id/message keys for the given
    *  messages, indicating that we are moving them to the target folder, but
    *  don't yet know their target message keys.
    *
    * Updates in-memory representations too.
    */
-  updateMessageFoldersByKeyPurging(aGlodaIds, aDestFolder) {
+  updateMessageFoldersByKeyPurging:
+      function gloda_ds_updateMessageFoldersByKeyPurging(aGlodaIds,
+                                                         aDestFolder) {
     let destFolderID = this._mapFolder(aDestFolder).id;
 
     let sqlStr = "UPDATE messages SET folderID = ?1, \
                                       messageKey = ?2 \
                    WHERE id IN (" + aGlodaIds.join(", ") + ")";
     let statement = this._createAsyncStatement(sqlStr, true);
     statement.bindByIndex(0, destFolderID);
     statement.bindByIndex(1, null);
@@ -2700,17 +2750,17 @@ var GlodaDatastore = {
                                                  aGlodaIds);
     for (let id in cached) {
       let glodaMsg = cached[id];
       glodaMsg._folderID = destFolderID;
       glodaMsg._messageKey = null;
     }
   },
 
-  _messageFromRow(aRow) {
+  _messageFromRow: function gloda_ds_messageFromRow(aRow) {
     let folderId, messageKey, date, jsonText, subject, indexedBodyText,
         attachmentNames;
     if (aRow.getTypeOfIndex(1) == Ci.mozIStorageValueArray.VALUE_TYPE_NULL)
       folderId = null;
     else
       folderId = aRow.getInt64(1);
     if (aRow.getTypeOfIndex(2) == Ci.mozIStorageValueArray.VALUE_TYPE_NULL)
       messageKey = null;
@@ -2729,19 +2779,19 @@ var GlodaDatastore = {
       if (aRow.getTypeOfIndex(10) == Ci.mozIStorageValueArray.VALUE_TYPE_NULL)
         subject = undefined;
       else
         subject = aRow.getString(10);
       if (aRow.getTypeOfIndex(9) == Ci.mozIStorageValueArray.VALUE_TYPE_NULL)
         indexedBodyText = undefined;
       else
         indexedBodyText = aRow.getString(9);
-      if (aRow.getTypeOfIndex(11) == Ci.mozIStorageValueArray.VALUE_TYPE_NULL) {
+      if (aRow.getTypeOfIndex(11) == Ci.mozIStorageValueArray.VALUE_TYPE_NULL)
         attachmentNames = null;
-      } else {
+      else {
         attachmentNames = aRow.getString(11);
         if (attachmentNames)
           attachmentNames = attachmentNames.split("\n");
         else
           attachmentNames = null;
       }
       // we ignore 12, author
       // we ignore 13, recipients
@@ -2768,34 +2818,36 @@ var GlodaDatastore = {
    *  we obviously do not know the id's of the messages affected by this which
    *  complicates in-memory updates.  The options are sending out to the SQL
    *  database for a list of the message id's or some form of in-memory
    *  traversal.  I/O costs being what they are, users having a propensity to
    *  have folders with tens of thousands of messages, and the unlikeliness
    *  of all of those messages being gloda-memory-resident, we go with the
    *  in-memory traversal.
    */
-  markMessagesDeletedByFolderID(aFolderID) {
+  markMessagesDeletedByFolderID:
+      function gloda_ds_markMessagesDeletedByFolderID(aFolderID) {
     let statement = this._updateMessagesMarkDeletedByFolderID;
     statement.bindByIndex(0, aFolderID);
     statement.executeAsync(this.trackAsync());
 
     // Have the collection manager generate itemsRemoved events for any
     //  in-memory messages in that folder.
     GlodaCollectionManager.itemsDeletedByAttribute(
       GlodaMessage.prototype.NOUN_ID,
       aMsg => aMsg._folderID == aFolderID);
   },
 
   /**
    * Mark all the gloda messages as deleted blind-fire.  Check if any of the
    *  messages are known to the collection manager and update them to be deleted
    *  along with the requisite collection notifications.
    */
-  markMessagesDeletedByIDs(aMessageIDs) {
+  markMessagesDeletedByIDs: function gloda_ds_markMessagesDeletedByIDs(
+      aMessageIDs) {
     // When marking deleted clear the folderID and messageKey so that the
     //  indexing process can reuse it without any location constraints.
     let sqlString = "UPDATE messages SET folderID = NULL, messageKey = NULL, " +
                      "deleted = 1 WHERE id IN (" +
                      aMessageIDs.join(",") + ")";
 
     let statement = this._createAsyncStatement(sqlString, true);
     statement.executeAsync(this.trackAsync());
@@ -2811,17 +2863,17 @@ var GlodaDatastore = {
     this.__defineGetter__("_countDeletedMessagesStatement",
                           () => statement);
     return this._countDeletedMessagesStatement;
   },
 
   /**
    * Count how many messages are currently marked as deleted in the database.
    */
-  countDeletedMessages(aCallback) {
+  countDeletedMessages: function gloda_ds_countDeletedMessages(aCallback) {
     let cms = this._countDeletedMessagesStatement;
     cms.executeAsync(new SingletonResultValueHandler(aCallback));
   },
 
   get _deleteMessageByIDStatement() {
     let statement = this._createAsyncStatement(
       "DELETE FROM messages WHERE id = ?1");
     this.__defineGetter__("_deleteMessageByIDStatement",
@@ -2837,41 +2889,43 @@ var GlodaDatastore = {
     return this._deleteMessageTextByIDStatement;
   },
 
   /**
    * Delete a message and its fulltext from the database.  It is assumed that
    *  the message was already marked as deleted and so is not visible to the
    *  collection manager and so nothing needs to be done about that.
    */
-  deleteMessageByID(aMessageID) {
+  deleteMessageByID: function gloda_ds_deleteMessageByID(aMessageID) {
     let dmbids = this._deleteMessageByIDStatement;
     dmbids.bindByIndex(0, aMessageID);
     dmbids.executeAsync(this.trackAsync());
 
     this.deleteMessageTextByID(aMessageID);
   },
 
-  deleteMessageTextByID(aMessageID) {
+  deleteMessageTextByID: function gloda_ds_deleteMessageTextByID(aMessageID) {
     let dmt = this._deleteMessageTextByIDStatement;
     dmt.bindByIndex(0, aMessageID);
     dmt.executeAsync(this.trackAsync());
   },
 
   get _folderCompactionStatement() {
     let statement = this._createAsyncStatement(
       "SELECT id, messageKey, headerMessageID FROM messages \
         WHERE folderID = ?1 AND \
           messageKey >= ?2 AND +deleted = 0 ORDER BY messageKey LIMIT ?3");
     this.__defineGetter__("_folderCompactionStatement",
                           () => statement);
     return this._folderCompactionStatement;
   },
 
-  folderCompactionPassBlockFetch(aFolderID, aStartingMessageKey, aLimit, aCallback) {
+  folderCompactionPassBlockFetch:
+      function gloda_ds_folderCompactionPassBlockFetch(
+        aFolderID, aStartingMessageKey, aLimit, aCallback) {
     let fcs = this._folderCompactionStatement;
     fcs.bindByIndex(0, aFolderID);
     fcs.bindByIndex(1, aStartingMessageKey);
     fcs.bindByIndex(2, aLimit);
     fcs.executeAsync(new CompactionBlockFetcherHandler(aCallback));
   },
 
   /* ********** Message Attributes ********** */
@@ -2909,17 +2963,18 @@ var GlodaDatastore = {
    * @param aAddDBAttributes A list of attribute tuples to add, where each tuple
    *     contains an attribute ID and a value.  Lest you forget, an attribute ID
    *     corresponds to a row in the attribute definition table.  The attribute
    *     definition table stores the 'parameter' for the attribute, if any.
    *     (Which is to say, our frequent Attribute-Parameter-Value triple has
    *     the Attribute-Parameter part distilled to a single attribute id.)
    * @param aRemoveDBAttributes A list of attribute tuples to remove.
    */
-  adjustMessageAttributes(aMessage, aAddDBAttributes, aRemoveDBAttributes) {
+  adjustMessageAttributes: function gloda_ds_adjustMessageAttributes(aMessage,
+                                        aAddDBAttributes, aRemoveDBAttributes) {
     let imas = this._insertMessageAttributeStatement;
     let dmas = this._deleteMessageAttributeStatement;
     this._beginTransaction();
     try {
       for (let iAttrib = 0; iAttrib < aAddDBAttributes.length; iAttrib++) {
         let attribValueTuple = aAddDBAttributes[iAttrib];
 
         imas.bindByIndex(0, aMessage.conversationID);
@@ -2949,17 +3004,18 @@ var GlodaDatastore = {
         else
           dmas.bindByIndex(1, attribValueTuple[1]);
         dmas.bindByIndex(2, aMessage.conversationID);
         dmas.bindByIndex(3, aMessage.id);
         dmas.executeAsync(this.trackAsync());
       }
 
       this._commitTransaction();
-    } catch (ex) {
+    }
+    catch (ex) {
       this._log.error("adjustMessageAttributes:", ex);
       this._rollbackTransaction();
       throw ex;
     }
   },
 
   get _deleteMessageAttributesByMessageIDStatement() {
     let statement = this._createAsyncStatement(
@@ -2972,34 +3028,35 @@ var GlodaDatastore = {
   /**
    * Clear all the message attributes for a given GlodaMessage.  No changes
    *  are made to the in-memory representation of the message; it is up to the
    *  caller to ensure that it handles things correctly.
    *
    * @param aMessage The GlodaMessage whose database attributes should be
    *     purged.
    */
-  clearMessageAttributes(aMessage) {
+  clearMessageAttributes: function gloda_ds_clearMessageAttributes(aMessage) {
     if (aMessage.id != null) {
       this._deleteMessageAttributesByMessageIDStatement.bindByIndex(0,
         aMessage.id);
       this._deleteMessageAttributesByMessageIDStatement.executeAsync(
         this.trackAsync());
     }
   },
 
-  _stringSQLQuoter(aString) {
+  _stringSQLQuoter: function(aString) {
     return "'" + aString.replace(/\'/g, "''") + "'";
   },
-  _numberQuoter(aNum) {
+  _numberQuoter: function(aNum) {
     return aNum;
   },
 
   /* ===== Generic Attribute Support ===== */
-  adjustAttributes(aItem, aAddDBAttributes, aRemoveDBAttributes) {
+  adjustAttributes: function gloda_ds_adjustAttributes(aItem, aAddDBAttributes,
+      aRemoveDBAttributes) {
     let nounDef = aItem.NOUN_DEF;
     let dbMeta = nounDef._dbMeta;
     if (dbMeta.insertAttrStatement === undefined) {
       dbMeta.insertAttrStatement = this._createAsyncStatement(
         "INSERT INTO " + nounDef.attrTableName +
         " (" + nounDef.attrIDColumnName + ", attributeID, value) " +
         " VALUES (?1, ?2, ?3)");
       // we always create this at the same time (right here), no need to check
@@ -3041,26 +3098,27 @@ var GlodaDatastore = {
           das.bindByIndex(1, attribValueTuple[1]);
         else
           das.bindByIndex(1, attribValueTuple[1]);
         das.bindByIndex(2, aItem.id);
         das.executeAsync(this.trackAsync());
       }
 
       this._commitTransaction();
-    } catch (ex) {
+    }
+    catch (ex) {
       this._log.error("adjustAttributes:", ex);
       this._rollbackTransaction();
       throw ex;
     }
   },
 
-  clearAttributes(aItem) {
+  clearAttributes: function gloda_ds_clearAttributes(aItem) {
     let nounDef = aItem.NOUN_DEF;
-    let dbMeta = nounDef._dbMeta;
+    let dbMeta = nounMeta._dbMeta;
     if (dbMeta.clearAttrStatement === undefined) {
       dbMeta.clearAttrStatement = this._createAsyncStatement(
         "DELETE FROM " + nounDef.attrTableName + " WHERE " +
         nounDef.attrIDColumnName + " = ?1");
     }
 
     if (aItem.id != null) {
       dbMeta.clearAttrstatement.bindByIndex(0, aItem.id);
@@ -3074,17 +3132,19 @@ var GlodaDatastore = {
    *  for this reason.
    */
   get _escapeLikeStatement() {
     let statement = this._createAsyncStatement("SELECT 0");
     this.__defineGetter__("_escapeLikeStatement", () => statement);
     return this._escapeLikeStatement;
   },
 
-  * _convertToDBValuesAndGroupByAttributeID(aAttrDef, aValues) {
+  _convertToDBValuesAndGroupByAttributeID:
+    function* gloda_ds__convertToDBValuesAndGroupByAttributeID(aAttrDef,
+                                                               aValues) {
     let objectNounDef = aAttrDef.objectNounDef;
     if (!objectNounDef.usesParameter) {
       let dbValues = [];
       for (let iValue = 0; iValue < aValues.length; iValue++) {
         let value = aValues[iValue];
         // If the empty set is significant and it's an empty signifier, emit
         //  the appropriate dbvalue.
         if (value == null && aAttrDef.emptySetIsSignificant) {
@@ -3120,34 +3180,38 @@ var GlodaDatastore = {
       let [dbParam, dbValue] = objectNounDef.toParamAndValue(value);
       if (curParam === undefined) {
         curParam = dbParam;
         attrID = attrDBDef.bindParameter(curParam);
         if (dbValue != null)
           dbValues = [dbValue];
         else
           dbValues = [];
-      } else if (curParam == dbParam) {
+      }
+      else if (curParam == dbParam) {
         if (dbValue != null)
           dbValues.push(dbValue);
-      } else {
+      }
+      else {
         yield [attrID, dbValues];
         curParam = dbParam;
         attrID = attrDBDef.bindParameter(curParam);
         if (dbValue != null)
           dbValues = [dbValue];
         else
           dbValues = [];
       }
     }
     if (dbValues !== undefined)
       yield [attrID, dbValues];
   },
 
-  * _convertRangesToDBStringsAndGroupByAttributeID(aAttrDef, aValues, aValueColumnName) {
+  _convertRangesToDBStringsAndGroupByAttributeID:
+    function* gloda_ds__convertRangesToDBStringsAndGroupByAttributeID(aAttrDef,
+      aValues, aValueColumnName) {
     let objectNounDef = aAttrDef.objectNounDef;
     if (!objectNounDef.usesParameter) {
       let dbStrings = [];
       for (let iValue = 0; iValue < aValues.length; iValue++) {
         let [lowerVal, upperVal] = aValues[iValue];
         // they both can't be null.  that is the law.
         if (lowerVal == null)
           dbStrings.push(aValueColumnName + " <= " +
@@ -3169,55 +3233,59 @@ var GlodaDatastore = {
     for (let iValue = 0; iValue < aValues.length; iValue++) {
       let [lowerVal, upperVal] = aValues[iValue];
 
       let dbString, dbParam, lowerDBVal, upperDBVal;
       // they both can't be null.  that is the law.
       if (lowerVal == null) {
         [dbParam, upperDBVal] = objectNounDef.toParamAndValue(upperVal);
         dbString = aValueColumnName + " <= " + upperDBVal;
-      } else if (upperVal == null) {
+      }
+      else if (upperVal == null) {
         [dbParam, lowerDBVal] = objectNounDef.toParamAndValue(lowerVal);
         dbString = aValueColumnName + " >= " + lowerDBVal;
-      } else { // no one is null!
+      }
+      else { // no one is null!
         [dbParam, lowerDBVal] = objectNounDef.toParamAndValue(lowerVal);
         dbString = aValueColumnName + " BETWEEN " + lowerDBVal + " AND " +
                    objectNounDef.toParamAndValue(upperVal)[1];
       }
 
       if (curParam === undefined) {
         curParam = dbParam;
         attrID = attrDBDef.bindParameter(curParam);
         dbStrings = [dbString];
-      } else if (curParam === dbParam) {
+      }
+      else if (curParam === dbParam) {
         dbStrings.push(dbString);
-      } else {
+      }
+      else {
         yield [attrID, dbStrings];
         curParam = dbParam;
         attrID = attrDBDef.bindParameter(curParam);
         dbStrings = [dbString];
       }
     }
     if (dbStrings !== undefined)
       yield [attrID, dbStrings];
   },
 
-  /* eslint-disable complexity */
   /**
    * Perform a database query given a GlodaQueryClass instance that specifies
    *  a set of constraints relating to the noun type associated with the query.
    *  A GlodaCollection is returned containing the results of the look-up.
    *  By default the collection is "live", and will mutate (generating events to
    *  its listener) as the state of the database changes.
    * This functionality is made user/extension visible by the Query's
    *  getCollection (asynchronous).
    *
    * @param [aArgs] See |GlodaQuery.getCollection| for info.
    */
-  queryFromQuery(aQuery, aListener, aListenerData, aExistingCollection, aMasterCollection, aArgs) {
+  queryFromQuery: function gloda_ds_queryFromQuery(aQuery, aListener,
+      aListenerData, aExistingCollection, aMasterCollection, aArgs) {
     // when changing this method, be sure that GlodaQuery's testMatch function
     //  likewise has its changes made.
     let nounDef = aQuery._nounDef;
 
     let whereClauses = [];
     let unionQueries = [aQuery].concat(aQuery._unions);
     let boundArgs = [];
 
@@ -3241,42 +3309,45 @@ var GlodaDatastore = {
       let curConstraintIsSpecial;
 
       for (let iConstraint = 0; iConstraint < curQuery._constraints.length;
            iConstraint++) {
         let constraint = curQuery._constraints[iConstraint];
         let [constraintType, attrDef] = constraint;
         let constraintValues = constraint.slice(2);
 
-        let tableName, idColumnName, valueColumnName;
+        let tableName, idColumnName, tableColumnName, valueColumnName;
         if (constraintType == this.kConstraintIdIn) {
           // we don't need any of the next cases' setup code, and we especially
           //  would prefer that attrDef isn't accessed since it's null for us.
-        } else if (attrDef.special) {
+        }
+        else if (attrDef.special) {
           tableName = nounDef.tableName;
           idColumnName = "id"; // canonical id for a table is "id".
           valueColumnName = attrDef.specialColumnName;
           curConstraintIsSpecial = true;
-        } else {
+        }
+        else {
           tableName = nounDef.attrTableName;
           idColumnName = nounDef.attrIDColumnName;
           valueColumnName = "value";
           curConstraintIsSpecial = false;
         }
 
-        let select = null, test = null;
+        let select = null, test = null, bindArgs = null;
         if (constraintType === this.kConstraintIdIn) {
           // this is somewhat of a trick.  this does mean that this can be the
           //  only constraint.  Namely, our idiom is:
           // SELECT * FROM blah WHERE id IN (a INTERSECT b INTERSECT c)
           //  but if we only have 'a', then that becomes "...IN (a)", and if
           //  'a' is not a select but a list of id's... tricky, no?
           select = constraintValues.join(",");
-        } else if (constraintType === this.kConstraintIn) {
-          // @testpoint gloda.datastore.sqlgen.kConstraintIn
+        }
+        // @testpoint gloda.datastore.sqlgen.kConstraintIn
+        else if (constraintType === this.kConstraintIn) {
           let clauses = [];
           for (let [attrID, values] of
               this._convertToDBValuesAndGroupByAttributeID(attrDef,
                                                            constraintValues)) {
             let clausePart;
             if (attrID !== undefined)
               clausePart = "(attributeID = " + attrID +
                 (values.length ? " AND " : "");
@@ -3290,83 +3361,88 @@ var GlodaDatastore = {
               if (("special" in attrDef) && (attrDef.special == this.kSpecialString)) {
                 clausePart += valueColumnName + " IN (" +
                   values.map(v => "'" + v.replace(/\'/g, "''") + "'").
                   join(",") + "))";
               } else {
                 clausePart += valueColumnName + " IN (" + values.join(",") +
                               "))";
               }
-            } else {
+            }
+            else
               clausePart += ")";
-            }
             clauses.push(clausePart);
           }
           test = clauses.join(" OR ");
-        } else if (constraintType === this.kConstraintRanges) {
-          // @testpoint gloda.datastore.sqlgen.kConstraintRanges
+        }
+        // @testpoint gloda.datastore.sqlgen.kConstraintRanges
+        else if (constraintType === this.kConstraintRanges) {
           let clauses = [];
           for (let [attrID, dbStrings] of
               this._convertRangesToDBStringsAndGroupByAttributeID(attrDef,
                               constraintValues, valueColumnName)) {
             if (attrID !== undefined)
               clauses.push("(attributeID = " + attrID +
                            " AND (" + dbStrings.join(" OR ") + "))");
             else
               clauses.push("(" + dbStrings.join(" OR ") + ")");
           }
           test = clauses.join(" OR ");
-        } else if (constraintType === this.kConstraintEquals) {
-          // @testpoint gloda.datastore.sqlgen.kConstraintEquals
+        }
+        // @testpoint gloda.datastore.sqlgen.kConstraintEquals
+        else if (constraintType === this.kConstraintEquals) {
           let clauses = [];
           for (let [attrID, values] of
               this._convertToDBValuesAndGroupByAttributeID(attrDef,
                                                            constraintValues)) {
             if (attrID !== undefined)
               clauses.push("(attributeID = " + attrID +
                   " AND (" + values.map(_ => valueColumnName + " = ?").
                   join(" OR ") + "))");
             else
               clauses.push("(" + values.map(_ => valueColumnName + " = ?").
                            join(" OR ") + ")");
             boundArgs.push.apply(boundArgs, values);
           }
           test = clauses.join(" OR ");
-        } else if (constraintType === this.kConstraintStringLike) {
-          // @testpoint gloda.datastore.sqlgen.kConstraintStringLike
-          let likePayload = "";
+        }
+        // @testpoint gloda.datastore.sqlgen.kConstraintStringLike
+        else if (constraintType === this.kConstraintStringLike) {
+          let likePayload = '';
           for (let valuePart of constraintValues) {
             if (typeof valuePart == "string")
               likePayload += this._escapeLikeStatement.escapeStringForLIKE(
                 valuePart, "/");
             else
               likePayload += "%";
           }
           test = valueColumnName + " LIKE ? ESCAPE '/'";
           boundArgs.push(likePayload);
-        } else if (constraintType === this.kConstraintFulltext) {
-          // @testpoint gloda.datastore.sqlgen.kConstraintFulltext
+        }
+        // @testpoint gloda.datastore.sqlgen.kConstraintFulltext
+        else if (constraintType === this.kConstraintFulltext) {
           let matchStr = constraintValues[0];
           select = "SELECT docid FROM " + nounDef.tableName + "Text" +
             " WHERE " + attrDef.specialColumnName + " MATCH ?";
           boundArgs.push(matchStr);
         }
 
         if (curConstraintIsSpecial && lastConstraintWasSpecial && test) {
-          selects[selects.length - 1] += " AND " + test;
-        } else if (select) {
+          selects[selects.length-1] += " AND " + test;
+        }
+        else if (select)
           selects.push(select);
-        } else if (test) {
+        else if (test) {
           select = "SELECT " + idColumnName + " FROM " + tableName + " WHERE " +
               test;
           selects.push(select);
-        } else {
+        }
+        else
           this._log.warn("Unable to translate constraint of type " +
             constraintType + " on attribute bound as " + nounDef.name);
-        }
 
         lastConstraintWasSpecial = curConstraintIsSpecial;
       }
 
       if (selects.length)
         whereClauses.push("id IN (" + selects.join(" INTERSECT ") + ")" +
                           validityConstraintSuffix);
     }
@@ -3420,30 +3496,29 @@ var GlodaDatastore = {
     if (aArgs && ("becomeExplicit" in aArgs) && aArgs.becomeExplicit)
       aQuery = new nounDef.explicitQueryClass();
     else if (aArgs && ("becomeNull" in aArgs) && aArgs.becomeNull)
       aQuery = new nounDef.nullQueryClass();
 
     return this._queryFromSQLString(sqlString, boundArgs, nounDef, aQuery,
         aListener, aListenerData, aExistingCollection, aMasterCollection);
   },
-  /* eslint-enable complexity */
-
-  _queryFromSQLString(aSqlString,
+
+  _queryFromSQLString: function gloda_ds__queryFromSQLString(aSqlString,
       aBoundArgs, aNounDef, aQuery, aListener, aListenerData,
       aExistingCollection, aMasterCollection) {
     let statement = this._createAsyncStatement(aSqlString, true);
     for (let [iBinding, bindingValue] of aBoundArgs.entries()) {
       this._bindVariant(statement, iBinding, bindingValue);
     }
 
     let collection;
-    if (aExistingCollection) {
+    if (aExistingCollection)
       collection = aExistingCollection;
-    } else {
+    else {
       collection = new GlodaCollection(aNounDef, [], aQuery, aListener,
                                        aMasterCollection);
       GlodaCollectionManager.registerCollection(collection);
       // we don't want to overwrite the existing listener or its data, but this
       //  does raise the question about what should happen if we get passed in
       //  a different listener and/or data.
       if (aListenerData !== undefined)
         collection.data = aListenerData;
@@ -3456,72 +3531,78 @@ var GlodaDatastore = {
     }
 
     statement.executeAsync(new QueryFromQueryCallback(statement, aNounDef,
       collection));
     statement.finalize();
     return collection;
   },
 
-  /* eslint-disable complexity */
-  loadNounItem(aItem, aReferencesByNounID, aInverseReferencesByNounID) {
+  /**
+   *
+   *
+   */
+  loadNounItem: function gloda_ds_loadNounItem(aItem, aReferencesByNounID,
+      aInverseReferencesByNounID) {
     let attribIDToDBDefAndParam = this._attributeIDToDBDefAndParam;
 
     let hadDeps = aItem._deps != null;
     let deps = aItem._deps || {};
     let hasDeps = false;
 
-    // this._log.debug("  hadDeps: " + hadDeps + " deps: " +
+    //this._log.debug("  hadDeps: " + hadDeps + " deps: " +
     //    Log4Moz.enumerateProperties(deps).join(","));
 
     for (let attrib of aItem.NOUN_DEF.specialLoadAttribs) {
       let objectNounDef = attrib.objectNounDef;
 
       if (("special" in attrib) && (attrib.special === this.kSpecialColumnChildren)) {
         let invReferences = aInverseReferencesByNounID[objectNounDef.id];
         if (invReferences === undefined)
           invReferences = aInverseReferencesByNounID[objectNounDef.id] = {};
         // only contribute if it's not already pending or there
-        if (!(attrib.id in deps) && aItem[attrib.storageAttributeName] == null) {
-          // this._log.debug("   Adding inv ref for: " + aItem.id);
+        if (!(attrib.id in deps) && aItem[attrib.storageAttributeName] == null){
+          //this._log.debug("   Adding inv ref for: " + aItem.id);
           if (!(aItem.id in invReferences))
             invReferences[aItem.id] = null;
           deps[attrib.id] = null;
           hasDeps = true;
         }
-      } else if (("special" in attrib) && (attrib.special === this.kSpecialColumnParent)) {
+      }
+      else if (("special" in attrib) && (attrib.special === this.kSpecialColumnParent)) {
         let references = aReferencesByNounID[objectNounDef.id];
         if (references === undefined)
           references = aReferencesByNounID[objectNounDef.id] = {};
         // nothing to contribute if it's already there
         if (!(attrib.id in deps) &&
             aItem[attrib.valueStorageAttributeName] == null) {
           let parentID = aItem[attrib.idStorageAttributeName];
           if (!(parentID in references))
             references[parentID] = null;
-          // this._log.debug("   Adding parent ref for: " +
+          //this._log.debug("   Adding parent ref for: " +
           //  aItem[attrib.idStorageAttributeName]);
           deps[attrib.id] = null;
           hasDeps = true;
-        } else {
+        }
+        else {
           this._log.debug("  paranoia value storage: " + aItem[attrib.valueStorageAttributeName]);
         }
       }
     }
 
     // bail here if arbitrary values are not allowed, there just is no
     //  encoded json, or we already had dependencies for this guy, implying
     //  the json pass has already been performed
     if (!aItem.NOUN_DEF.allowsArbitraryAttrs || !aItem._jsonText || hadDeps) {
       if (hasDeps)
         aItem._deps = deps;
       return hasDeps;
     }
 
-    // this._log.debug(" load json: " + aItem._jsonText);
+    //this._log.debug(" load json: " + aItem._jsonText);
     let jsonDict = JSON.parse(aItem._jsonText);
     delete aItem._jsonText;
 
     // Iterate over the attributes on the item
     for (let attribId in jsonDict) {
       let jsonValue = jsonDict[attribId];
       // It is technically impossible for attribute ids to go away at this
       //  point in time.  This would require someone to monkey around with
@@ -3552,146 +3633,155 @@ var GlodaDatastore = {
       if (objectNounDef.tableName && !objectNounDef.fromJSON) {
         let references = aReferencesByNounID[objectNounDef.id];
         if (references === undefined)
           references = aReferencesByNounID[objectNounDef.id] = {};
 
         if (attrib.singular) {
           if (!(jsonValue in references))
             references[jsonValue] = null;
-        } else {
+        }
+        else {
           for (let key in jsonValue) {
             let anID = jsonValue[key];
             if (!(anID in references))
             references[anID] = null;
           }
         }
 
         deps[attribId] = jsonValue;
         hasDeps = true;
-      } else if (objectNounDef.contributeObjDependencies) {
-        /* if it has custom contribution logic, use it */
+      }
+      /* if it has custom contribution logic, use it */
+      else if (objectNounDef.contributeObjDependencies) {
         if (objectNounDef.contributeObjDependencies(jsonValue,
                              aReferencesByNounID, aInverseReferencesByNounID)) {
           deps[attribId] = jsonValue;
           hasDeps = true;
-        } else { // just propagate the value, it's some form of simple sentinel
+        }
+        else // just propagate the value, it's some form of simple sentinel
           aItem[attrib.boundName] = jsonValue;
-        }
-      } else if (objectNounDef.fromJSON) {
-        // otherwise, the value just needs to be de-persisted, or...
+      }
+      // otherwise, the value just needs to be de-persisted, or...
+      else if (objectNounDef.fromJSON) {
         if (attrib.singular) {
           // For consistency with the non-singular case, we don't assign the
           //  attribute if undefined is returned.
           let deserialized = objectNounDef.fromJSON(jsonValue, aItem);
           if (deserialized !== undefined)
             aItem[attrib.boundName] = deserialized;
-        } else {
+        }
+        else {
           // Convert all the entries in the list filtering out any undefined
           //  values. (TagNoun will do this if the tag is now dead.)
           let outList = [];
           for (let key in jsonValue) {
             let val = jsonValue[key];
             let deserialized = objectNounDef.fromJSON(val, aItem);
             if (deserialized !== undefined)
               outList.push(deserialized);
           }
           // Note: It's possible if we filtered things out that this is an empty
           //  list.  This is acceptable because this is somewhat of an unusual
           //  case and I don't think we want to further complicate our
           //  semantics.
           aItem[attrib.boundName] = outList;
         }
-      } else { // it's fine as is
+      }
+      // it's fine as is
+      else
         aItem[attrib.boundName] = jsonValue;
-      }
     }
 
     if (hasDeps)
       aItem._deps = deps;
     return hasDeps;
   },
-  /* eslint-enable complexity */
-
-  loadNounDeferredDeps(aItem, aReferencesByNounID, aInverseReferencesByNounID) {
+
+  loadNounDeferredDeps: function gloda_ds_loadNounDeferredDeps(aItem,
+      aReferencesByNounID, aInverseReferencesByNounID) {
     if (aItem._deps === undefined)
       return;
 
-    // this._log.debug("  loading deferred, deps: " +
+    //this._log.debug("  loading deferred, deps: " +
     //    Log4Moz.enumerateProperties(aItem._deps).join(","));
 
 
     let attribIDToDBDefAndParam = this._attributeIDToDBDefAndParam;
 
     for (let [attribId, jsonValue] of Object.entries(aItem._deps)) {
       let dbAttrib = attribIDToDBDefAndParam[attribId][0];
       let attrib = dbAttrib.attrDef;
 
       let objectNounDef = attrib.objectNounDef;
       let references = aReferencesByNounID[objectNounDef.id];
       if (attrib.special) {
         if (attrib.special === this.kSpecialColumnChildren) {
           let inverseReferences = aInverseReferencesByNounID[objectNounDef.id];
-          // this._log.info("inverse assignment: " + objectNounDef.id +
+          //this._log.info("inverse assignment: " + objectNounDef.id +
           //    " of " + aItem.id)
           aItem[attrib.storageAttributeName] = inverseReferences[aItem.id];
-        } else if (attrib.special === this.kSpecialColumnParent) {
-          // this._log.info("parent column load: " + objectNounDef.id +
+        }
+        else if (attrib.special === this.kSpecialColumnParent) {
+          //this._log.info("parent column load: " + objectNounDef.id +
           //    " storage value: " + aItem[attrib.idStorageAttributeName]);
           aItem[attrib.valueStorageAttributeName] =
             references[aItem[attrib.idStorageAttributeName]];
         }
-      } else if (objectNounDef.tableName) {
-        // this._log.info("trying to load: " + objectNounDef.id + " refs: " +
+      }
+      else if (objectNounDef.tableName) {
+        //this._log.info("trying to load: " + objectNounDef.id + " refs: " +
         //    jsonValue + ": " + Log4Moz.enumerateProperties(jsonValue).join(","));
         if (attrib.singular)
           aItem[attrib.boundName] = references[jsonValue];
         else
           aItem[attrib.boundName] = Object.keys(jsonValue).
             map(key => references[jsonValue[key]]);
-      } else if (objectNounDef.contributeObjDependencies) {
+      }
+      else if (objectNounDef.contributeObjDependencies) {
         aItem[attrib.boundName] =
           objectNounDef.resolveObjDependencies(jsonValue, aReferencesByNounID,
             aInverseReferencesByNounID);
       }
       // there is no other case
     }
 
     delete aItem._deps;
   },
 
   /* ********** Contact ********** */
   _nextContactId: 1,
 
-  _populateContactManagedId() {
+  _populateContactManagedId: function () {
     let stmt = this._createSyncStatement("SELECT MAX(id) FROM contacts", true);
     if (stmt.executeStep()) {  // no chance of this SQLITE_BUSY on this call
       this._nextContactId = stmt.getInt64(0) + 1;
     }
     stmt.finalize();
   },
 
   get _insertContactStatement() {
     let statement = this._createAsyncStatement(
       "INSERT INTO contacts (id, directoryUUID, contactUUID, name, popularity,\
                              frecency, jsonAttributes) \
               VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)");
     this.__defineGetter__("_insertContactStatement", () => statement);
     return this._insertContactStatement;
   },
 
-  createContact(aDirectoryUUID, aContactUUID, aName, aPopularity, aFrecency) {
+  createContact: function gloda_ds_createContact(aDirectoryUUID, aContactUUID,
+      aName, aPopularity, aFrecency) {
     let contactID = this._nextContactId++;
     let contact = new GlodaContact(this, contactID,
                                    aDirectoryUUID, aContactUUID, aName,
                                    aPopularity, aFrecency);
     return contact;
   },
 
-  insertContact(aContact) {
+  insertContact: function gloda_ds_insertContact(aContact) {
     let ics = this._insertContactStatement;
     ics.bindByIndex(0, aContact.id);
     if (aContact.directoryUUID == null)
       ics.bindByIndex(1, null);
     else
       ics.bindByIndex(1, aContact.directoryUUID);
     if (aContact.contactUUID == null)
       ics.bindByIndex(2, null);
@@ -3718,33 +3808,33 @@ var GlodaDatastore = {
                            popularity = ?4, \
                            frecency = ?5, \
                            jsonAttributes = ?6 \
                        WHERE id = ?7");
     this.__defineGetter__("_updateContactStatement", () => statement);
     return this._updateContactStatement;
   },
 
-  updateContact(aContact) {
+  updateContact: function gloda_ds_updateContact(aContact) {
     let ucs = this._updateContactStatement;
     ucs.bindByIndex(6, aContact.id);
     ucs.bindByIndex(0, aContact.directoryUUID);
     ucs.bindByIndex(1, aContact.contactUUID);
     ucs.bindByIndex(2, aContact.name);
     ucs.bindByIndex(3, aContact.popularity);
     ucs.bindByIndex(4, aContact.frecency);
     if (aContact._jsonText)
       ucs.bindByIndex(5, aContact._jsonText);
     else
       ucs.bindByIndex(5, null);
 
     ucs.executeAsync(this.trackAsync());
   },
 
-  _contactFromRow(aRow) {
+  _contactFromRow: function gloda_ds_contactFromRow(aRow) {
     let directoryUUID, contactUUID, jsonText;
     if (aRow.getTypeOfIndex(1) == Ci.mozIStorageValueArray.VALUE_TYPE_NULL)
       directoryUUID = null;
     else
       directoryUUID = aRow.getString(1);
     if (aRow.getTypeOfIndex(2) == Ci.mozIStorageValueArray.VALUE_TYPE_NULL)
       contactUUID = null;
     else
@@ -3768,17 +3858,17 @@ var GlodaDatastore = {
   },
 
   /**
    * Synchronous contact lookup currently only for use by gloda's creation
    *  of the concept of "me".  It is okay for it to be doing synchronous work
    *  because it is part of the startup process before any user code could
    *  have gotten a reference to Gloda, but no one else should do this.
    */
-  getContactByID(aContactID) {
+  getContactByID: function gloda_ds_getContactByID(aContactID) {
     let contact = GlodaCollectionManager.cacheLookupOne(
       GlodaContact.prototype.NOUN_ID, aContactID);
 
     if (contact === null) {
       let scbi = this._selectContactByIDStatement;
       scbi.bindByIndex(0, aContactID);
       if (this._syncStep(scbi)) {
         contact = this._contactFromRow(scbi);
@@ -3788,34 +3878,36 @@ var GlodaDatastore = {
     }
 
     return contact;
   },
 
   /* ********** Identity ********** */
   /** next identity id, managed for async use reasons. */
   _nextIdentityId: 1,
-  _populateIdentityManagedId() {
+  _populateIdentityManagedId: function () {
     let stmt = this._createSyncStatement(
       "SELECT MAX(id) FROM identities", true);
     if (stmt.executeStep()) { // no chance of this SQLITE_BUSY on this call
       this._nextIdentityId = stmt.getInt64(0) + 1;
     }
     stmt.finalize();
   },
 
   get _insertIdentityStatement() {
     let statement = this._createAsyncStatement(
       "INSERT INTO identities (id, contactID, kind, value, description, relay) \
               VALUES (?1, ?2, ?3, ?4, ?5, ?6)");
     this.__defineGetter__("_insertIdentityStatement", () => statement);
     return this._insertIdentityStatement;
   },
 
-  createIdentity(aContactID, aContact, aKind, aValue, aDescription, aIsRelay) {
+  createIdentity: function gloda_ds_createIdentity(aContactID, aContact, aKind,
+                                                   aValue, aDescription,
+                                                   aIsRelay) {
     let identityID = this._nextIdentityId++;
     let iis = this._insertIdentityStatement;
     iis.bindByIndex(0, identityID);
     iis.bindByIndex(1, aContactID);
     iis.bindByIndex(2, aKind);
     iis.bindByIndex(3, aValue);
     iis.bindByIndex(4, aDescription);
     iis.bindByIndex(5, aIsRelay ? 1 : 0);
@@ -3835,49 +3927,49 @@ var GlodaDatastore = {
                              value = ?3, \
                              description = ?4, \
                              relay = ?5 \
                          WHERE id = ?6");
     this.__defineGetter__("_updateIdentityStatement", () => statement);
     return this._updateIdentityStatement;
   },
 
-  updateIdentity(aIdentity) {
+  updateIdentity: function gloda_ds_updateIdentity(aIdentity) {
     let ucs = this._updateIdentityStatement;
     ucs.bindByIndex(5, aIdentity.id);
     ucs.bindByIndex(0, aIdentity.contactID);
     ucs.bindByIndex(1, aIdentity.kind);
     ucs.bindByIndex(2, aIdentity.value);
     ucs.bindByIndex(3, aIdentity.description);
     ucs.bindByIndex(4, aIdentity.relay ? 1 : 0);
 
     ucs.executeAsync(this.trackAsync());
   },
 
-  _identityFromRow(aRow) {
+  _identityFromRow: function gloda_ds_identityFromRow(aRow) {
     return new GlodaIdentity(this, aRow.getInt64(0), aRow.getInt64(1), null,
                              aRow.getString(2), aRow.getString(3),
                              aRow.getString(4),
-                             !!aRow.getInt32(5));
+                             aRow.getInt32(5) ? true : false);
   },
 
   get _selectIdentityByKindValueStatement() {
     let statement = this._createSyncStatement(
       "SELECT * FROM identities WHERE kind = ?1 AND value = ?2");
     this.__defineGetter__("_selectIdentityByKindValueStatement",
       () => statement);
     return this._selectIdentityByKindValueStatement;
   },
 
   /**
    * Synchronous lookup of an identity by kind and value, only for use by
    *  the legacy gloda core code that creates a concept of "me".
    *  Ex: (email, foo@example.com)
    */
-  getIdentity(aKind, aValue) {
+  getIdentity: function gloda_ds_getIdentity(aKind, aValue) {
     let identity = GlodaCollectionManager.cacheLookupOneByUniqueValue(
       GlodaIdentity.prototype.NOUN_ID, aKind + "@" + aValue);
 
     let ibkv = this._selectIdentityByKindValueStatement;
     ibkv.bindByIndex(0, aKind);
     ibkv.bindByIndex(1, aValue);
     if (this._syncStep(ibkv)) {
       identity = this._identityFromRow(ibkv);
--- a/mailnews/db/gloda/modules/dbview.js
+++ b/mailnews/db/gloda/modules/dbview.js
@@ -26,74 +26,78 @@ const {GlodaMsgSearcher} = ChromeUtils.i
  *     you want to display.
  */
 function GlodaSyntheticView(aArgs) {
   if ("query" in aArgs) {
     this.query = aArgs.query;
     this.collection = this.query.getCollection(this);
     this.completed = false;
     this.viewType = "global";
-  } else if ("collection" in aArgs) {
+  }
+  else if ("collection" in aArgs) {
     this.query = null;
     this.collection = aArgs.collection;
     this.completed = true;
     this.viewType = "global";
-  } else if ("conversation" in aArgs) {
+  }
+  else if ("conversation" in aArgs) {
     this.collection = aArgs.conversation.getMessagesCollection(this);
     this.query = this.collection.query;
     this.completed = false;
     this.viewType = "conversation";
-  } else {
+  }
+  else {
     throw new Error("You need to pass a query or collection");
   }
 
   this.customColumns = [];
 }
 GlodaSyntheticView.prototype = {
   defaultSort: [[Ci.nsMsgViewSortType.byDate, Ci.nsMsgViewSortOrder.descending]],
 
   /**
    * Request the search be performed and notification provided to
    *  aSearchListener.  If results are already available, they should
    *  be provided to aSearchListener without re-performing the search.
    */
-  search(aSearchListener, aCompletionCallback) {
+  search: function(aSearchListener, aCompletionCallback) {
     this.searchListener = aSearchListener;
     this.completionCallback = aCompletionCallback;
 
     this.searchListener.onNewSearch();
     if (this.completed) {
       this.reportResults(this.collection.items);
       // we're not really aborting, but it closes things out nicely
       this.abortSearch();
+      return;
     }
   },
 
-  abortSearch() {
+  abortSearch: function() {
     if (this.searchListener)
       this.searchListener.onSearchDone(Cr.NS_OK);
     if (this.completionCallback)
       this.completionCallback();
     this.searchListener = null;
     this.completionCallback = null;
   },
 
-  reportResults(aItems) {
+  reportResults: function(aItems) {
     for (let item of aItems) {
       let hdr = item.folderMessage;
       if (hdr)
         this.searchListener.onSearchHit(hdr, hdr.folder);
     }
   },
 
   /**
    * Helper function used by |DBViewWrapper.getMsgHdrForMessageID| since there
    *  are no actual backing folders for it to check.
    */
-  getMsgHdrForMessageID(aMessageId) {
+  getMsgHdrForMessageID: function(aMessageId) {
     for (let item of this.collection.items) {
       if (item.headerMessageID == aMessageId) {
         let hdr = item.folderMessage;
         if (hdr)
           return hdr;
       }
     }
     return null;
@@ -122,45 +126,47 @@ GlodaSyntheticView.prototype = {
       visible: true,
     },
     locationCol: {
       visible: true,
     },
   },
 
   // --- settings persistence
-  getPersistedSetting(aSetting) {
+  getPersistedSetting: function(aSetting) {
     try {
       return JSON.parse(Services.prefs.getCharPref(
         "mailnews.database.global.views." + this.viewType + "." + aSetting
       ));
-    } catch (e) {
+    }
+    catch (e) {
       return this.getDefaultSetting(aSetting);
     }
   },
-  setPersistedSetting(aSetting, aValue) {
+  setPersistedSetting: function(aSetting, aValue) {
     Services.prefs.setCharPref(
       "mailnews.database.global.views." + this.viewType + "." + aSetting,
       JSON.stringify(aValue)
     );
   },
-  getDefaultSetting(aSetting) {
+  getDefaultSetting: function(aSetting) {
     if (aSetting == "columns")
       return this.DEFAULT_COLUMN_STATES;
-    return undefined;
+    else
+      return undefined;
   },
 
   // --- collection listener
-  onItemsAdded(aItems, aCollection) {
+  onItemsAdded: function(aItems, aCollection) {
     if (this.searchListener)
       this.reportResults(aItems);
   },
-  onItemsModified(aItems, aCollection) {
+  onItemsModified: function(aItems, aCollection) {
   },
-  onItemsRemoved(aItems, aCollection) {
+  onItemsRemoved: function(aItems, aCollection) {
   },
-  onQueryCompleted(aCollection) {
+  onQueryCompleted: function(aCollection) {
     this.completed = true;
     this.searchListener.onSearchDone(Cr.NS_OK);
     if (this.completionCallback)
       this.completionCallback();
   },
 };
--- a/mailnews/db/gloda/modules/explattr.js
+++ b/mailnews/db/gloda/modules/explattr.js
@@ -4,17 +4,17 @@
 
 /*
  * This file provides the "explicit attribute" provider for messages.  It is
  *  concerned with attributes that are the result of user actions.  For example,
  *  whether a message is starred (flagged), message tags, whether it is
  *  read/unread, etc.
  */
 
-this.EXPORTED_SYMBOLS = ["GlodaExplicitAttr"];
+this.EXPORTED_SYMBOLS = ['GlodaExplicitAttr'];
 
 const {Log4Moz} = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
 const {StringBundle} = ChromeUtils.import("resource:///modules/StringBundle.js");
 
 const {GlodaUtils} = ChromeUtils.import("resource:///modules/gloda/utils.js");
 const {Gloda} = ChromeUtils.import("resource:///modules/gloda/gloda.js");
 const {TagNoun} = ChromeUtils.import("resource:///modules/gloda/noun_tag.js");
 const {MailServices} = ChromeUtils.import("resource:///modules/MailServices.jsm");
@@ -31,37 +31,38 @@ var EXT_BUILTIN = "built-in";
  *  message as read.
  */
 var GlodaExplicitAttr = {
   providerName: "gloda.explattr",
   strings: new StringBundle("chrome://messenger/locale/gloda.properties"),
   _log: null,
   _msgTagService: null,
 
-  init() {
+  init: function gloda_explattr_init() {
     this._log =  Log4Moz.repository.getLogger("gloda.explattr");
 
     this._msgTagService = MailServices.tags;
 
     try {
       this.defineAttributes();
-    } catch (ex) {
+    }
+    catch (ex) {
       this._log.error("Error in init: " + ex);
       throw ex;
     }
   },
 
   /** Boost for starred messages. */
   NOTABILITY_STARRED: 16,
   /** Boost for tagged messages, first tag. */
   NOTABILITY_TAGGED_FIRST: 8,
   /** Boost for tagged messages, each additional tag. */
   NOTABILITY_TAGGED_ADDL: 1,
 
-  defineAttributes() {
+  defineAttributes: function() {
     // Tag
     this._attrTag = Gloda.defineAttribute({
                         provider: this,
                         extensionName: Gloda.BUILT_IN,
                         attributeType: Gloda.kAttrExplicit,
                         attributeName: "tag",
                         bindName: "tags",
                         singular: false,
@@ -123,17 +124,18 @@ var GlodaExplicitAttr = {
       attributeName: "forwarded",
       singular: true,
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_BOOLEAN,
       parameterNoun: null,
     }); // tested-by: test_attributes_explicit
   },
 
-  * process(aGlodaMessage, aRawReps, aIsNew, aCallbackHandle) {
+  process: function* Gloda_explattr_process(aGlodaMessage, aRawReps, aIsNew,
+                                            aCallbackHandle) {
     let aMsgHdr = aRawReps.header;
 
     aGlodaMessage.starred = aMsgHdr.isFlagged;
     if (aGlodaMessage.starred)
       aGlodaMessage.notability += this.NOTABILITY_STARRED;
 
     aGlodaMessage.read = aMsgHdr.isRead;
 
@@ -141,17 +143,17 @@ var GlodaExplicitAttr = {
     aGlodaMessage.repliedTo = Boolean(flags & nsMsgMessageFlags_Replied);
     aGlodaMessage.forwarded = Boolean(flags & nsMsgMessageFlags_Forwarded);
 
     let tags = aGlodaMessage.tags = [];
 
     // -- Tag
     // build a map of the keywords
     let keywords = aMsgHdr.getStringProperty("keywords");
-    let keywordList = keywords.split(" ");
+    let keywordList = keywords.split(' ');
     let keywordMap = {};
     for (let iKeyword = 0; iKeyword < keywordList.length; iKeyword++) {
       let keyword = keywordList[iKeyword];
       keywordMap[keyword] = true;
     }
 
     let tagArray = TagNoun.getAllTags();
     for (let iTag = 0; iTag < tagArray.length; iTag++) {
@@ -167,17 +169,17 @@ var GlodaExplicitAttr = {
     yield Gloda.kWorkDone;
   },
 
   /**
    * Duplicates the notability logic from process().  Arguably process should
    *  be factored to call us, grokNounItem should be factored to call us, or we
    *  should get sufficiently fancy that our code wildly diverges.
    */
-  score(aMessage, aContext) {
+  score: function Gloda_explattr_score(aMessage, aContext) {
     let score = 0;
     if (aMessage.starred)
       score += this.NOTABILITY_STARRED;
     if (aMessage.tags.length)
       score += this.NOTABILITY_TAGGED_FIRST +
         (aMessage.tags.length - 1) * this.NOTABILITY_TAGGED_ADDL;
     return score;
   },
--- a/mailnews/db/gloda/modules/facet.js
+++ b/mailnews/db/gloda/modules/facet.js
@@ -27,31 +27,33 @@ function FacetDriver(aNounDef, aWindow) 
 
   this._makeFaceters();
 }
 FacetDriver.prototype = {
   /**
    * Populate |this.faceters| with a set of faceters appropriate to the noun
    *  definition associated with this instance.
    */
-  _makeFaceters() {
+  _makeFaceters: function() {
     let faceters = this.faceters = [];
 
     function makeFaceter(aAttrDef, aFacetDef) {
       let facetType = aFacetDef.type;
 
       if (aAttrDef.singular) {
         if (facetType == "date")
           faceters.push(new DateFaceter(aAttrDef, aFacetDef));
         else
           faceters.push(new DiscreteFaceter(aAttrDef, aFacetDef));
-      } else if (facetType == "nonempty?") {
-        faceters.push(new NonEmptySetFaceter(aAttrDef, aFacetDef));
-      } else {
-        faceters.push(new DiscreteSetFaceter(aAttrDef, aFacetDef));
+      }
+      else {
+        if (facetType == "nonempty?")
+          faceters.push(new NonEmptySetFaceter(aAttrDef, aFacetDef));
+        else
+          faceters.push(new DiscreteSetFaceter(aAttrDef, aFacetDef));
       }
     }
 
     for (let key in this.nounDef.attribsByBoundName) {
       let attrDef = this.nounDef.attribsByBoundName[key];
       // ignore attributes that do not want to be faceted
       if (!attrDef.facet)
         continue;
@@ -64,31 +66,31 @@ FacetDriver.prototype = {
         }
       }
     }
   },
   /**
    * Asynchronously facet the provided items, calling the provided callback when
    *  completed.
    */
-  go(aItems, aCallback, aCallbackThis) {
+  go: function FacetDriver_go(aItems, aCallback, aCallbackThis) {
     this.items = aItems;
     this.callback = aCallback;
     this.callbackThis = aCallbackThis;
 
     this._nextFaceter = 0;
     this._drive();
   },
 
   _MAX_FACETING_TIMESLICE_MS: 100,
   _FACETING_YIELD_DURATION_MS: 0,
-  _driveWrapper(aThis) {
+  _driveWrapper: function(aThis) {
     aThis._drive();
   },
-  _drive() {
+  _drive: function() {
     let start = Date.now();
 
     while (this._nextFaceter < this.faceters.length) {
       let faceter = this.faceters[this._nextFaceter++];
       // for now we facet in one go, but the long-term plan allows for them to
       //  be generators.
       faceter.facetItems(this.items);
 
@@ -98,79 +100,82 @@ FacetDriver.prototype = {
                                 this._FACETING_YIELD_DURATION_MS,
                                 this);
         return;
       }
     }
 
     // we only get here once we are done with the faceters
     this.callback.call(this.callbackThis);
-  },
+  }
 };
 
 var FacetUtils = {
-  _groupSizeComparator(a, b) {
+  _groupSizeComparator: function(a, b) {
     return b[1].length - a[1].length;
   },
 
   /**
    * Given a list where each entry is a tuple of [group object, list of items
    *  belonging to that group], produce a new list of the top grouped items.  We
    *  used to also produce an "other" aggregation, but that turned out to be
    *  conceptually difficult to deal with, so that's gone, leaving this method
    *  with much less to do.
    *
    * @param aAttrDef The attribute for the facet we are working with.
    * @param aGroups The list of groups built for the facet.
    * @param aMaxCount The number of result rows you want back.
    */
-  makeTopGroups(aAttrDef, aGroups, aMaxCount) {
+  makeTopGroups: function FacetUtils_makeTopGroups(aAttrDef, aGroups,
+                                                   aMaxCount) {
     let nounDef = aAttrDef.objectNounDef;
     let realGroupsToUse = aMaxCount;
 
     let orderedBySize = aGroups.concat();
     orderedBySize.sort(this._groupSizeComparator);
 
     // - get the real groups to use and order them by the attribute comparator
     let outGroups = orderedBySize.slice(0, realGroupsToUse);
     let comparator = nounDef.comparator;
     function comparatorHelper(a, b) {
       return comparator(a[0], b[0]);
     }
     outGroups.sort(comparatorHelper);
 
     return outGroups;
-  },
+  }
 };
 
 /**
  * Facet discrete things like message authors, boolean values, etc.  Only
  *  appropriate for use on singular values.  Use |DiscreteSetFaceter| for
  *  non-singular values.
  */
 function DiscreteFaceter(aAttrDef, aFacetDef) {
   this.attrDef = aAttrDef;
   this.facetDef = aFacetDef;
 }
 DiscreteFaceter.prototype = {
   type: "discrete",
   /**
    * Facet the given set of items, deferring to the appropriate helper method
    */
-  facetItems(aItems) {
+  facetItems: function(aItems) {
     if (this.attrDef.objectNounDef.isPrimitive)
       return this.facetPrimitiveItems(aItems);
-    return this.facetComplexItems(aItems);
+    else
+      return this.facetComplexItems(aItems);
   },
   /**
    * Facet an attribute whose value is primitive, meaning that it is a raw
    *  numeric value or string, rather than a complex object.
    */
-  facetPrimitiveItems(aItems) {
+  facetPrimitiveItems: function(aItems) {
     let attrKey = this.attrDef.boundName;
+    let nounDef = this.attrDef.objectNounDef;
     let filter = this.facetDef.filter;
 
     let valStrToVal = {};
     let groups = this.groups = {};
     this.groupCount = 0;
 
     for (let item of aItems) {
       let val = (attrKey in item) ? item[attrKey] : null;
@@ -178,19 +183,19 @@ DiscreteFaceter.prototype = {
         continue;
 
       // skip items the filter tells us to ignore
       if (filter && !filter(val))
         continue;
 
       // We need to use hasOwnProperty because we cannot guarantee that the
       //  contents of val won't collide with the attributes in Object.prototype.
-      if (groups.hasOwnProperty(val)) {
+      if (groups.hasOwnProperty(val))
         groups[val].push(item);
-      } else {
+      else {
         groups[val] = [item];
         valStrToVal[val] = val;
         this.groupCount++;
       }
     }
 
     let orderedGroups = Object.keys(groups).
       map(key => [valStrToVal[key], groups[key]]);
@@ -201,18 +206,19 @@ DiscreteFaceter.prototype = {
     orderedGroups.sort(comparatorHelper);
     this.orderedGroups = orderedGroups;
   },
   /**
    * Facet an attribute whose value is a complex object that can be identified
    *  by its 'id' attribute.  This is the case where the value is itself a noun
    *  instance.
    */
-  facetComplexItems(aItems) {
+  facetComplexItems: function(aItems) {
     let attrKey = this.attrDef.boundName;
+    let nounDef = this.attrDef.objectNounDef;
     let filter = this.facetDef.filter;
     let idAttr = this.facetDef.groupIdAttr;
 
     let groups = this.groups = {};
     let groupMap = this.groupMap = {};
     this.groupCount = 0;
 
     for (let item of aItems) {
@@ -226,17 +232,18 @@ DiscreteFaceter.prototype = {
 
       let valId = (val == null) ? null : val[idAttr];
       // We need to use hasOwnProperty because tag nouns are complex objects
       //  with id's that are non-numeric and so can collide with the contents
       //  of Object.prototype.  (Note: the "tags" attribute is actually handled
       //  by the DiscreteSetFaceter.)
       if (groupMap.hasOwnProperty(valId)) {
         groups[valId].push(item);
-      } else {
+      }
+      else {
         groupMap[valId] = val;
         groups[valId] = [item];
         this.groupCount++;
       }
     }
 
     let orderedGroups = Object.keys(groups).
       map(key => [groupMap[key], groups[key]]);
@@ -261,27 +268,29 @@ function DiscreteSetFaceter(aAttrDef, aF
   this.attrDef = aAttrDef;
   this.facetDef = aFacetDef;
 }
 DiscreteSetFaceter.prototype = {
   type: "discrete",
   /**
    * Facet the given set of items, deferring to the appropriate helper method
    */
-  facetItems(aItems) {
+  facetItems: function(aItems) {
     if (this.attrDef.objectNounDef.isPrimitive)
       return this.facetPrimitiveItems(aItems);
-    return this.facetComplexItems(aItems);
+    else
+      return this.facetComplexItems(aItems);
   },
   /**
    * Facet an attribute whose value is primitive, meaning that it is a raw
    *  numeric value or string, rather than a complex object.
    */
-  facetPrimitiveItems(aItems) {
+  facetPrimitiveItems: function(aItems) {
     let attrKey = this.attrDef.boundName;
+    let nounDef = this.attrDef.objectNounDef;
     let filter = this.facetDef.filter;
 
     let groups = this.groups = {};
     let valStrToVal = {};
     this.groupCount = 0;
 
     for (let item of aItems) {
       let vals = (attrKey in item) ? item[attrKey] : null;
@@ -294,19 +303,19 @@ DiscreteSetFaceter.prototype = {
       for (let val of vals) {
         // skip items the filter tells us to ignore
         if (filter && !filter(val))
           continue;
 
         // We need to use hasOwnProperty because we cannot guarantee that the
         //  contents of val won't collide with the attributes in
         //  Object.prototype.
-        if (groups.hasOwnProperty(val)) {
+        if (groups.hasOwnProperty(val))
           groups[val].push(item);
-        } else {
+        else {
           groups[val] = [item];
           valStrToVal[val] = val;
           this.groupCount++;
         }
       }
     }
 
     let orderedGroups = Object.keys(groups).
@@ -318,18 +327,19 @@ DiscreteSetFaceter.prototype = {
     orderedGroups.sort(comparatorHelper);
     this.orderedGroups = orderedGroups;
   },
   /**
    * Facet an attribute whose value is a complex object that can be identified
    *  by its 'id' attribute.  This is the case where the value is itself a noun
    *  instance.
    */
-  facetComplexItems(aItems) {
+  facetComplexItems: function(aItems) {
     let attrKey = this.attrDef.boundName;
+    let nounDef = this.attrDef.objectNounDef;
     let filter = this.facetDef.filter;
     let idAttr = this.facetDef.groupIdAttr;
 
     let groups = this.groups = {};
     let groupMap = this.groupMap = {};
     this.groupCount = 0;
 
     for (let item of aItems) {
@@ -346,17 +356,18 @@ DiscreteSetFaceter.prototype = {
           continue;
 
         let valId = (val == null) ? null : val[idAttr];
         // We need to use hasOwnProperty because tag nouns are complex objects
         //  with id's that are non-numeric and so can collide with the contents
         //  of Object.prototype.
         if (groupMap.hasOwnProperty(valId)) {
           groups[valId].push(item);
-        } else {
+        }
+        else {
           groupMap[valId] = val;
           groups[valId] = [item];
           this.groupCount++;
         }
       }
     }
 
     let orderedGroups = Object.keys(groups).
@@ -378,22 +389,24 @@ function NonEmptySetFaceter(aAttrDef, aF
   this.attrDef = aAttrDef;
   this.facetDef = aFacetDef;
 }
 NonEmptySetFaceter.prototype = {
   type: "boolean",
   /**
    * Facet the given set of items, deferring to the appropriate helper method
    */
-  facetItems(aItems) {
+  facetItems: function(aItems) {
     let attrKey = this.attrDef.boundName;
+    let nounDef = this.attrDef.objectNounDef;
 
     let trueValues = [];
     let falseValues = [];
 
+    let groups = this.groups = {};
     this.groupCount = 0;
 
     for (let item of aItems) {
       let vals = (attrKey in item) ? item[attrKey] : null;
       if (vals == null || vals.length == 0)
         falseValues.push(item);
       else
         trueValues.push(item);
@@ -401,28 +414,28 @@ NonEmptySetFaceter.prototype = {
 
     this.orderedGroups = [];
     if (trueValues.length)
       this.orderedGroups.push([true, trueValues]);
     if (falseValues.length)
       this.orderedGroups.push([false, falseValues]);
     this.groupCount = this.orderedGroups.length;
   },
-  makeQuery(aGroupValues, aInclusive) {
+  makeQuery: function(aGroupValues, aInclusive) {
     let query = this.query = Gloda.newQuery(Gloda.NOUN_MESSAGE);
 
     let constraintFunc = query[this.attrDef.boundName];
     constraintFunc.call(query);
 
     // Our query is always for non-empty lists (at this time), so we want to
     //  invert if they're excluding 'true' or including 'false', which means !=.
     let invert = aGroupValues[0] != aInclusive;
 
     return [query, invert];
-  },
+  }
 };
 
 
 /**
  * Facet dates.  We build a hierarchical nested structure of year, month, and
  *  day nesting levels.  This decision was made speculatively in the hopes that
  *  it would allow us to do clustered analysis and that there might be a benefit
  *  for that.  For example, if you search for "Christmas", we might notice
@@ -435,23 +448,26 @@ function DateFaceter(aAttrDef, aFacetDef
   this.attrDef = aAttrDef;
   this.facetDef = aFacetDef;
 }
 DateFaceter.prototype = {
   type: "date",
   /**
    *
    */
-  facetItems(aItems) {
+  facetItems: function(aItems) {
     let attrKey = this.attrDef.boundName;
+    let nounDef = this.attrDef.objectNounDef;
 
     let years = this.years = {_subCount: 0};
     // generally track the time range
     let oldest = null, newest = null;
 
+    let validItems = this.validItems = [];
+
     // just cheat and put us at the front...
     this.groupCount = aItems.length ? 1000 : 0;
     this.orderedGroups = null;
 
     /** The number of items with a null/missing attribute. */
     this.missing = 0;
 
     /**
@@ -495,64 +511,67 @@ DateFaceter.prototype = {
         newest = val;
 
       // -- bucket
       // - year
       let year, valYear = val.getYear();
       if (valYear in years) {
         year = years[valYear];
         year._dateCount++;
-      } else {
+      }
+      else {
         year = years[valYear] = {
           _dateCount: 1,
-          _subCount: 0,
+          _subCount: 0
         };
         years._subCount++;
       }
 
       // - month
       let month, valMonth = val.getMonth();
       if (valMonth in year) {
         month = year[valMonth];
         month._dateCount++;
-      } else {
+      }
+      else {
         month = year[valMonth] = {
           _dateCount: 1,
-          _subCount: 0,
+          _subCount: 0
         };
         year._subCount++;
       }
 
       // - day
       let valDate = val.getDate();
       if (valDate in month) {
         month[valDate].push(item);
-      } else {
+      }
+      else {
         month[valDate] = [item];
       }
     }
 
     this.oldest = oldest;
     this.newest = newest;
   },
 
-  _unionMonth(aMonthObj) {
+  _unionMonth: function(aMonthObj) {
     let dayItemLists = [];
     for (let key in aMonthObj) {
       let dayItemList = aMonthObj[key];
-      if (typeof(key) == "string" && key.startsWith("_"))
+      if (typeof(key) == "string" && key.startsWith('_'))
         continue;
       dayItemLists.push(dayItemList);
     }
     return dayItemLists;
   },
 
-  _unionYear(aYearObj) {
+  _unionYear: function(aYearObj) {
     let monthItemLists = [];
     for (let key in aYearObj) {
       let monthObj = aYearObj[key];
-      if (typeof(key) == "string" && key.startsWith("_"))
+      if (typeof(key) == "string" && key.startsWith('_'))
         continue;
       monthItemLists.push(this._unionMonth(monthObj));
     }
     return monthItemLists;
-  },
+  }
 };
--- a/mailnews/db/gloda/modules/fundattr.js
+++ b/mailnews/db/gloda/modules/fundattr.js
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-this.EXPORTED_SYMBOLS = ["GlodaFundAttr"];
+this.EXPORTED_SYMBOLS = ['GlodaFundAttr'];
 
 const {Log4Moz} = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
 const {StringBundle} = ChromeUtils.import("resource:///modules/StringBundle.js");
 
 const {GlodaUtils} = ChromeUtils.import("resource:///modules/gloda/utils.js");
 const {Gloda} = ChromeUtils.import("resource:///modules/gloda/gloda.js");
 const {GlodaDatastore} = ChromeUtils.import("resource:///modules/gloda/datastore.js");
 const {GlodaAttachment} = ChromeUtils.import("resource:///modules/gloda/datamodel.js");
@@ -21,22 +21,23 @@ const {GlodaContent} = ChromeUtils.impor
  *  than most extension providers should do.  In summary, don't mimic this code
  *  unless you won't complain when your code breaks.
  */
 var GlodaFundAttr = {
   providerName: "gloda.fundattr",
   strings: new StringBundle("chrome://messenger/locale/gloda.properties"),
   _log: null,
 
-  init() {
+  init: function gloda_explattr_init() {
     this._log =  Log4Moz.repository.getLogger("gloda.fundattr");
 
     try {
       this.defineAttributes();
-    } catch (ex) {
+    }
+    catch (ex) {
       this._log.error("Error in init: " + ex);
       throw ex;
     }
   },
 
   POPULARITY_FROM_ME_TO: 10,
   POPULARITY_FROM_ME_CC: 4,
   POPULARITY_FROM_ME_BCC: 3,
@@ -50,169 +51,169 @@ var GlodaFundAttr = {
   NOTABILITY_INVOLVING_ME: 1,
   /** Boost for message from someone in 'my' address book. */
   NOTABILITY_FROM_IN_ADDR_BOOK: 10,
   /** Boost for the first person involved in my address book. */
   NOTABILITY_INVOLVING_ADDR_BOOK_FIRST: 8,
   /** Boost for each additional person involved in my address book. */
   NOTABILITY_INVOLVING_ADDR_BOOK_ADDL: 2,
 
-  defineAttributes() {
+  defineAttributes: function gloda_fundattr_defineAttributes() {
     /* ***** Conversations ***** */
     // conversation: subjectMatches
     this._attrConvSubject = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrDerived,
       attributeName: "subjectMatches",
       singular: true,
       special: Gloda.kSpecialFulltext,
       specialColumnName: "subject",
       subjectNouns: [Gloda.NOUN_CONVERSATION],
       objectNoun: Gloda.NOUN_FULLTEXT,
-    });
+      });
 
     /* ***** Messages ***** */
     // folder
     this._attrFolder = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrFundamental,
       attributeName: "folder",
       singular: true,
       facet: true,
       special: Gloda.kSpecialColumn,
       specialColumnName: "folderID",
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_FOLDER,
-    }); // tested-by: test_attributes_fundamental
+      }); // tested-by: test_attributes_fundamental
     this._attrAccount = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrDerived,
       attributeName: "account",
       canQuery: "memory",
       singular: true,
       facet: true,
       subjectNouns: [Gloda.NOUN_MESSAGE],
-      objectNoun: Gloda.NOUN_ACCOUNT,
-    });
+      objectNoun: Gloda.NOUN_ACCOUNT
+      });
     this._attrMessageKey = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrFundamental,
       attributeName: "messageKey",
       singular: true,
       special: Gloda.kSpecialColumn,
       specialColumnName: "messageKey",
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_NUMBER,
       canQuery: true,
-    }); // tested-by: test_attributes_fundamental
+      }); // tested-by: test_attributes_fundamental
 
     // We need to surface the deleted attribute for querying, but there is no
     //  reason for user code, so let's call it "_deleted" rather than deleted.
     // (In fact, our validity constraints require a special query formulation
     //  that user code should have no clue exists.  That's right user code,
     //  that's a dare.)
     Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrFundamental,
       attributeName: "_deleted",
       singular: true,
       special: Gloda.kSpecialColumn,
       specialColumnName: "deleted",
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_NUMBER,
-    });
+      });
 
 
     // -- fulltext search helpers
     // fulltextMatches.  Match over message subject, body, and attachments
     // @testpoint gloda.noun.message.attr.fulltextMatches
     this._attrFulltext = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrDerived,
       attributeName: "fulltextMatches",
       singular: true,
       special: Gloda.kSpecialFulltext,
       specialColumnName: "messagesText",
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_FULLTEXT,
-    });
+      });
 
     // subjectMatches.  Fulltext match on subject
     // @testpoint gloda.noun.message.attr.subjectMatches
     this._attrSubjectText = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrDerived,
       attributeName: "subjectMatches",
       singular: true,
       special: Gloda.kSpecialFulltext,
       specialColumnName: "subject",
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_FULLTEXT,
-    });
+      });
 
     // bodyMatches. super-synthetic full-text matching...
     // @testpoint gloda.noun.message.attr.bodyMatches
     this._attrBody = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrDerived,
       attributeName: "bodyMatches",
       singular: true,
       special: Gloda.kSpecialFulltext,
       specialColumnName: "body",
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_FULLTEXT,
-    });
+      });
 
     // attachmentNamesMatch
     // @testpoint gloda.noun.message.attr.attachmentNamesMatch
     this._attrAttachmentNames = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrDerived,
       attributeName: "attachmentNamesMatch",
       singular: true,
       special: Gloda.kSpecialFulltext,
       specialColumnName: "attachmentNames",
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_FULLTEXT,
-    });
+      });
 
     // @testpoint gloda.noun.message.attr.authorMatches
     this._attrAuthorFulltext = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrDerived,
       attributeName: "authorMatches",
       singular: true,
       special: Gloda.kSpecialFulltext,
       specialColumnName: "author",
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_FULLTEXT,
-    });
+      });
 
     // @testpoint gloda.noun.message.attr.recipientsMatch
     this._attrRecipientsFulltext = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrDerived,
       attributeName: "recipientsMatch",
       singular: true,
       special: Gloda.kSpecialFulltext,
       specialColumnName: "recipients",
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_FULLTEXT,
-    });
+      });
 
     // --- synthetic stuff for some reason
     // conversation
     // @testpoint gloda.noun.message.attr.conversation
     this._attrConversation = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrFundamental,
@@ -220,49 +221,49 @@ var GlodaFundAttr = {
       singular: true,
       special: Gloda.kSpecialColumnParent,
       specialColumnName: "conversationID",
       idStorageAttributeName: "_conversationID",
       valueStorageAttributeName: "_conversation",
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_CONVERSATION,
       canQuery: true,
-    });
+      });
 
     // --- Fundamental
     // From
     this._attrFrom = Gloda.defineAttribute({
                         provider: this,
                         extensionName: Gloda.BUILT_IN,
                         attributeType: Gloda.kAttrFundamental,
                         attributeName: "from",
                         singular: true,
                         subjectNouns: [Gloda.NOUN_MESSAGE],
                         objectNoun: Gloda.NOUN_IDENTITY,
-                      }); // tested-by: test_attributes_fundamental
+                        }); // tested-by: test_attributes_fundamental
     // To
     this._attrTo = Gloda.defineAttribute({
                         provider: this,
                         extensionName: Gloda.BUILT_IN,
                         attributeType: Gloda.kAttrFundamental,
                         attributeName: "to",
                         singular: false,
                         subjectNouns: [Gloda.NOUN_MESSAGE],
                         objectNoun: Gloda.NOUN_IDENTITY,
-                      }); // tested-by: test_attributes_fundamental
+                        }); // tested-by: test_attributes_fundamental
     // Cc
     this._attrCc = Gloda.defineAttribute({
                         provider: this,
                         extensionName: Gloda.BUILT_IN,
                         attributeType: Gloda.kAttrFundamental,
                         attributeName: "cc",
                         singular: false,
                         subjectNouns: [Gloda.NOUN_MESSAGE],
                         objectNoun: Gloda.NOUN_IDENTITY,
-                      }); // not-tested
+                        }); // not-tested
     /**
      * Bcc'ed recipients; only makes sense for sent messages.
      */
     this._attrBcc = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrFundamental,
       attributeName: "bcc",
@@ -280,31 +281,31 @@ var GlodaFundAttr = {
                         singular: true,
                         facet: {
                           type: "date",
                         },
                         special: Gloda.kSpecialColumn,
                         specialColumnName: "date",
                         subjectNouns: [Gloda.NOUN_MESSAGE],
                         objectNoun: Gloda.NOUN_DATE,
-                      }); // tested-by: test_attributes_fundamental
+                        }); // tested-by: test_attributes_fundamental
 
     // Header message ID.
     this._attrHeaderMessageID = Gloda.defineAttribute({
                         provider: this,
                         extensionName: Gloda.BUILT_IN,
                         attributeType: Gloda.kAttrFundamental,
                         attributeName: "headerMessageID",
                         singular: true,
                         special: Gloda.kSpecialString,
                         specialColumnName: "headerMessageID",
                         subjectNouns: [Gloda.NOUN_MESSAGE],
                         objectNoun: Gloda.NOUN_STRING,
                         canQuery: true,
-                      }); // tested-by: test_attributes_fundamental
+                        }); // tested-by: test_attributes_fundamental
 
     // Attachment MIME Types
     this._attrAttachmentTypes = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrFundamental,
       attributeName: "attachmentTypes",
       singular: false,
@@ -312,41 +313,41 @@ var GlodaFundAttr = {
       facet: {
         type: "default",
         // This will group the MIME types by their category.
         groupIdAttr: "category",
         queryHelper: "Category",
       },
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_MIME_TYPE,
-    });
+      });
 
     // Attachment infos
     this._attrIsEncrypted = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrFundamental,
       attributeName: "isEncrypted",
       singular: true,
       emptySetIsSignificant: false,
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_NUMBER,
-    });
+      });
 
     // Attachment infos
     this._attrAttachmentInfos = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrFundamental,
       attributeName: "attachmentInfos",
       singular: false,
       emptySetIsSignificant: false,
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_ATTACHMENT,
-    });
+      });
 
     // --- Optimization
     /**
      * Involves means any of from/to/cc/bcc.  The queries get ugly enough
      *  without this that it seems to justify the cost, especially given the
      *  frequent use case.  (In fact, post-filtering for the specific from/to/cc
      *  is probably justifiable rather than losing this attribute...)
      */
@@ -360,65 +361,65 @@ var GlodaFundAttr = {
         type: "default",
         /**
          * Filter out 'me', as we have other facets that deal with that, and the
          *  'me' identities are so likely that they distort things.
          *
          * @return true if the identity is not one of my identities, false if it
          *   is.
          */
-        filter(aItem) {
+        filter: function gloda_explattr_involves_filter(aItem) {
           return (!(aItem.id in Gloda.myIdentities));
-        },
+        }
       },
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_IDENTITY,
-    }); // not-tested
+      }); // not-tested
 
     /**
      * Any of to/cc/bcc.
      */
     this._attrRecipients = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrOptimization,
       attributeName: "recipients",
       singular: false,
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_IDENTITY,
-    }); // not-tested
+      }); // not-tested
 
     // From Me (To/Cc/Bcc)
     this._attrFromMe = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrOptimization,
       attributeName: "fromMe",
       singular: false,
       // The interesting thing to a facet is whether the message is from me.
       facet: {
-        type: "nonempty?",
+        type: "nonempty?"
       },
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_PARAM_IDENTITY,
-    }); // not-tested
+      }); // not-tested
     // To/Cc/Bcc Me
     this._attrToMe = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrFundamental,
       attributeName: "toMe",
       // The interesting thing to a facet is whether the message is to me.
       facet: {
-        type: "nonempty?",
+        type: "nonempty?"
       },
       singular: false,
       subjectNouns: [Gloda.NOUN_MESSAGE],
       objectNoun: Gloda.NOUN_PARAM_IDENTITY,
-    }); // not-tested
+      }); // not-tested
 
 
     // -- Mailing List
     // Non-singular, but a hard call.  Namely, it is obvious that a message can
     //  be addressed to multiple mailing lists.  However, I don't see how you
     //  could receive a message with more than one set of List-* headers,
     //  since each list-serve would each send you a copy.  Based on our current
     //  decision to treat each physical message as separate, it almost seems
@@ -438,32 +439,33 @@ var GlodaFundAttr = {
                         attributeType: Gloda.kAttrFundamental,
                         attributeName: "mailing-list",
                         bindName: "mailingLists",
                         singular: false,
                         emptySetIsSignificant: true,
                         facet: true,
                         subjectNouns: [Gloda.NOUN_MESSAGE],
                         objectNoun: Gloda.NOUN_IDENTITY,
-                      }); // not-tested, not-implemented
+                        }); // not-tested, not-implemented
   },
 
   RE_LIST_POST: /<mailto:([^>]+)>/,
 
   /**
    *
    * Specializations:
    * - Mailing Lists.  Replies to a message on a mailing list frequently only
    *   have the list-serve as the 'to', so we try to generate a synthetic 'to'
    *   based on the author of the parent message when possible.  (The 'possible'
    *   part is that we may not have a copy of the parent message at the time of
    *   processing.)
    * - Newsgroups.  Same deal as mailing lists.
    */
-  * process(aGlodaMessage, aRawReps, aIsNew, aCallbackHandle) {
+  process: function* gloda_fundattr_process(aGlodaMessage, aRawReps,
+                                            aIsNew, aCallbackHandle) {
     let aMsgHdr = aRawReps.header;
     let aMimeMsg = aRawReps.mime;
 
     // -- From
     // Let's use replyTo if available.
     // er, since we are just dealing with mailing lists for now, forget the
     //  reply-to...
     // TODO: deal with default charset issues
@@ -575,17 +577,18 @@ var GlodaFundAttr = {
     // TODO: deal with mailing lists, including implicit-to.  this will require
     //  convincing the indexer to pass us in the previous message if it is
     //  available.  (which we'll simply pass to everyone... it can help body
     //  logic for quoting purposes, etc. too.)
 
     yield Gloda.kWorkDone;
   },
 
-  glodaAttFromMimeAtt(aGlodaMessage, aAtt) {
+  glodaAttFromMimeAtt:
+      function gloda_fundattr_glodaAttFromMimeAtt(aGlodaMessage, aAtt) {
     // So we don't want to store the URL because it can change over time if
     // the message is moved. What we do is store the full URL if it's a
     // detached attachment, otherwise just keep the part information, and
     // rebuild the URL according to where the message is sitting.
     let part, externalUrl;
     if (aAtt.isExternal) {
       externalUrl = aAtt.url;
     } else {
@@ -599,17 +602,19 @@ var GlodaFundAttr = {
                                aAtt.name,
                                aAtt.contentType,
                                aAtt.size,
                                part,
                                externalUrl,
                                aAtt.isExternal);
   },
 
-  * optimize(aGlodaMessage, aRawReps, aIsNew, aCallbackHandle) {
+  optimize: function* gloda_fundattr_optimize(aGlodaMessage, aRawReps,
+                                              aIsNew, aCallbackHandle) {
+
     let aMsgHdr = aRawReps.header;
 
     // for simplicity this is used for both involves and recipients
     let involvesIdentities = {};
     let involves = aGlodaMessage.involves || [];
     let recipients = aGlodaMessage.recipients || [];
 
     // 'me' specialization optimizations
@@ -623,24 +628,24 @@ var GlodaFundAttr = {
     // The fulltext search column for the author.  We want to have in here:
     // - The e-mail address and display name as enclosed on the message.
     // - The name per the address book card for this e-mail address, if we have
     //   one.
     aGlodaMessage._indexAuthor = aMsgHdr.mime2DecodedAuthor;
     // The fulltext search column for the recipients. (same deal)
     aGlodaMessage._indexRecipients = aMsgHdr.mime2DecodedRecipients;
 
-    if (isFromMe) {
+    if (isFromMe)
       aGlodaMessage.notability += this.NOTABILITY_FROM_ME;
-    } else {
+    else {
       let authorCard = authorIdentity.abCard;
       if (authorCard) {
         aGlodaMessage.notability += this.NOTABILITY_FROM_IN_ADDR_BOOK;
         // @testpoint gloda.noun.message.attr.authorMatches
-        aGlodaMessage._indexAuthor += " " + authorCard.displayName;
+        aGlodaMessage._indexAuthor += ' ' + authorCard.displayName;
       }
     }
 
     involves.push(authorIdentity);
     involvesIdentities[authorIdentity.id] = true;
 
     let involvedAddrBookCount = 0;
 
@@ -648,17 +653,17 @@ var GlodaFundAttr = {
       if (!(toIdentity.id in involvesIdentities)) {
         involves.push(toIdentity);
         recipients.push(toIdentity);
         involvesIdentities[toIdentity.id] = true;
         let toCard = toIdentity.abCard;
         if (toCard) {
           involvedAddrBookCount++;
           // @testpoint gloda.noun.message.attr.recipientsMatch
-          aGlodaMessage._indexRecipients += " " + toCard.displayName;
+          aGlodaMessage._indexRecipients += ' ' + toCard.displayName;
         }
       }
 
       // optimization attribute to-me ('I' am the parameter)
       if (toIdentity.id in myIdentities) {
         toMe.push([toIdentity, authorIdentity]);
         if (aIsNew)
           authorIdentity.contact.popularity += this.POPULARITY_TO_ME;
@@ -675,17 +680,17 @@ var GlodaFundAttr = {
       if (!(ccIdentity.id in involvesIdentities)) {
         involves.push(ccIdentity);
         recipients.push(ccIdentity);
         involvesIdentities[ccIdentity.id] = true;
         let ccCard = ccIdentity.abCard;
         if (ccCard) {
           involvedAddrBookCount++;
           // @testpoint gloda.noun.message.attr.recipientsMatch
-          aGlodaMessage._indexRecipients += " " + ccCard.displayName;
+          aGlodaMessage._indexRecipients += ' ' + ccCard.displayName;
         }
       }
       // optimization attribute cc-me ('I' am the parameter)
       if (ccIdentity.id in myIdentities) {
         toMe.push([ccIdentity, authorIdentity]);
         if (aIsNew)
           authorIdentity.contact.popularity += this.POPULARITY_CC_ME;
       }
@@ -703,17 +708,17 @@ var GlodaFundAttr = {
       if (!(bccIdentity.id in involvesIdentities)) {
         involves.push(bccIdentity);
         recipients.push(bccIdentity);
         involvesIdentities[bccIdentity.id] = true;
         let bccCard = bccIdentity.abCard;
         if (bccCard) {
           involvedAddrBookCount++;
           // @testpoint gloda.noun.message.attr.recipientsMatch
-          aGlodaMessage._indexRecipients += " " + bccCard.displayName;
+          aGlodaMessage._indexRecipients += ' ' + bccCard.displayName;
         }
       }
       // optimization attribute cc-me ('I' am the parameter)
       if (bccIdentity.id in myIdentities) {
         toMe.push([bccIdentity, authorIdentity]);
         if (aIsNew)
           authorIdentity.contact.popularity += this.POPULARITY_BCC_ME;
       }
@@ -740,29 +745,30 @@ var GlodaFundAttr = {
       aGlodaMessage.fromMe = fromMe;
 
     // Content
     if (aRawReps.bodyLines) {
       aGlodaMessage._content = aRawReps.content = new GlodaContent();
       if (this.contentWhittle({}, aRawReps.bodyLines, aGlodaMessage._content)) {
         // we were going to do something here?
       }
-    } else {
+    }
+    else {
       aRawReps.content = null;
     }
 
     yield Gloda.kWorkDone;
   },
 
   /**
    * Duplicates the notability logic from optimize().  Arguably optimize should
    *  be factored to call us, grokNounItem should be factored to call us, or we
    *  should get sufficiently fancy that our code wildly diverges.
    */
-  score(aMessage, aContext) {
+  score: function gloda_fundattr_score(aMessage, aContext) {
     let score = 0;
 
     let authorIdentity = aMessage.from;
     if (authorIdentity.id in Gloda.myIdentities)
       score += this.NOTABILITY_FROM_ME;
     else if (authorIdentity.inAddressBook)
       score += this.NOTABILITY_FROM_IN_ADDR_BOOK;
     if (aMessage.toMe)
@@ -776,41 +782,46 @@ var GlodaFundAttr = {
       if (identity.inAddressBook)
         involvedAddrBookCount++;
     if (involvedAddrBookCount)
       score += this.NOTABILITY_INVOLVING_ADDR_BOOK_FIRST +
         (involvedAddrBookCount - 1) * this.NOTABILITY_INVOLVING_ADDR_BOOK_ADDL;
     return score;
   },
 
-  _countQuoteDepthAndNormalize(aLine) {
+  _countQuoteDepthAndNormalize:
+    function gloda_fundattr__countQuoteDepthAndNormalize(aLine) {
     let count = 0;
     let lastStartOffset = 0;
 
     for (let i = 0; i < aLine.length; i++) {
       let c = aLine[i];
       if (c == ">") {
         count++;
-        lastStartOffset = i + 1;
-      } else if (c != " ") {
+        lastStartOffset = i+1;
+      }
+      else if (c == " ") {
+      }
+      else {
         return [count,
                 lastStartOffset ? aLine.substring(lastStartOffset) : aLine];
       }
     }
 
     return [count, lastStartOffset ? aLine.substring(lastStartOffset) : aLine];
   },
 
   /**
    * Attempt to understand simple quoting constructs that use ">" with
    * obvious phrases to enter the quoting block.  No support for other types
    * of quoting at this time.  Also no support for piercing the wrapper of
    * forwarded messages to actually be the content of the forwarded message.
    */
-  contentWhittle(aMeta, aBodyLines, aContent) {
+  contentWhittle: function gloda_fundattr_contentWhittle(aMeta,
+      aBodyLines, aContent) {
     if (!aContent.volunteerContent(aContent.kPriorityBase))
       return false;
 
     // duplicate the list; we mutate somewhat...
     let bodyLines = aBodyLines.concat();
 
     // lastNonBlankLine originally was just for detecting quoting idioms where
     //  the "wrote" line was separated from the quoted block by a blank line.
@@ -841,45 +852,50 @@ var GlodaFundAttr = {
               //  be the new lastNonBlankLine for the next logic block
               lastNonBlankLine = prevLastNonBlankLine;
             }
             // eat the trailing whitespace...
             if (lastNonBlankLine != null)
               rangeEnd = Math.min(rangeEnd, lastNonBlankLine);
           }
           if (rangeEnd >= rangeStart)
-            aContent.content(aBodyLines.slice(rangeStart, rangeEnd + 1));
+            aContent.content(aBodyLines.slice(rangeStart, rangeEnd+1));
 
           [inQuoteDepth, line] = this._countQuoteDepthAndNormalize(line);
           bodyLines[iLine] = line;
           rangeStart = quoteRangeStart;
-        } else {
+        }
+        else {
           let curQuoteDepth;
           [curQuoteDepth, line] = this._countQuoteDepthAndNormalize(line);
           bodyLines[iLine] = line;
 
           if (curQuoteDepth != inQuoteDepth) {
             // we could do some "wrote" compensation here, but it's not really
             //  as important.  let's wait for a more clever algorithm.
             aContent.quoted(aBodyLines.slice(rangeStart, iLine), inQuoteDepth);
             inQuoteDepth = curQuoteDepth;
             rangeStart = iLine;
           }
         }
-      } else if (inQuoteDepth) {
-        aContent.quoted(aBodyLines.slice(rangeStart, iLine), inQuoteDepth);
-        inQuoteDepth = 0;
-        rangeStart = iLine;
+      }
+      else {
+        if (inQuoteDepth) {
+          aContent.quoted(aBodyLines.slice(rangeStart, iLine), inQuoteDepth);
+          inQuoteDepth = 0;
+          rangeStart = iLine;
+        }
       }
 
       prevLastNonBlankLine = lastNonBlankLine;
       lastNonBlankLine = iLine;
     }
 
     if (inQuoteDepth) {
       aContent.quoted(aBodyLines.slice(rangeStart), inQuoteDepth);
-    } else {
-      aContent.content(aBodyLines.slice(rangeStart, lastNonBlankLine + 1));
+    }
+    else {
+      aContent.content(aBodyLines.slice(rangeStart, lastNonBlankLine+1));
     }
 
     return true;
   },
 };
--- a/mailnews/db/gloda/modules/gloda.js
+++ b/mailnews/db/gloda/modules/gloda.js
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-this.EXPORTED_SYMBOLS = ["Gloda"];
+this.EXPORTED_SYMBOLS = ['Gloda'];
 
 const {Log4Moz} = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
 
 const {GlodaDatastore} = ChromeUtils.import("resource:///modules/gloda/datastore.js");
 const {
   GlodaAttributeDBDef,
   GlodaAccount,
   GlodaConversation,
@@ -30,19 +30,19 @@ const {MailServices} = ChromeUtils.impor
 
 /**
  * @see |Gloda.BadItemContentsError|
  */
 function BadItemContentsError(aMessage) {
   this.message = aMessage;
 }
 BadItemContentsError.prototype = {
-  toString() {
+  toString: function BadItemContentsError_toString() {
     return this.message;
-  },
+  }
 };
 
 
 /**
  * Provides the user-visible (and extension visible) global database
  *  functionality.  There is currently a dependency/ordering
  *  problem in that the concept of 'gloda' also includes some logic that is
  *  contributed by built-in extensions, if you will.  Those built-in extensions
@@ -135,29 +135,29 @@ var Gloda = {
    * Initialize logging, the datastore (SQLite database), the core nouns and
    *  attributes, and the contact and identities that belong to the presumed
    *  current user (based on accounts).
    *
    * Additional nouns and the core attribute providers are initialized by the
    *  everybody.js module which ensures all of those dependencies are loaded
    *  (and initialized).
    */
-  _init() {
+  _init: function gloda_ns_init() {
     this._initLogging();
     GlodaDatastore._init(this._nounIDToDef);
     this._initAttributes();
     this._initMyIdentities();
   },
 
   _log: null,
   /**
    * Initialize logging; the error console window gets Warning/Error, and stdout
    *  (via dump) gets everything.
    */
-  _initLogging() {
+  _initLogging: function gloda_ns_initLogging() {
     let formatter = new Log4Moz.BasicFormatter();
     Log4Moz.repository.rootLogger.level = Log4Moz.Level.Debug;
 
     let enableConsoleLogging = false;
     let enableDumpLogging = false;
     // should we assume there is someone else consuming our log4moz stream?
     let enableUpstreamLogging = false;
     let considerNetLogging = false;
@@ -280,17 +280,18 @@ var Gloda = {
    * @param aListener The listener that should be registered with the collection
    * @param aData The (optional) value to set as the data attribute on the
    *     collection.
    *
    * @return The collection that will receive the results.
    *
    * @testpoint gloda.ns.getMessageCollectionForHeader()
    */
-  getMessageCollectionForHeader(aMsgHdr, aListener, aData) {
+  getMessageCollectionForHeader: function gloda_ns_getMessageForHeader(aMsgHdr,
+      aListener, aData) {
     let query = Gloda.newQuery(Gloda.NOUN_MESSAGE);
     query.folder(aMsgHdr.folder).messageKey(aMsgHdr.messageKey);
     return query.getCollection(aListener, aData);
   },
 
   /**
    * Given a list of message headers, return a collection containing the gloda
    *  messages that correspond to those headers.  Keep in mind that gloda may
@@ -305,19 +306,21 @@ var Gloda = {
    * @param aListener The listener that should be registered with the collection
    * @param aData The (optional) value to set as the data attribute on the
    *     collection.
    *
    * @return The collection that will receive the results.
    *
    * @testpoint gloda.ns.getMessageCollectionForHeaders()
    */
-  getMessageCollectionForHeaders(aHeaders, aListener, aData) {
+  getMessageCollectionForHeaders: function gloda_ns_getMessagesForHeaders(
+      aHeaders, aListener, aData) {
     // group the headers by the folder they are found in
     let headersByFolder = {};
+    let iter;
     for (let header of fixIterator(aHeaders)) {
       let folderURI = header.folder.URI;
       let headersForFolder = headersByFolder[folderURI];
       if (headersForFolder === undefined)
         headersByFolder[folderURI] = [header];
       else
         headersForFolder.push(header);
     }
@@ -340,21 +343,21 @@ var Gloda = {
     }
 
     return query.getCollection(aListener, aData);
   },
 
   /**
    * @testpoint gloda.ns.getMessageContent
    */
-  getMessageContent(aGlodaMessage, aMimeMsg) {
+  getMessageContent: function gloda_ns_getMessageContent(aGlodaMessage, aMimeMsg) {
     return mimeMsgToContentAndMeta(aMimeMsg, aGlodaMessage.folderMessage.folder)[0];
   },
 
-  getFolderForFolder(aMsgFolder) {
+  getFolderForFolder: function gloda_ns_getFolderForFolder(aMsgFolder) {
     return GlodaDatastore._mapFolder(aMsgFolder);
   },
 
   /**
    * Takes one or more strings containing lists of comma-delimited e-mail
    *  addresses with optional display names, and returns a list of sub-lists of
    *  identities, where each sub-list corresponds to each of the strings passed
    *  as arguments.  These identities are loaded from the database if they
@@ -376,27 +379,29 @@ var Gloda = {
    *   they should be comma-delimited.  For example
    *   '"Bob Smith" <bob@example.com>' is an address with display name.  Mime
    *   header decoding is performed, but is ignorant of any folder-level
    *   character set overrides.
    * @returns via the callback handle mechanism, a list containing one sub-list
    *   for each string argument passed.  Each sub-list contains zero or more
    *   GlodaIdentity instances corresponding to the addresses provided.
    */
-  * getOrCreateMailIdentities(aCallbackHandle, ...aAddrGroups) {
+  getOrCreateMailIdentities:
+      function* gloda_ns_getOrCreateMailIdentities(aCallbackHandle, ...aAddrGroups) {
     let addresses = {};
     let resultLists = [];
 
     // parse the strings
     for (let aMailAddresses of aAddrGroups) {
       let parsed = GlodaUtils.parseMailAddresses(aMailAddresses);
 
       let resultList = [];
       resultLists.push(resultList);
 
+      let identities = [];
       for (let iAddress = 0; iAddress < parsed.count; iAddress++) {
         let address = parsed.addresses[iAddress].toLowerCase();
         if (address in addresses)
           addresses[address].push(resultList);
         else
           addresses[address] = [parsed.names[iAddress], resultList];
       }
     }
@@ -462,17 +467,18 @@ var Gloda = {
       let identity = GlodaDatastore.createIdentity(contact.id, contact,
         "email", address, /* description */ "", /* relay? */ false);
       contact._identities = [identity];
 
       // give the address book indexer a chance if we have a card.
       // (it will fix-up the name based on the card as appropriate)
       if (card)
         yield aCallbackHandle.pushAndGo(
-          Gloda.grokNounItem(contact, {card}, true, true, aCallbackHandle));
+          Gloda.grokNounItem(contact, {card: card}, true, true,
+                             aCallbackHandle));
       else // grokNounItem will issue the insert for us...
         GlodaDatastore.insertContact(contact);
 
       for (let iResList = 1; iResList < nameAndResultLists.length; iResList++) {
         nameAndResultLists[iResList].push(identity);
       }
     }
 
@@ -808,17 +814,17 @@ var Gloda = {
   _nounNameToNounID: {},
   /**
    * Maps noun IDs to noun definition dictionaries.  (Noun definition
    *  dictionaries provided to us at the time a noun was defined, plus some
    *  additional stuff we put in there.)
    */
   _nounIDToDef: {},
 
-  _managedToJSON(aItem) {
+  _managedToJSON: function gloda_ns_managedToJSON(aItem) {
     return aItem.id;
   },
 
   /**
    * Define a noun.  Takes a dictionary with the following keys/values:
    *
    * @param aNounDef.name The name of the noun.  This is not a display name
    *     (anything being displayed needs to be localized, after all), but simply
@@ -869,17 +875,17 @@ var Gloda = {
    *       how the attributes are poked into your object (for example, you want
    *       underscores used for some of them because the attributes should be
    *       immutable), then you can include a third string that is the name of
    *       the attribute to use.
    *     - indices A dictionary of lists of column names, where the key name
    *       becomes the index name.  Ex: {foo: ["bar"]} results in an index on
    *       the column "bar" where the index is named "foo".
   */
-  defineNoun(aNounDef, aNounID) {
+  defineNoun: function gloda_ns_defineNoun(aNounDef, aNounID) {
     this._log.info("Defining noun: " + aNounDef.name);
     if (aNounID === undefined)
       aNounID = this._nextNounID++;
     aNounDef.id = aNounID;
 
     // Let people whose editors get angry about illegal attribute names use
     //  clazz instead of class.
     if (aNounDef.clazz)
@@ -903,21 +909,21 @@ var Gloda = {
           aNounDef.tableName = "ext_" + aNounDef.schema.name;
         else
           aNounDef.tableName = "ext_" + aNounDef.name;
       }
       // this creates the data table and binder and hooks everything up
       GlodaDatastore.createNounTable(aNounDef);
 
       if (!aNounDef.toParamAndValue)
-        aNounDef.toParamAndValue = function(aThing) {
+        aNounDef.toParamAndValue = function (aThing) {
           if (aThing instanceof aNounDef.class)
             return [null, aThing.id];
-          // assume they're just passing the id directly
-          return [null, aThing];
+          else // assume they're just passing the id directly
+            return [null, aThing];
         };
     }
 
     // if it has a table, you can query on it.  seems straight-forward.
     if (aNounDef.tableName) {
       [aNounDef.queryClass, aNounDef.nullQueryClass,
        aNounDef.explicitQueryClass, aNounDef.wildcardQueryClass] =
           GlodaQueryClassFactory(aNounDef);
@@ -959,29 +965,29 @@ var Gloda = {
     return aNounDef;
   },
 
   /**
    * Lookup a noun (ID) suitable for passing to defineAttribute's various
    *  noun arguments.  Throws an exception if the noun with the given name
    *  cannot be found; the assumption is that you can't live without the noun.
    */
-  lookupNoun(aNounName) {
+  lookupNoun: function gloda_ns_lookupNoun(aNounName) {
     if (aNounName in this._nounNameToNounID)
       return this._nounNameToNounID[aNounName];
 
     throw Error("Unable to locate noun with name '" + aNounName + "', but I " +
                 "do know about: " +
                 Object.keys(this._nounNameToNounID).join(", "));
   },
 
   /**
    * Lookup a noun def given a name.
    */
-  lookupNounDef(aNounName) {
+  lookupNounDef: function gloda_ns_lookupNoun(aNounName) {
     return this._nounIDToDef[this.lookupNoun(aNounName)];
   },
 
 
   /**
    * Define an action on a noun.  During the prototype stage, this was conceived
    *  of as a way to expose all the constraints possible given a noun.  For
    *  example, if you have an identity or a contact, you could use this to
@@ -1014,26 +1020,26 @@ var Gloda = {
    *   example, a checkbox-heavy UI might display a checkbox for each constraint
    *   using shortName as the label.
    * - makeConstraint: A function that takes the attribute that is the source
    *   of the noun and the noun instance as arguments, and returns APV-style
    *   constraints.  Since the APV-style query mechanism is now deprecated,
    *   this signature is deprecated.  Probably the way to update this would be
    *   to pass in the query instance that constraints should be contributed to.
    */
-  defineNounAction(aNounID, aActionMeta) {
+  defineNounAction: function gloda_ns_defineNounAction(aNounID, aActionMeta) {
     let nounDef = this._nounIDToDef[aNounID];
     nounDef.actions.push(aActionMeta);
   },
 
   /**
    * Retrieve all of the actions (as defined using defineNounAction) for the
    *  given noun type (via noun ID) with the given action type (ex: filter).
    */
-  getNounActions(aNounID, aActionType) {
+  getNounActions: function gloda_ns_getNounActions(aNounID, aActionType) {
     let nounDef = this._nounIDToDef[aNounID];
     if (!nounDef)
       return [];
     return nounDef.actions.
       filter(action => !aActionType || (action.actionType == aActionType));
   },
 
   /** Attribute providers in the sequence to process them. */
@@ -1054,96 +1060,104 @@ var Gloda = {
    *  issues are resolved via the everybody.js mechanism or something else.
    *  Right now, noun_tag defines the tag noun.  If we broke more of these out,
    *  we would probably want to move the 'class' code from datamodel.js, the
    *  SQL table def and helper code from datastore.js (and this code) to their
    *  own noun_*.js files.  There are some trade-offs to be made, and I think
    *  we can deal with those once we start to integrate lightning/calendar and
    *  our noun space gets large and more heterogeneous.
    */
-  _initAttributes() {
+  _initAttributes: function gloda_ns_initAttributes() {
     this.defineNoun({
       name: "bool",
       clazz: Boolean, allowsArbitraryAttrs: false,
       isPrimitive: true,
       // favor true before false
-      comparator(a, b) {
+      comparator: function gloda_bool_comparator(a, b) {
         if (a == null) {
           if (b == null)
             return 0;
-          return 1;
-        } else if (b == null) {
+          else
+            return 1;
+        }
+        else if (b == null) {
           return -1;
         }
         return b - a;
       },
-      toParamAndValue(aBool) {
+      toParamAndValue: function(aBool) {
         return [null, aBool ? 1 : 0];
       }}, this.NOUN_BOOLEAN);
     this.defineNoun({
       name: "number",
       clazz: Number, allowsArbitraryAttrs: false, continuous: true,
       isPrimitive: true,
-      comparator(a, b) {
+      comparator: function gloda_number_comparator(a, b) {
         if (a == null) {
           if (b == null)
             return 0;
-          return 1;
-        } else if (b == null) {
+          else
+            return 1;
+        }
+        else if (b == null) {
           return -1;
         }
         return a - b;
       },
-      toParamAndValue(aNum) {
+      toParamAndValue: function(aNum) {
         return [null, aNum];
       }}, this.NOUN_NUMBER);
     this.defineNoun({
       name: "string",
       clazz: String, allowsArbitraryAttrs: false,
       isPrimitive: true,
-      comparator(a, b) {
+      comparator: function gloda_string_comparator(a, b) {
         if (a == null) {
           if (b == null)
             return 0;
-          return 1;
-        } else if (b == null) {
+          else
+            return 1;
+        }
+        else if (b == null) {
           return -1;
         }
         return a.localeCompare(b);
       },
-      toParamAndValue(aString) {
+      toParamAndValue: function(aString) {
         return [null, aString];
       }}, this.NOUN_STRING);
     this.defineNoun({
       name: "date",
       clazz: Date, allowsArbitraryAttrs: false, continuous: true,
       isPrimitive: true,
-      comparator(a, b) {
+      comparator: function gloda_data_comparator(a, b) {
         if (a == null) {
           if (b == null)
             return 0;
-          return 1;
-        } else if (b == null) {
+          else
+            return 1;
+        }
+        else if (b == null) {
           return -1;
         }
         return a - b;
       },
-      toParamAndValue(aDate) {
+      toParamAndValue: function(aDate) {
         return [null, aDate.valueOf() * 1000];
       }}, this.NOUN_DATE);
     this.defineNoun({
       name: "fulltext",
       clazz: String, allowsArbitraryAttrs: false, continuous: false,
       isPrimitive: true,
-      comparator(a, b) {
+      comparator: function gloda_fulltext_comparator(a, b) {
         throw new Error("Fulltext nouns are not comparable!");
       },
       // as noted on NOUN_FULLTEXT, we just pass the string around.  it never
       //  hits the database, so it's okay.
-      toParamAndValue(aString) {
+      toParamAndValue: function(aString) {
         return [null, aString];
       }}, this.NOUN_FULLTEXT);
 
     this.defineNoun({
       name: "folder",
       clazz: GlodaFolder,
       allowsArbitraryAttrs: false,
       isPrimitive: false,
@@ -1154,17 +1168,17 @@ var Gloda = {
          *  the list of folders that match if gloda would index them.  This is
          *  unsuitable for producing a persistable constraint since it does not
          *  adapt for added/deleted folders.  However, it is sufficient for
          *  faceting.  Also, we don't persist constraints yet.
          *
          * @TODO The long-term solution is to move towards using arithmetic
          *     encoding on folder-id's like we use for MIME types and friends.
          */
-        Account(aAttrDef, aArguments) {
+        Account: function(aAttrDef, aArguments) {
           let folderValues = [];
           let seenRootFolders = {};
           for (let iArg = 0; iArg < aArguments.length; iArg++) {
             let givenFolder = aArguments[iArg];
             let givenMsgFolder = givenFolder.getXPCOMFolder(
                                    givenFolder.kActivityFolderOnlyNoData);
             let rootFolder = givenMsgFolder.rootFolder;
 
@@ -1189,80 +1203,87 @@ var Gloda = {
                 !(folder instanceof Ci.nsIMsgImapMailFolder))
                 continue;
 
               let glodaFolder = Gloda.getFolderForFolder(folder);
               folderValues.push(glodaFolder);
             }
           }
           return this._inConstraintHelper(aAttrDef, folderValues);
-        },
+        }
       },
-      comparator(a, b) {
+      comparator: function gloda_folder_comparator(a, b) {
         if (a == null) {
           if (b == null)
             return 0;
-          return 1;
-        } else if (b == null) {
+          else
+            return 1;
+        }
+        else if (b == null) {
           return -1;
         }
         return a.name.localeCompare(b.name);
       },
-      toParamAndValue(aFolderOrGlodaFolder) {
+      toParamAndValue: function(aFolderOrGlodaFolder) {
         if (aFolderOrGlodaFolder instanceof GlodaFolder)
           return [null, aFolderOrGlodaFolder.id];
-        return [null, GlodaDatastore._mapFolder(aFolderOrGlodaFolder).id];
+        else
+          return [null, GlodaDatastore._mapFolder(aFolderOrGlodaFolder).id];
       }}, this.NOUN_FOLDER);
     this.defineNoun({
       name: "account",
       clazz: GlodaAccount,
       allowsArbitraryAttrs: false,
       isPrimitive: false,
-      equals(a, b) {
+      equals: function(a, b) {
         if (a && !b || !a && b)
           return false;
         if (!a && !b)
           return true;
         return a.id == b.id;
       },
-      comparator(a, b) {
+      comparator: function gloda_account_comparator(a, b) {
         if (a == null) {
           if (b == null)
             return 0;
-          return 1;
-        } else if (b == null) {
+          else
+            return 1;
+        }
+        else if (b == null) {
           return -1;
         }
         return a.name.localeCompare(b.name);
       }}, this.NOUN_ACCOUNT);
     this.defineNoun({
       name: "conversation",
       clazz: GlodaConversation,
       allowsArbitraryAttrs: false,
       isPrimitive: false,
       cache: true, cacheCost: 512,
       tableName: "conversations",
       attrTableName: "messageAttributes", attrIDColumnName: "conversationID",
       datastore: GlodaDatastore,
       objFromRow: GlodaDatastore._conversationFromRow,
-      comparator(a, b) {
+      comparator: function gloda_conversation_comparator(a, b) {
         if (a == null) {
           if (b == null)
             return 0;
-          return 1;
-        } else if (b == null) {
+          else
+            return 1;
+        }
+        else if (b == null) {
           return -1;
         }
         return a.subject.localeCompare(b.subject);
       },
-      toParamAndValue(aConversation) {
+      toParamAndValue: function(aConversation) {
         if (aConversation instanceof GlodaConversation)
           return [null, aConversation.id];
-        // assume they're just passing the id directly
-        return [null, aConversation];
+        else // assume they're just passing the id directly
+          return [null, aConversation];
       }}, this.NOUN_CONVERSATION);
     this.defineNoun({
       name: "message",
       clazz: GlodaMessage,
       allowsArbitraryAttrs: true,
       isPrimitive: false,
       cache: true, cacheCost: 2048,
       tableName: "messages",
@@ -1276,134 +1297,140 @@ var Gloda = {
       dbQueryValidityConstraintSuffix:
         " AND +deleted = 0 AND +folderID IS NOT NULL AND +messageKey IS NOT NULL",
       // This is what's used when we have no validity constraints, i.e. we allow
       // for ghost messages, which do not have a row in the messagesText table.
       dbQueryJoinMagicWithNoValidityConstraints:
         " LEFT JOIN messagesText ON messages.id = messagesText.rowid",
       objInsert: GlodaDatastore.insertMessage,
       objUpdate: GlodaDatastore.updateMessage,
-      toParamAndValue(aMessage) {
+      toParamAndValue: function(aMessage) {
         if (aMessage instanceof GlodaMessage)
           return [null, aMessage.id];
-        // assume they're just passing the id directly
-        return [null, aMessage];
+        else // assume they're just passing the id directly
+          return [null, aMessage];
       }}, this.NOUN_MESSAGE);
     this.defineNoun({
       name: "contact",
       clazz: GlodaContact,
       allowsArbitraryAttrs: true,
       isPrimitive: false,
       cache: true, cacheCost: 128,
       tableName: "contacts",
       attrTableName: "contactAttributes", attrIDColumnName: "contactID",
       datastore: GlodaDatastore, objFromRow: GlodaDatastore._contactFromRow,
       dbAttribAdjuster: GlodaDatastore.adjustAttributes,
       objInsert: GlodaDatastore.insertContact,
       objUpdate: GlodaDatastore.updateContact,
-      comparator(a, b) {
+      comparator: function gloda_contact_comparator(a, b) {
         if (a == null) {
           if (b == null)
             return 0;
-          return 1;
-        } else if (b == null) {
+          else
+            return 1;
+        }
+        else if (b == null) {
           return -1;
         }
         return a.name.localeCompare(b.name);
       },
-      toParamAndValue(aContact) {
+      toParamAndValue: function(aContact) {
         if (aContact instanceof GlodaContact)
           return [null, aContact.id];
-        // assume they're just passing the id directly
-        return [null, aContact];
+        else // assume they're just passing the id directly
+          return [null, aContact];
       }}, this.NOUN_CONTACT);
     this.defineNoun({
       name: "identity",
       clazz: GlodaIdentity,
       allowsArbitraryAttrs: false,
       isPrimitive: false,
       cache: true, cacheCost: 128,
       usesUniqueValue: true,
       tableName: "identities",
       datastore: GlodaDatastore, objFromRow: GlodaDatastore._identityFromRow,
       /**
        * Short string is the contact name, long string includes the identity
        *  value too, delimited by a colon.  Not tremendously localizable.
        */
-      userVisibleString(aIdentity, aLong) {
+      userVisibleString: function(aIdentity, aLong) {
         if (!aLong)
           return aIdentity.contact.name;
         if (aIdentity.contact.name == aIdentity.value)
           return aIdentity.value;
         return aIdentity.contact.name + " (" + aIdentity.value + ")";
       },
-      comparator(a, b) {
+      comparator: function gloda_identity_comparator(a, b) {
         if (a == null) {
           if (b == null)
             return 0;
-          return 1;
-        } else if (b == null) {
+          else
+            return 1;
+        }
+        else if (b == null) {
           return -1;
         }
         return a.contact.name.localeCompare(b.contact.name);
       },
-      toParamAndValue(aIdentity) {
+      toParamAndValue: function(aIdentity) {
         if (aIdentity instanceof GlodaIdentity)
           return [null, aIdentity.id];
-        // assume they're just passing the id directly
-        return [null, aIdentity];
+        else // assume they're just passing the id directly
+          return [null, aIdentity];
       }}, this.NOUN_IDENTITY);
     this.defineNoun({
       name: "attachment-infos",
       clazz: GlodaAttachment,
       allowsArbitraryAttrs: false,
       isPrimitive: false,
-      toJSON(x) {
+      toJSON: function (x) {
           return [
             x._name,
             x._contentType,
             x._size,
             x._part,
             x._externalUrl,
-            x._isExternal,
-          ];
+            x._isExternal
+          ]
         },
-      fromJSON(x, aGlodaMessage) {
+      fromJSON: function (x, aGlodaMessage) {
           let [name, contentType, size, _part, _externalUrl, isExternal] = x;
           return new GlodaAttachment(aGlodaMessage, name, contentType, size, _part, _externalUrl, isExternal);
         },
       }, this.NOUN_ATTACHMENT);
 
     // parameterized identity is just two identities; we store the first one
     //  (whose value set must be very constrainted, like the 'me' identities)
     //  as the parameter, the second (which does not need to be constrained)
     //  as the value.
     this.defineNoun({
       name: "parameterized-identity",
       clazz: null,
       allowsArbitraryAttrs: false,
-      comparator(a, b) {
+      comparator: function gloda_fulltext_comparator(a, b) {
         if (a == null) {
           if (b == null)
             return 0;
-          return 1;
-        } else if (b == null) {
+          else
+            return 1;
+        }
+        else if (b == null) {
           return -1;
         }
         // First sort by the first identity in the tuple
         // Since our general use-case is for the first guy to be "me", we only
         //  compare the identity value, not the name.
         let fic = a[0].value.localeCompare(b[0].value);
         if (fic)
           return fic;
         // Next compare the second identity in the tuple, but use the contact
         //  this time to be consistent with our identity comparator.
         return a[1].contact.name.localeCompare(b[1].contact.name);
       },
-      computeDelta(aCurValues, aOldValues) {
+      computeDelta: function(aCurValues, aOldValues) {
         let oldMap = {};
         for (let tupe of aOldValues) {
           let [originIdentity, targetIdentity] = tupe;
           let targets = oldMap[originIdentity];
           if (targets === undefined)
             targets = oldMap[originIdentity] = {};
           targets[targetIdentity] = true;
         }
@@ -1422,17 +1449,17 @@ var Gloda = {
           let targets = oldMap[originIdentity];
           for (let targetIdentity in targets) {
             removed.push([originIdentity, targetIdentity]);
           }
         }
 
         return [added, removed];
       },
-      contributeObjDependencies(aJsonValues, aReferencesByNounID,
+      contributeObjDependencies: function(aJsonValues, aReferencesByNounID,
           aInverseReferencesByNounID) {
         // nothing to do with a zero-length list
         if (aJsonValues.length == 0)
           return false;
 
         let nounIdentityDef = Gloda._nounIDToDef[Gloda.NOUN_IDENTITY];
         let references = aReferencesByNounID[nounIdentityDef.id];
         if (references === undefined)
@@ -1443,77 +1470,78 @@ var Gloda = {
           if (!(originIdentityID in references))
             references[originIdentityID] = null;
           if (!(targetIdentityID in references))
             references[targetIdentityID] = null;
         }
 
         return true;
       },
-      resolveObjDependencies(aJsonValues, aReferencesByNounID,
+      resolveObjDependencies: function(aJsonValues, aReferencesByNounID,
           aInverseReferencesByNounID) {
         let references =
           aReferencesByNounID[Gloda.NOUN_IDENTITY];
 
         let results = [];
         for (let tupe of aJsonValues) {
           let [originIdentityID, targetIdentityID] = tupe;
           results.push([references[originIdentityID],
                         references[targetIdentityID]]);
         }
 
         return results;
       },
-      toJSON(aIdentityTuple) {
+      toJSON: function (aIdentityTuple) {
         return [aIdentityTuple[0].id, aIdentityTuple[1].id];
       },
-      toParamAndValue(aIdentityTuple) {
+      toParamAndValue: function(aIdentityTuple) {
         return [aIdentityTuple[0].id, aIdentityTuple[1].id];
       }}, this.NOUN_PARAM_IDENTITY);
 
     GlodaDatastore.getAllAttributes();
   },
 
   /**
    * Create accessor functions to 'bind' an attribute to underlying normalized
    *  attribute storage, as well as creating the appropriate query object
    *  constraint helper functions.  This name is somewhat of a misnomer because
    *  special attributes are not 'bound' (because specific/non-generic per-class
    *  code provides the properties) but still depend on this method to
    *  establish their constraint helper methods.
    *
    * @XXX potentially rename to not suggest binding is required.
    */
-  _bindAttribute(aAttrDef, aSubjectNounDef) {
+  _bindAttribute: function gloda_ns_bindAttr(aAttrDef, aSubjectNounDef) {
     let objectNounDef = aAttrDef.objectNounDef;
 
     // -- the query constraint helpers
     if (aSubjectNounDef.queryClass !== undefined) {
       let constrainer;
       let canQuery = true;
       if (("special" in aAttrDef) && (aAttrDef.special == this.kSpecialFulltext)) {
         constrainer = function(...aArgs) {
           let constraint = [GlodaDatastore.kConstraintFulltext, aAttrDef, ...aArgs];
           this._constraints.push(constraint);
           return this;
         };
-      } else if (aAttrDef.canQuery || aAttrDef.attributeName.startsWith("_")) {
+      }
+      else if (aAttrDef.canQuery || aAttrDef.attributeName.startsWith("_")) {
         constrainer = function(...aArgs) {
           let constraint = [GlodaDatastore.kConstraintIn, aAttrDef, ...aArgs];
           this._constraints.push(constraint);
           return this;
         };
       } else {
         constrainer = function() {
           throw new Error(
-              "Cannot query on attribute " + aAttrDef.attributeName
+              "Cannot query on attribute "+aAttrDef.attributeName
             + " because its canQuery parameter hasn't been set to true."
             + " Reading the comments about Gloda.defineAttribute may be a"
             + " sensible thing to do now.");
-        };
+        }
         canQuery = false;
       }
 
       aSubjectNounDef.queryClass.prototype[aAttrDef.boundName] = constrainer;
 
       // Don't bind extra query-able attributes if we're unable to perform a
       // search on the attribute.
       if (!canQuery)
@@ -1619,17 +1647,17 @@ var Gloda = {
    *     NOUN_* constants or a dynamically registered noun type.
    * @param aAttrDef.objectNoun The object type (one of the NOUN_* constants or
    *     a dynamically registered noun types) that is the 'object' in the
    *     traditional RDF triple.  More pragmatically, in the database row used
    *     to represent an attribute, we store the subject (ex: message ID),
    *     attribute ID, and an integer which is the integer representation of the
    *     'object' whose type you are defining right here.
    */
-  defineAttribute(aAttrDef) {
+  defineAttribute: function gloda_ns_defineAttribute(aAttrDef) {
     // ensure required properties exist on aAttrDef
     if (!("provider" in aAttrDef) ||
         !("extensionName" in aAttrDef) ||
         !("attributeType" in aAttrDef) ||
         !("attributeName" in aAttrDef) ||
         !("singular" in aAttrDef) ||
         !("subjectNouns" in aAttrDef) ||
         !("objectNoun" in aAttrDef))
@@ -1638,17 +1666,17 @@ var Gloda = {
       throw Error("You omitted a required attribute defining property, please" +
                   " consult the documentation as penance.");
 
     // -- Fill in defaults
     if (!("emptySetIsSignificant" in aAttrDef))
       aAttrDef.emptySetIsSignificant = false;
 
     if (!("canQuery" in aAttrDef))
-      aAttrDef.canQuery = !!aAttrDef.facet;
+      aAttrDef.canQuery = aAttrDef.facet ? true : false;
 
     // return if the attribute has already been defined
     if (aAttrDef.dbDef)
       return aAttrDef;
 
     // - first time we've seen a provider init logic
     if (!(aAttrDef.provider.providerName in this._attrProviders)) {
       this._attrProviders[aAttrDef.provider.providerName] = [];
@@ -1660,17 +1688,19 @@ var Gloda = {
     // -- Database Definition
     let attrDBDef;
     if (compoundName in GlodaDatastore._attributeDBDefs) {
       // the existence of the GlodaAttributeDBDef means that either it has
       //  already been fully defined, or has been loaded from the database but
       //  not yet 'bound' to a provider (and had important meta-info that
       //  doesn't go in the db copied over)
       attrDBDef = GlodaDatastore._attributeDBDefs[compoundName];
-    } else { // we need to create the attribute definition in the database
+    }
+    // we need to create the attribute definition in the database
+    else {
       let attrID = null;
       attrID = GlodaDatastore._createAttributeDef(aAttrDef.attributeType,
                                                   aAttrDef.extensionName,
                                                   aAttrDef.attributeName,
                                                   null);
 
       attrDBDef = new GlodaAttributeDBDef(GlodaDatastore, attrID, compoundName,
         aAttrDef.attributeType, aAttrDef.extensionName, aAttrDef.attributeName);
@@ -1697,42 +1727,46 @@ var Gloda = {
         aFacetDef.groupIdAttr = aAttrDef.objectNounDef.idAttr;
       if (!("groupComparator" in aFacetDef))
         aFacetDef.groupComparator = aAttrDef.objectNounDef.comparator;
       if (!("filter" in aFacetDef))
         aFacetDef.filter = null;
     }
     // No facet attribute means no facet desired; set an explicit null so that
     //  code can check without doing an "in" check.
-    if (!("facet" in aAttrDef)) {
+    if (!("facet" in aAttrDef))
       aAttrDef.facet = null;
-    } else if (aAttrDef.facet) {
-      // Promote "true" facet values to the defaults.  Where attributes have
-      //  specified values, make sure we fill in any missing defaults.
-      aAttrDef.facet = {
-        type: "default",
-        groupIdAttr: aAttrDef.objectNounDef.idAttr,
-        groupComparator: aAttrDef.objectNounDef.comparator,
-        filter: null,
-      };
-    } else {
-      normalizeFacetDef(aAttrDef.facet);
+    // Promote "true" facet values to the defaults.  Where attributes have
+    //  specified values, make sure we fill in any missing defaults.
+    else {
+      if (aAttrDef.facet == true) {
+        aAttrDef.facet = {
+          type: "default",
+          groupIdAttr: aAttrDef.objectNounDef.idAttr,
+          groupComparator: aAttrDef.objectNounDef.comparator,
+          filter: null,
+        };
+      }
+      else {
+        normalizeFacetDef(aAttrDef.facet);
+      }
     }
     if ("extraFacets" in aAttrDef) {
       for (let facetDef of aAttrDef.extraFacets) {
         normalizeFacetDef(facetDef);
       }
     }
 
     function gatherLocalizedStrings(aBundle, aPropRoot, aStickIn) {
       for (let propName in Gloda._ATTR_LOCALIZED_STRINGS) {
         let attrName = Gloda._ATTR_LOCALIZED_STRINGS[propName];
         try {
           aStickIn[attrName] = aBundle.get(aPropRoot + propName);
-        } catch (ex) {
+        }
+        catch (ex) {
           // do nothing.  nsIStringBundle throws exceptions because it is a
           //  standard nsresult type of API and our helper buddy does nothing
           //  to help us.  (StringBundle.js, that is.)
         }
       }
     }
 
     // -- L10n.
@@ -1766,17 +1800,18 @@ var Gloda = {
     // -- Subject Noun Binding
     for (let iSubject = 0; iSubject < aAttrDef.subjectNouns.length;
            iSubject++) {
       let subjectType = aAttrDef.subjectNouns[iSubject];
       let subjectNounDef = this._nounIDToDef[subjectType];
       this._bindAttribute(aAttrDef, subjectNounDef);
 
       // update the provider maps...
-      if (!this._attrProviderOrderByNoun[subjectType].includes(aAttrDef.provider)) {
+      if (this._attrProviderOrderByNoun[subjectType]
+              .indexOf(aAttrDef.provider) == -1) {
         this._attrProviderOrderByNoun[subjectType].push(aAttrDef.provider);
         if (aAttrDef.provider.optimize)
           this._attrOptimizerOrderByNoun[subjectType].push(aAttrDef.provider);
         this._attrProvidersByNoun[subjectType][aAttrDef.provider.providerName] = [];
       }
       this._attrProvidersByNoun[subjectType][aAttrDef.provider.providerName].push(aAttrDef);
 
       subjectNounDef.attribsByBoundName[aAttrDef.boundName] = aAttrDef;
@@ -1808,17 +1843,17 @@ var Gloda = {
    * Retrieve the attribute provided by the given extension with the given
    *  attribute name.  The original idea was that plugins would effectively
    *  name-space attributes, helping avoid collisions.  Since we are leaning
    *  towards using binding heavily, this doesn't really help, as the collisions
    *  will just occur on the attribute name instead.  Also, this can turn
    *  extensions into liars as name changes/moves to core/etc. happen.
    * @TODO consider removing the extension name argument parameter requirement
    */
-  getAttrDef(aPluginName, aAttrName) {
+  getAttrDef: function gloda_ns_getAttrDef(aPluginName, aAttrName) {
     let compoundName = aPluginName + ":" + aAttrName;
     return GlodaDatastore._attributeDBDefs[compoundName];
   },
 
   /**
    * Create a new query instance for the given noun-type.  This provides
    *  a generic way to provide constraint-based queries of any first-class
    *  nouns supported by the system.
@@ -1851,27 +1886,27 @@ var Gloda = {
    * There are also full-text constraint columns.  In a nutshell, their
    *  arguments are the strings that should be passed to the SQLite FTS3
    *  MATCH clause.
    *
    * @param aNounID The (integer) noun-id of the noun you want to query on.
    * @param aOptions an optional dictionary of query options, see the GlodaQuery
    *     class documentation.
    */
-  newQuery(aNounID, aOptions) {
+  newQuery: function gloda_ns_newQuery(aNounID, aOptions) {
     let nounDef = this._nounIDToDef[aNounID];
     return new nounDef.queryClass(aOptions);
   },
 
   /**
    * Create a collection/query for the given noun-type that only matches the
    *  provided items.  This is to be used when you have an explicit set of items
    *  that you would still like to receive updates for.
    */
-  explicitCollection(aNounID, aItems) {
+  explicitCollection: function gloda_ns_explicitCollection(aNounID, aItems) {
     let nounDef = this._nounIDToDef[aNounID];
     let collection = new GlodaCollection(nounDef, aItems, null, null);
     let query = new nounDef.explicitQueryClass(collection);
     collection.query = query;
     GlodaCollectionManager.registerCollection(collection);
     return collection;
   },
 
@@ -1881,35 +1916,34 @@ var Gloda = {
    *  as new.  The result is that it allows you to be notified as new items
    *  as they are indexed, existing items as they are loaded from the database,
    *  etc.
    * Because the items are added to the collection without limit, this will
    *  result in a leak if you don't do something to clean up after the
    *  collection.  (Forgetting about the collection will suffice, as it is still
    *  weakly held.)
    */
-  _wildcardCollection(aNounID, aItems) {
+  _wildcardCollection: function gloda_ns_wildcardCollection(aNounID, aItems) {
     let nounDef = this._nounIDToDef[aNounID];
     let collection = new GlodaCollection(nounDef, aItems, null, null);
     let query = new nounDef.wildcardQueryClass(collection);
     collection.query = query;
     GlodaCollectionManager.registerCollection(collection);
     return collection;
   },
 
   /**
    * Attribute providers attempting to index something that experience a fatal
    *  problem should throw one of these.  For example:
    *  "throw new Gloda.BadItemContentsError('Message lacks an author.');".
    *
    * We're not really taking advantage of this yet, but it's a good idea.
    */
-  BadItemContentsError,
+  BadItemContentsError: BadItemContentsError,
 
-  /* eslint-disable complexity */
   /**
    * Populate a gloda representation of an item given the thus-far built
    *  representation, the previous representation, and one or more raw
    *  representations.  The attribute providers/optimizers for the given noun
    *  type are invoked, allowing them to contribute/alter things.  Following
    *  that, we build and persist our attribute representations.
    *
    * The result of the processing ends up with attributes in 3 different forms:
@@ -1939,32 +1973,33 @@ var Gloda = {
    *     with messages where we may have a ghost, the ghost message is not a
    *     new record, but is conceptually new.
    * @param aCallbackHandle The GlodaIndexer-style callback handle that is being
    *     used to drive this processing in an async fashion.  (See
    *     GlodaIndexer._callbackHandle).
    * @param aDoCache Should we allow this item to be contributed to its noun
    *     cache?
    */
-  * grokNounItem(aItem, aRawReps, aIsConceptuallyNew, aIsRecordNew, aCallbackHandle, aDoCache) {
+  grokNounItem: function* gloda_ns_grokNounItem(aItem, aRawReps,
+      aIsConceptuallyNew, aIsRecordNew, aCallbackHandle, aDoCache) {
     let itemNounDef = aItem.NOUN_DEF;
     let attribsByBoundName = itemNounDef.attribsByBoundName;
 
     this._log.info(" ** grokNounItem: " + itemNounDef.name);
 
     let addDBAttribs = [];
     let removeDBAttribs = [];
 
     let jsonDict = {};
 
     let aOldItem;
     aRawReps.trueGlodaRep = aItem;
-    if (aIsConceptuallyNew) { // there is no old item if we are new.
+    if (aIsConceptuallyNew) // there is no old item if we are new.
       aOldItem = {};
-    } else {
+    else {
       aOldItem = aItem;
       // we want to create a clone of the existing item so that we can know the
       //  deltas that happened for indexing purposes
       aItem = aItem._clone();
     }
 
     // Have the attribute providers directly set properties on the aItem
     let attrProviders = this._attrProviderOrderByNoun[itemNounDef.id];
@@ -2004,24 +2039,27 @@ var Gloda = {
       let objectNounDef = attrib.objectNounDef;
 
       // - translate for our JSON rep
       if (attrib.singular) {
         if (objectNounDef.toJSON)
           jsonDict[attrib.id] = objectNounDef.toJSON(value);
         else
           jsonDict[attrib.id] = value;
-      } else if (objectNounDef.toJSON) {
-        let toJSON = objectNounDef.toJSON;
-        jsonDict[attrib.id] = [];
-        for (let subValue of value) {
-          jsonDict[attrib.id].push(toJSON(subValue));
+      }
+      else {
+        if (objectNounDef.toJSON) {
+          let toJSON = objectNounDef.toJSON;
+          jsonDict[attrib.id] = [];
+          for (let subValue of value) {
+            jsonDict[attrib.id].push(toJSON(subValue));
+          }
         }
-      } else {
-        jsonDict[attrib.id] = value;
+        else
+          jsonDict[attrib.id] = value;
       }
 
       let oldValue = aOldItem[key];
 
       // the 'old' item is still the canonical one; update it
       // do the update now, because we may skip operations on addDBAttribs and
       //  removeDBattribs, if the attribute is not to generate entries in
       //  messageAttributes
@@ -2045,30 +2083,32 @@ var Gloda = {
           // test for identicality, failing that, see if they have explicit
           //  equals support.
           if ((value !== oldValue) &&
               (!value.equals || !value.equals(oldValue))) {
             addDBAttribs.push(attribDB.convertValuesToDBAttributes([value])[0]);
             removeDBAttribs.push(
               attribDB.convertValuesToDBAttributes([oldValue])[0]);
           }
-        } else if (objectNounDef.computeDelta) {
-          // in the plural case, we have to figure the deltas accounting for
-          //  possible changes in ordering (which is insignificant from an
-          //  indexing perspective)
-          // some nouns may not meet === equivalence needs, so must provide a
-          //  custom computeDelta method to help us out
+        }
+        // in the plural case, we have to figure the deltas accounting for
+        //  possible changes in ordering (which is insignificant from an
+        //  indexing perspective)
+        // some nouns may not meet === equivalence needs, so must provide a
+        //  custom computeDelta method to help us out
+        else if (objectNounDef.computeDelta) {
           let [valuesAdded, valuesRemoved] =
             objectNounDef.computeDelta(value, oldValue);
           // convert the values to database-style attribute rows
           addDBAttribs.push.apply(addDBAttribs,
             attribDB.convertValuesToDBAttributes(valuesAdded));
           removeDBAttribs.push.apply(removeDBAttribs,
             attribDB.convertValuesToDBAttributes(valuesRemoved));
-        } else {
+        }
+        else {
           // build a map of the previous values; we will delete the values as
           //  we see them so that we will know what old values are no longer
           //  present in the current set of values.
           let oldValueMap = {};
           for (let anOldValue of oldValue) {
             // remember, the key is just the toString'ed value, so we need to
             //  store and use the actual value as the value!
             oldValueMap[anOldValue] = anOldValue;
@@ -2095,17 +2135,19 @@ var Gloda = {
         if (attrib.emptySetIsSignificant) {
           // if we are now non-zero but previously were zero, remove.
           if (value.length && !oldValue.length)
             removeDBAttribs.push([GlodaDatastore.kEmptySetAttrId, attribDB.id]);
           // if we are now zero length but previously were not, add
           else if (!value.length && oldValue.length)
             addDBAttribs.push([GlodaDatastore.kEmptySetAttrId, attribDB.id]);
         }
-      } else { // no old value, all values are new
+      }
+      // no old value, all values are new
+      else {
         // add the db reps on the new values
         if (attrib.singular)
           value = [value];
         addDBAttribs.push.apply(addDBAttribs,
                                 attribDB.convertValuesToDBAttributes(value));
         // Add the empty set indicator for the attribute id if appropriate.
         if (!value.length && attrib.emptySetIsSignificant)
           addDBAttribs.push([GlodaDatastore.kEmptySetAttrId, attribDB.id]);
@@ -2131,18 +2173,18 @@ var Gloda = {
         continue;
       }
 
       // delete these from the old item, as the old item is canonical, and
       //  should no longer have these values
       delete aOldItem[key];
 
       if (attrib.canQuery !== true) {
-        this._log.debug("Not inserting attribute " + attrib.attributeName
-          + " into the db, since we don't plan on querying on it");
+        this._log.debug("Not inserting attribute "+attrib.attributeName
+            +" into the db, since we don't plan on querying on it");
         continue;
       }
 
       if (attrib.singular)
         value = [value];
       let attribDB = attrib.dbDef;
       removeDBAttribs.push.apply(removeDBAttribs,
                                  attribDB.convertValuesToDBAttributes(value));
@@ -2152,17 +2194,18 @@ var Gloda = {
     }
 
     aItem._jsonText = JSON.stringify(jsonDict);
     this._log.debug("  json text: " + aItem._jsonText);
 
     if (aIsRecordNew) {
       this._log.debug(" inserting item");
       itemNounDef.objInsert.call(itemNounDef.datastore, aItem);
-    } else {
+    }
+    else {
       this._log.debug(" updating item");
       itemNounDef.objUpdate.call(itemNounDef.datastore, aItem);
     }
 
     this._log.debug(" adjusting attributes, add: " + addDBAttribs + " rem: " +
         removeDBAttribs);
     itemNounDef.dbAttribAdjuster.call(itemNounDef.datastore, aItem,
       addDBAttribs, removeDBAttribs);
@@ -2177,30 +2220,30 @@ var Gloda = {
       else
         GlodaCollectionManager.itemsModified(aOldItem.NOUN_ID, [aOldItem]);
     }
 
     this._log.debug(" done grokking.");
 
     yield this.kWorkDone;
   },
-  /* eslint-enable complexity */
 
   /**
    * Processes a list of noun instances for their score within a given context.
    *  This is primarily intended for use by search ranking mechanisms, but could
    *  be used elsewhere too.  (It does, however, depend on the complicity of the
    *  score method implementations to not get confused.)
    *
    * @param aItems The non-empty list of items to score.
    * @param aContext A noun-specific dictionary that we just pass to the funcs.
    * @param aExtraScoreFuncs A list of extra scoring functions to apply.
    * @returns A list of integer scores equal in length to aItems.
    */
-  scoreNounItems(aItems, aContext, aExtraScoreFuncs) {
+  scoreNounItems: function gloda_ns_grokNounItem(aItems, aContext,
+                                                 aExtraScoreFuncs) {
     let scores = [];
     // bail if there is nothing to score
     if (!aItems.length)
       return scores;
 
     let itemNounDef = aItems[0].NOUN_DEF;
     if (aExtraScoreFuncs == null)
       aExtraScoreFuncs = [];
@@ -2214,21 +2257,22 @@ var Gloda = {
           score += provider.score(item);
       }
       for (let extraScoreFunc of aExtraScoreFuncs)
         score += extraScoreFunc(item, aContext);
       scores.push(score);
     }
 
     return scores;
-  },
+  }
 };
 
 /* and initialize the Gloda object/NS before we return... */
 try {
   Gloda._init();
-} catch (ex) {
+}
+catch (ex) {
   Gloda._log.debug("Exception during Gloda init (" + ex.fileName + ":" +
                    ex.lineNumber + "): " + ex);
-}
+};
 /* but don't forget that we effectively depend on everybody.js too, and
    currently on our importer to be importing that if they need us fully armed
    and operational. */
--- a/mailnews/db/gloda/modules/index_ab.js
+++ b/mailnews/db/gloda/modules/index_ab.js
@@ -1,52 +1,52 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-this.EXPORTED_SYMBOLS = ["GlodaABIndexer", "GlodaABAttrs"];
+this.EXPORTED_SYMBOLS = ['GlodaABIndexer', 'GlodaABAttrs'];
 
 const {GlodaCollectionManager} = ChromeUtils.import("resource:///modules/gloda/collection.js");
 const {GlodaDatastore} = ChromeUtils.import("resource:///modules/gloda/datastore.js");
 const {Gloda} = ChromeUtils.import("resource:///modules/gloda/gloda.js");
 const {GlodaIndexer, IndexingJob} = ChromeUtils.import("resource:///modules/gloda/indexer.js");
 const {Log4Moz} = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
 const {FreeTagNoun} = ChromeUtils.import("resource:///modules/gloda/noun_freetag.js");
 const {GlodaUtils} = ChromeUtils.import("resource:///modules/gloda/utils.js");
 const {MailServices} = ChromeUtils.import("resource:///modules/MailServices.jsm");
 
 
 var GlodaABIndexer = {
   _log: null,
 
   name: "index_ab",
-  enable() {
+  enable: function() {
     if (this._log == null)
       this._log =  Log4Moz.repository.getLogger("gloda.index_ab");
 
     MailServices.ab.addAddressBookListener(this,
                                            Ci.nsIAbListener.itemAdded |
                                            Ci.nsIAbListener.itemChanged |
                                            Ci.nsIAbListener.directoryItemRemoved);
   },
 
-  disable() {
+  disable: function() {
     MailServices.ab.removeAddressBookListener(this);
   },
 
   // it's a getter so we can reference 'this'
   get workers() {
     return [
       ["ab-card", {
          worker: this._worker_index_card,
        }],
     ];
   },
 
-  * _worker_index_card(aJob, aCallbackHandle) {
+  _worker_index_card: function*(aJob, aCallbackHandle) {
     let card = aJob.id;
 
     if (card.primaryEmail) {
       // load the identity
       let query = Gloda.newQuery(Gloda.NOUN_IDENTITY);
       query.kind("email");
       // we currently normalize all e-mail addresses to be lowercase
       query.value(card.primaryEmail.toLowerCase());
@@ -55,94 +55,97 @@ var GlodaABIndexer = {
 
       if (identityCollection.items.length) {
         let identity = identityCollection.items[0];
         // force the identity to know it has an associated ab card.
         identity._hasAddressBookCard = true;
 
         this._log.debug("Found identity, processing card.");
         yield aCallbackHandle.pushAndGo(
-          Gloda.grokNounItem(identity.contact, {card}, false, false,
-                             aCallbackHandle));
+            Gloda.grokNounItem(identity.contact, {card: card}, false, false,
+                               aCallbackHandle));
         this._log.debug("Done processing card.");
       }
     }
 
     yield GlodaIndexer.kWorkDone;
   },
 
-  initialSweep() {
+  initialSweep: function() {
   },
 
   /* ------ nsIAbListener ------ */
   /**
    * When an address book card is added, update the cached GlodaIdentity
    *  object's cached idea of whether the identity has an ab card.
    */
-  onItemAdded(aParentDir, aItem) {
+  onItemAdded: function ab_indexer_onItemAdded(aParentDir, aItem) {
     if (!(aItem instanceof Ci.nsIAbCard))
       return;
 
     this._log.debug("Received Card Add Notification");
     let identity = GlodaCollectionManager.cacheLookupOneByUniqueValue(
       Gloda.NOUN_IDENTITY, "email@" + aItem.primaryEmail.toLowerCase());
     if (identity)
       identity._hasAddressBookCard = true;
   },
   /**
    * When an address book card is added, update the cached GlodaIdentity
    *  object's cached idea of whether the identity has an ab card.
    */
-  onItemRemoved(aParentDir, aItem) {
+  onItemRemoved: function ab_indexer_onItemRemoved(aParentDir, aItem) {
     if (!(aItem instanceof Ci.nsIAbCard))
       return;
 
     this._log.debug("Received Card Removal Notification");
     let identity = GlodaCollectionManager.cacheLookupOneByUniqueValue(
       Gloda.NOUN_IDENTITY, "email@" + aItem.primaryEmail.toLowerCase());
     if (identity)
       identity._hasAddressBookCard = false;
+
   },
-  onItemPropertyChanged(aItem, aProperty, aOldValue, aNewValue) {
+  onItemPropertyChanged: function ab_indexer_onItemPropertyChanged(aItem,
+      aProperty, aOldValue, aNewValue) {
     if (aProperty == null && aItem instanceof Ci.nsIAbCard) {
       this._log.debug("Received Card Change Notification");
 
       let card = aItem; // instanceof already QueryInterface'd for us.
       let job = new IndexingJob("ab-card", card);
       GlodaIndexer.indexJob(job);
     }
-  },
+  }
 };
 GlodaIndexer.registerIndexer(GlodaABIndexer);
 
 var GlodaABAttrs = {
   providerName: "gloda.ab_attr",
   _log: null,
 
-  init() {
+  init: function() {
     this._log =  Log4Moz.repository.getLogger("gloda.abattrs");
 
     try {
       this.defineAttributes();
-    } catch (ex) {
+    }
+    catch (ex) {
       this._log.error("Error in init: " + ex);
       throw ex;
     }
   },
 
-  defineAttributes() {
+  defineAttributes: function() {
     /* ***** Contacts ***** */
     this._attrIdentityContact = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrDerived,
       attributeName: "identities",
       singular: false,
       special: Gloda.kSpecialColumnChildren,
-      // specialColumnName: "contactID",
+      //specialColumnName: "contactID",
       storageAttributeName: "_identities",
       subjectNouns: [Gloda.NOUN_CONTACT],
       objectNoun: Gloda.NOUN_IDENTITY,
       }); // tested-by: test_attributes_fundamental
     this._attrContactName = Gloda.defineAttribute({
       provider: this,
       extensionName: Gloda.BUILT_IN,
       attributeType: Gloda.kAttrFundamental,
@@ -241,17 +244,17 @@ var GlodaABAttrs = {
     if ("parameterBindings" in this._attrFreeTag) {
       for (let freeTagName in this._attrFreeTag.parameterBindings) {
         this._log.debug("Telling FreeTagNoun about: " + freeTagName);
         FreeTagNoun.getFreeTag(freeTagName);
       }
     }
   },
 
-  * process(aContact, aRawReps, aIsNew, aCallbackHandle) {
+  process: function*(aContact, aRawReps, aIsNew, aCallbackHandle) {
     let card = aRawReps.card;
     if (aContact.NOUN_ID != Gloda.NOUN_CONTACT) {
       this._log.warn("Somehow got a non-contact: " + aContact);
       return; // this will produce an exception; we like.
     }
 
     // update the name
     if (card.displayName && card.displayName != aContact.name)
@@ -270,10 +273,10 @@ var GlodaABAttrs = {
         tagName = tagName.trim();
         if (tagName) {
           aContact.freeTags.push(FreeTagNoun.getFreeTag(tagName));
         }
       }
     }
 
     yield Gloda.kWorkDone;
-  },
+  }
 };
--- a/mailnews/db/gloda/modules/index_msg.js
+++ b/mailnews/db/gloda/modules/index_msg.js
@@ -7,17 +7,17 @@
 /*
  * This file currently contains a fairly general implementation of asynchronous
  *  indexing with a very explicit message indexing implementation.  As gloda
  *  will eventually want to index more than just messages, the message-specific
  *  things should ideally lose their special hold on this file.  This will
  *  benefit readability/size as well.
  */
 
-this.EXPORTED_SYMBOLS = ["GlodaMsgIndexer"];
+this.EXPORTED_SYMBOLS = ['GlodaMsgIndexer'];
 
 const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {fixIterator} = ChromeUtils.import("resource:///modules/iteratorUtils.jsm");
 const {MailServices} = ChromeUtils.import("resource:///modules/MailServices.jsm");
 const {MailUtils} = ChromeUtils.import("resource:///modules/MailUtils.jsm");
 
 const {Log4Moz} = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
 
@@ -120,17 +120,17 @@ var PendingCommitTracker = {
    * Accordingly, we make a list of all the folders that the headers belong to
    *  as we iterate, make sure to re-attach their msgDatabase before forgetting
    *  the headers, then make sure to zero the msgDatabase again, triggering a
    *  commit.  If there were a way to directly get the nsIMsgDatabase from the
    *  header we could do that and call commit directly.  We don't track
    *  databases along with the headers since the headers can change because of
    *  moves and that would increase the number of moving parts.
    */
-  _commitCallback() {
+  _commitCallback: function PendingCommitTracker_commitCallback() {
     let foldersByURI = {};
     let lastFolder = null;
 
     for (let glodaId in
          PendingCommitTracker._indexedMessagesPendingCommitByGlodaId) {
      let [msgHdr, dirtyState] =
        PendingCommitTracker._indexedMessagesPendingCommitByGlodaId[glodaId];
       // Mark this message as indexed.
@@ -150,46 +150,47 @@ var PendingCommitTracker = {
 
         // Make sure this folder is in our foldersByURI map.
         if (lastFolder == msgHdr.folder)
           continue;
         lastFolder = msgHdr.folder;
         let folderURI = lastFolder.URI;
         if (!(folderURI in foldersByURI))
           foldersByURI[folderURI] = lastFolder;
-      } catch (ex) {
+      }
+      catch (ex) {
         GlodaMsgIndexer._log.error(
           "Exception while attempting to mark message with gloda state after" +
           "db commit", ex);
       }
     }
 
     // it is vitally important to do this before we forget about the headers!
     for (let uri in foldersByURI) {
       let folder = foldersByURI[uri];
       // This will not cause a parse.  The database is in-memory since we have
       //  a header that belongs to it.  This just causes the folder to
       //  re-acquire a reference from the database manager.
-      folder.msgDatabase;
+      let ignoredDb = folder.msgDatabase;
       // And this will cause a commit.  (And must be done since we don't want
       //  to cause a leak.)
       folder.msgDatabase = null;
     }
 
     PendingCommitTracker._indexedMessagesPendingCommitByGlodaId = {};
     PendingCommitTracker._indexedMessagesPendingCommitByKey = {};
 
     PendingCommitTracker._pendingCommit = false;
   },
 
   /**
    * Track a message header that should be marked with the given gloda id when
    *  the database commits.
    */
-  track(aMsgHdr, aGlodaId) {
+  track: function PendingCommitTracker_track(aMsgHdr, aGlodaId) {
     let pendingKey = aMsgHdr.folder.URI + "#" + aMsgHdr.messageKey;
     this._indexedMessagesPendingCommitByKey[pendingKey] = aGlodaId;
     this._indexedMessagesPendingCommitByGlodaId[aGlodaId] =
       [aMsgHdr, GlodaMsgIndexer.kMessageClean];
 
     if (!this._pendingCommit) {
       GlodaDatastore.runPostCommit(this._commitCallback);
       this._pendingCommit = true;
@@ -198,39 +199,41 @@ var PendingCommitTracker = {
 
   /**
    * Get the current state of a message header given that we cannot rely on just
    *  looking at the header's properties because we defer setting those
    *  until the SQLite commit happens.
    *
    * @return Tuple of [gloda id, dirty status].
    */
-  getGlodaState(aMsgHdr) {
+  getGlodaState:
+      function PendingCommitTracker_getGlodaState(aMsgHdr) {
     // If it's in the pending commit table, then the message is basically
     //  clean.  Return that info.
     let pendingKey = aMsgHdr.folder.URI + "#" + aMsgHdr.messageKey;
     if (pendingKey in this._indexedMessagesPendingCommitByKey) {
       let glodaId =
         PendingCommitTracker._indexedMessagesPendingCommitByKey[pendingKey];
       return [glodaId, this._indexedMessagesPendingCommitByGlodaId[glodaId][1]];
     }
-
-    // Otherwise the header's concept of state is correct.
-    let glodaId = aMsgHdr.getUint32Property(GLODA_MESSAGE_ID_PROPERTY);
-    let glodaDirty = aMsgHdr.getUint32Property(GLODA_DIRTY_PROPERTY);
-    return [glodaId, glodaDirty];
+    else {
+      // Otherwise the header's concept of state is correct.
+      let glodaId = aMsgHdr.getUint32Property(GLODA_MESSAGE_ID_PROPERTY);
+      let glodaDirty = aMsgHdr.getUint32Property(GLODA_DIRTY_PROPERTY);
+      return [glodaId, glodaDirty];
+    }
   },
 
   /**
    * Update our structure to reflect moved headers.  Moves are currently
    *  treated as weakly interesting and do not require a reindexing
    *  although collections will get notified.  So our job is to to fix-up
    *  the pending commit information if the message has a pending commit.
    */
-  noteMove(aOldHdr, aNewHdr) {
+  noteMove: function PendingCommitTracker_noteMove(aOldHdr, aNewHdr) {
     let oldKey = aOldHdr.folder.URI + "#" + aOldHdr.messageKey;
     if (!(oldKey in this._indexedMessagesPendingCommitByKey))
       return;
 
     let glodaId = this._indexedMessagesPendingCommitByKey[oldKey];
     delete this._indexedMessagesPendingCommitByKey[oldKey];
 
     let newKey = aNewHdr.folder.URI + "#" + aNewHdr.messageKey;
@@ -248,29 +251,29 @@ var PendingCommitTracker = {
    *  we could detect the other side of the move when it shows up as a
    *  msgsClassified event and restore the mapping information.  Since the
    *  offline fake header case should now cover the bulk of IMAP move
    *  operations, we probably do not need to pursue this.
    *
    * We just re-dispatch to noteDirtyHeader because we can't do anything more
    *  clever.
    */
-  noteBlindMove(aOldHdr) {
+  noteBlindMove: function PendingCommitTracker_noteBlindMove(aOldHdr) {
     this.noteDirtyHeader(aOldHdr);
   },
 
   /**
    * If a message is dirty we should stop tracking it for post-commit
    *  purposes.  This is not because we don't want to write to its header
    *  when we commit as much as that we want to avoid |getHeaderGlodaState|
    *  reporting that the message is clean.  We could complicate our state
    *  by storing that information, but this is easier and ends up the same
    *  in the end.
    */
-  noteDirtyHeader(aMsgHdr) {
+  noteDirtyHeader: function PendingCommitTracker_noteDirtyHeader(aMsgHdr) {
     let pendingKey = aMsgHdr.folder.URI + "#" + aMsgHdr.messageKey;
     if (!(pendingKey in this._indexedMessagesPendingCommitByKey))
       return;
 
     // (It is important that we get the gloda id from our own structure!)
     let glodaId = this._indexedMessagesPendingCommitByKey[pendingKey];
     this._indexedMessagesPendingCommitByGlodaId[glodaId][1] =
       GlodaMsgIndexer.kMessageDirty;
@@ -286,17 +289,19 @@ var PendingCommitTracker = {
    * When this happens, we are basically out of luck and need to discard
    *  everything about the folder.  The good news is that the folder compaction
    *  pass is clever enough to re-establish the linkages that are being lost
    *  when we drop these things on the floor.  Reindexing of a folder is not
    *  clever enough to deal with this but is an exceptional case of last resort
    *  (the user should not normally be performing a reindex as part of daily
    *  operation), so we accept that messages may be redundantly indexed.
    */
-  noteFolderDatabaseGettingBlownAway(aMsgFolder) {
+  noteFolderDatabaseGettingBlownAway:
+      function PendingCommitTracker_noteFolderDatabaseGettingBlownAway(
+                 aMsgFolder) {
     let uri = aMsgFolder.URI + "#";
     for (let key of Object.keys(this._indexedMessagesPendingCommitByKey)) {
       // this is not as efficient as it could be, but compaction is relatively
       //  rare and the number of pending headers is generally going to be
       //  small.
       if (key.indexOf(uri) == 0) {
         delete this._indexedMessagesPendingCommitByKey[key];
       }
@@ -314,38 +319,38 @@ function MessagesByMessageIdCallback(aMs
   this.results = aResults;
   this.callback = aCallback;
   this.callbackThis = aCallbackThis;
 }
 
 MessagesByMessageIdCallback.prototype = {
   _log: Log4Moz.repository.getLogger("gloda.index_msg.mbm"),
 
-  onItemsAdded(aItems, aCollection) {
+  onItemsAdded: function gloda_ds_mbmi_onItemsAdded(aItems, aCollection) {
     // just outright bail if we are shutdown
     if (GlodaDatastore.datastoreIsShutdown)
       return;
 
     this._log.debug("getting results...");
     for (let message of aItems) {
       this.results[this.msgIDToIndex[message.headerMessageID]].push(message);
     }
   },
-  onItemsModified() {},
-  onItemsRemoved() {},
-  onQueryCompleted(aCollection) {
+  onItemsModified: function () {},
+  onItemsRemoved: function () {},
+  onQueryCompleted: function gloda_ds_mbmi_onQueryCompleted(aCollection) {
     // just outright bail if we are shutdown
     if (GlodaDatastore.datastoreIsShutdown)
       return;
 
     if (this._log.level <= Log4Moz.Level.Debug)
       this._log.debug("query completed, notifying... " + this.results);
 
     this.callback.call(this.callbackThis, this.results);
-  },
+  }
 };
 
 
 /**
  * The message indexer!
  *
  * === Message Indexing Strategy
  * To these ends, we implement things like so:
@@ -419,17 +424,17 @@ var GlodaMsgIndexer = {
 
   name: "index_msg",
   /**
    * Are we enabled, read: are we processing change events?
    */
   _enabled: false,
   get enabled() { return this._enabled; },
 
-  enable() {
+  enable: function msg_indexer_enable() {
     // initialize our listeners' this pointers
     this._databaseAnnouncerListener.indexer = this;
     this._msgFolderListener.indexer = this;
 
     // register for:
     // - folder loaded events, so we know when getDatabaseWithReparse has
     //   finished updating the index/what not (if it wasn't immediately
     //   available)
@@ -454,17 +459,17 @@ var GlodaMsgIndexer = {
         Ci.nsIMsgFolderNotificationService.itemEvent);
 
     this._enabled = true;
 
     this._considerSchemaMigration();
 
     this._log.info("Event-Driven Indexing is now " + this._enabled);
   },
-  disable() {
+  disable: function msg_indexer_disable() {
     // remove FolderLoaded notification listener
     MailServices.mailSession.RemoveFolderListener(this._folderListener);
 
     MailServices.mfn.removeListener(this._msgFolderListener);
 
     this._indexerLeaveFolder(); // nop if we aren't "in" a folder
 
     this._enabled = false;
@@ -564,17 +569,17 @@ var GlodaMsgIndexer = {
    *  cutting down on duplicate code, this ensures that we are listening on
    *  the folder in case it tries to go away when we are using it.
    *
    * @return true when the folder was successfully entered, false when we need
    *     to pend on notification of updating of the folder (due to re-parsing
    *     or what have you).  In the event of an actual problem, an exception
    *     will escape.
    */
-  _indexerEnterFolder(aFolderID) {
+  _indexerEnterFolder: function gloda_index_indexerEnterFolder(aFolderID) {
     // leave the folder if we haven't explicitly left it.
     if (this._indexingFolder !== null) {
       this._indexerLeaveFolder();
     }
 
     this._indexingGlodaFolder = GlodaDatastore._mapFolderID(aFolderID);
     this._indexingFolder = this._indexingGlodaFolder.getXPCOMFolder(
                              this._indexingGlodaFolder.kActivityIndexing);
@@ -587,40 +592,43 @@ var GlodaMsgIndexer = {
       // This may require yielding until such time as the msf has been created.
       try {
         if (this._indexingFolder instanceof Ci.nsIMsgLocalMailFolder) {
           this._indexingDatabase =
             this._indexingFolder.getDatabaseWithReparse(null,
                                                         null);
         }
         // we need do nothing special for IMAP, news, or other
-      } catch (e) {
-        // getDatabaseWithReparse can return either NS_ERROR_NOT_INITIALIZED or
-        //  NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE if the net result is that it
-        //  is going to send us a notification when the reparse has completed.
-        // (note that although internally NS_MSG_ERROR_FOLDER_SUMMARY_MISSING
-        //  might get flung around, it won't make it out to us, and will instead
-        //  be permuted into an NS_ERROR_NOT_INITIALIZED.)
+      }
+      // getDatabaseWithReparse can return either NS_ERROR_NOT_INITIALIZED or
+      //  NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE if the net result is that it
+      //  is going to send us a notification when the reparse has completed.
+      // (note that although internally NS_MSG_ERROR_FOLDER_SUMMARY_MISSING
+      //  might get flung around, it won't make it out to us, and will instead
+      //  be permuted into an NS_ERROR_NOT_INITIALIZED.)
+      catch (e) {
         if ((e.result == Cr.NS_ERROR_NOT_INITIALIZED) ||
             (e.result == NS_MSG_ERROR_FOLDER_SUMMARY_OUT_OF_DATE)) {
           // this means that we need to pend on the update; the listener for
           //  FolderLoaded events will call _indexerCompletePendingFolderEntry.
           this._log.debug("Pending on folder load...");
           this._pendingFolderEntry = this._indexingFolder;
           return this.kWorkAsync;
+        } else {
+          throw e;
         }
-        throw e;
       }
       // we get an nsIMsgDatabase out of this (unsurprisingly) which
       //  explicitly inherits from nsIDBChangeAnnouncer, which has the
       //  AddListener call we want.
       if (this._indexingDatabase == null)
         this._indexingDatabase = this._indexingFolder.msgDatabase;
       this._indexingDatabase.AddListener(this._databaseAnnouncerListener);
-    } catch (ex) {
+    }
+    catch (ex) {
       this._log.error("Problem entering folder: " +
                       (this._indexingFolder ?
                          this._indexingFolder.prettyName : "unknown") +
                       ", skipping. Error was: " + ex.fileName + ":" +
                       ex.lineNumber + ": " + ex);
       this._indexingGlodaFolder.indexing = false;
       this._indexingFolder = null;
       this._indexingGlodaFolder = null;
@@ -636,17 +644,18 @@ var GlodaMsgIndexer = {
   },
 
   /**
    * If the folder was still parsing/updating when we tried to enter, then this
    *  handler will get called by the listener who got the FolderLoaded message.
    * All we need to do is get the database reference, register a listener on
    *  the db, and retrieve an iterator if desired.
    */
-  _indexerCompletePendingFolderEntry() {
+  _indexerCompletePendingFolderEntry:
+      function gloda_indexer_indexerCompletePendingFolderEntry() {
     this._indexingDatabase = this._indexingFolder.msgDatabase;
     this._indexingDatabase.AddListener(this._databaseAnnouncerListener);
     this._log.debug("...Folder Loaded!");
 
     // the load is no longer pending; we certainly don't want more notifications
     this._pendingFolderEntry = null;
     // indexerEnterFolder returned kWorkAsync, which means we need to notify
     //  the callback driver to get things going again.
@@ -671,17 +680,18 @@ var GlodaMsgIndexer = {
    *  in |_indexingFolder|.
    *
    * @param aEnumKind One of |kEnumAllMsgs|, |kEnumMsgsToIndex|, or
    *     |kEnumIndexedMsgs|.
    * @param [aAllowPreBadIds=false] Only valid for |kEnumIndexedMsgs|, tells us
    *     that we should treat message with any gloda-id as dirty, not just
    *     messages that have non-bad message id's.
    */
-  _indexerGetEnumerator(aEnumKind, aAllowPreBadIds) {
+  _indexerGetEnumerator: function gloda_indexer_indexerGetEnumerator(
+      aEnumKind, aAllowPreBadIds) {
     if (aEnumKind == this.kEnumMsgsToIndex) {
       // We need to create search terms for messages to index. Messages should
       //  be indexed if they're indexable (local or offline and not expunged)
       //  and either: haven't been indexed, are dirty, or are marked with with
       //  a former GLODA_BAD_MESSAGE_ID that is no longer our bad marker.  (Our
       //  bad marker can change on minor schema revs so that we can try and
       //  reindex those messages exactly once and without needing to go through
       //  a pass to mark them as needing one more try.)
@@ -752,17 +762,18 @@ var GlodaMsgIndexer = {
       searchTerm.op = nsMsgSearchOp.Isnt;
       value = searchTerm.value;
       value.attrib = searchTerm.attrib;
       value.str = JUNK_SPAM_SCORE_STR;
       searchTerm.value = value;
       searchTerm.hdrProperty = JUNK_SCORE_PROPERTY;
       searchTerms.appendElement(searchTerm);
 
-      if (!isLocal) {
+      if (!isLocal)
+      {
         // If the folder is offline, then the message should be too
         if (this._indexingFolder.getFlag(Ci.nsMsgFolderFlags.Offline)) {
           // third term: && Status Is nsMsgMessageFlags.Offline
           searchTerm = searchSession.createTerm();
           searchTerm.booleanAnd = true;
           searchTerm.attrib = nsMsgSearchAttrib.MsgStatus;
           searchTerm.op = nsMsgSearchOp.Is;
           value = searchTerm.value;
@@ -781,17 +792,18 @@ var GlodaMsgIndexer = {
         value.attrib = searchTerm.attrib;
         value.status = Ci.nsMsgMessageFlags.Expunged;
         searchTerm.value = value;
         searchTerms.appendElement(searchTerm);
       }
 
       this._indexingEnumerator =
         this._indexingDatabase.getFilterEnumerator(searchTerms, true);
-    } else if (aEnumKind == this.kEnumIndexedMsgs) {
+    }
+    else if (aEnumKind == this.kEnumIndexedMsgs) {
       // Enumerate only messages that are already indexed.  This comes out to:
       //  ((GLODA_MESSAGE_ID_PROPERTY > GLODA_FIRST_VALID_MESSAGE_ID-1) &&
       //   (GLODA_DIRTY_PROPERTY Isnt kMessageFilthy))
       // In English, a message is indexed if (by clause):
       // 1) The message has a gloda-id and that gloda-id is in the valid range
       //    (and not in the bad message marker range).
       // 2) The message has not been marked filthy (which invalidates the
       //    gloda-id.)  We also assume that the folder would not have been
@@ -833,25 +845,27 @@ var GlodaMsgIndexer = {
       searchTerm.value = value;
       searchTerm.hdrProperty = GLODA_DIRTY_PROPERTY;
       searchTerms.appendElement(searchTerm);
 
       // The use-case of already indexed messages does not want them reversed;
       //  we care about seeing the message keys in order.
       this._indexingEnumerator =
         this._indexingDatabase.getFilterEnumerator(searchTerms, false);
-    } else if (aEnumKind == this.kEnumAllMsgs) {
+    }
+    else if (aEnumKind == this.kEnumAllMsgs) {
       this._indexingEnumerator =
         this._indexingDatabase.ReverseEnumerateMessages();
-    } else {
+    }
+    else {
       throw new Error("Unknown enumerator type requested:" + aEnumKind);
     }
   },
 
-  _indexerLeaveFolder() {
+  _indexerLeaveFolder: function gloda_index_indexerLeaveFolder() {
     if (this._indexingFolder !== null) {
       if (this._indexingDatabase) {
         this._indexingDatabase.Commit(Ci.nsMsgDBCommitType.kLargeCommit);
         // remove our listener!
         this._indexingDatabase.RemoveListener(this._databaseAnnouncerListener);
       }
       // let the gloda folder know we are done indexing
       this._indexingGlodaFolder.indexing = false;
@@ -866,17 +880,17 @@ var GlodaMsgIndexer = {
   /**
    * Event fed to us by our nsIFolderListener when a folder is loaded.  We use
    *  this event to know when a folder we were trying to open to index is
    *  actually ready to be indexed.  (The summary may have not existed, may have
    *  been out of date, or otherwise.)
    *
    * @param aFolder An nsIMsgFolder, already QI'd.
    */
-  _onFolderLoaded(aFolder) {
+  _onFolderLoaded: function gloda_index_onFolderLoaded(aFolder) {
     if ((this._pendingFolderEntry !== null) &&
         (aFolder.URI == this._pendingFolderEntry.URI))
       this._indexerCompletePendingFolderEntry();
   },
 
   // it's a getter so we can reference 'this'.  we could memoize.
   get workers() {
     return [
@@ -908,26 +922,26 @@ var GlodaMsgIndexer = {
 
       ["fixMissingContacts", {
         worker: this._worker_fixMissingContacts,
        }],
     ];
   },
 
   _schemaMigrationInitiated: false,
-  _considerSchemaMigration() {
+  _considerSchemaMigration: function() {
     if (!this._schemaMigrationInitiated &&
         GlodaDatastore._actualSchemaVersion === 26) {
       let job = new IndexingJob("fixMissingContacts", null);
       GlodaIndexer.indexJob(job);
       this._schemaMigrationInitiated = true;
     }
   },
 
-  initialSweep() {
+  initialSweep: function() {
     this.indexingSweepNeeded = true;
   },
 
   _indexingSweepActive: false,
   /**
    * Indicate that an indexing sweep is desired.  We kick-off an indexing
    *  sweep at start-up and whenever we receive an event-based notification
    *  that we either can't process as an event or that we normally handle
@@ -953,31 +967,31 @@ var GlodaMsgIndexer = {
    *  retrieve the list of servers and folders each time want to find a new
    *  folder to index.  This avoids needing to maintain a perfect model of the
    *  folder hierarchy at all times.  (We may eventually want to do that, but
    *  this is sufficient and safe for now.)  Although our use of dirty flags on
    *  the folders allows us to avoid tracking the 'last folder' we processed,
    *  we do so to avoid getting 'trapped' in a folder with a high rate of
    *  changes.
    */
-  * _worker_indexingSweep(aJob) {
+  _worker_indexingSweep: function* gloda_worker_indexingSweep(aJob) {
     if (!aJob.mappedFolders) {
       // Walk the folders and make sure all the folders we would want to index
       //  are mapped.  Build up a list of GlodaFolders as we go, so that we can
       //  sort them by their indexing priority.
       let foldersToProcess = aJob.foldersToProcess = [];
 
       let allFolders = MailServices.accounts.allFolders;
       for (let folder of fixIterator(allFolders, Ci.nsIMsgFolder)) {
         if (this.shouldIndexFolder(folder))
           foldersToProcess.push(Gloda.getFolderForFolder(folder));
       }
 
       // sort the folders by priority (descending)
-      foldersToProcess.sort(function(a, b) {
+      foldersToProcess.sort(function (a, b) {
         return b.indexingPriority - a.indexingPriority;
       });
 
       aJob.mappedFolders = true;
     }
 
     // -- process the folders (in sorted order)
     while (aJob.foldersToProcess.length) {
@@ -1012,17 +1026,17 @@ var GlodaMsgIndexer = {
     this._indexingSweepActive = false;
     yield this.kWorkDone;
   },
 
   /**
    * The only state we need to cleanup is that there is no longer an active
    *  indexing sweep.
    */
-  _cleanup_indexingSweep(aJob) {
+  _cleanup_indexingSweep: function gloda_canceled_indexingSweep(aJob) {
     this._indexingSweepActive = false;
   },
 
   /**
    * The number of headers to look at before yielding with kWorkSync.  This
    *  is for time-slicing purposes so we still yield to the UI periodically.
    */
   HEADER_CHECK_SYNC_BLOCK_SIZE: 25,
@@ -1091,17 +1105,18 @@ var GlodaMsgIndexer = {
    *  actually deal with multiple chunks that we don't step on our own feet with
    *  our database updates.  Since compaction of message key K results in a new
    *  message key K' such that K' <= K, we can reliably issue database
    *  updates for all values <= K.  Which means our feet are safe no matter
    *  when we issue the update command.  For maximum cache benefit, we issue
    *  our updates prior to our new query since they should still be maximally
    *  hot at that point.
    */
-  * _worker_folderCompactionPass(aJob, aCallbackHandle) {
+  _worker_folderCompactionPass:
+      function* gloda_worker_folderCompactionPass(aJob, aCallbackHandle) {
     yield this._indexerEnterFolder(aJob.id);
 
     // It's conceivable that with a folder sweep we might end up trying to
     //  compact a folder twice.  Bail early in this case.
     if (!this._indexingGlodaFolder.compacted)
       yield this.kWorkDone;
 
     // this is a forward enumeration (sometimes we reverse enumerate; not here)
@@ -1119,16 +1134,17 @@ var GlodaMsgIndexer = {
     // (Initialize oldMessageKey because we use it to kickstart our query.)
     let oldGlodaId, oldMessageKey = -1, oldHeaderMessageId;
     // parallel lists of gloda ids and message keys to pass to
     //  GlodaDatastore.updateMessageLocations
     let updateGlodaIds = [];
     let updateMessageKeys = [];
     // list of gloda id's to mark deleted
     let deleteGlodaIds = [];
+    let exceptionalMessages = {};
 
     // for GC reasons we need to track the number of headers seen
     let numHeadersSeen = 0;
 
     // We are consuming two lists; our loop structure has to reflect that.
     let headerIter = this._indexingEnumerator[Symbol.iterator]();
     let mayHaveMoreGlodaMessages = true;
     let keepIterHeader = false;
@@ -1200,64 +1216,71 @@ var GlodaMsgIndexer = {
       }
 
       if (!keepGlodaTuple) {
         if (mayHaveMoreGlodaMessages)
           [oldGlodaId, oldMessageKey, oldHeaderMessageId] =
             glodaIdsMsgKeysHeaderIds.pop();
         else
           oldGlodaId = oldMessageKey = oldHeaderMessageId = null;
-      } else {
+      }
+      else {
         keepGlodaTuple = false;
       }
 
       // -- normal expected case
       if (glodaId == oldGlodaId) {
         // only need to do something if the key is not right
         if (msgHdr.messageKey != oldMessageKey) {
           updateGlodaIds.push(glodaId);
           updateMessageKeys.push(msgHdr.messageKey);
         }
-      } else { // -- exceptional cases
+      }
+      // -- exceptional cases
+      else {
         // This should always return a value unless something is very wrong.
         //  We do not want to catch the exception if one happens.
         let idBasedHeader = oldHeaderMessageId ?
           this._indexingDatabase.getMsgHdrForMessageID(oldHeaderMessageId) :
           false;
         // - Case 1b.
         // We want to mark the message as deleted.
         if (idBasedHeader == null) {
           deleteGlodaIds.push(oldGlodaId);
-        } else if (idBasedHeader &&
-             ((msgHdr && idBasedHeader.messageKey < msgHdr.messageKey) || !msgHdr)) {
-          // - Case 1a
-          // The expected case is that the message referenced by the gloda
-          //  database precedes the header the enumerator told us about.  This
-          //  is expected because if PendingCommitTracker did not mark the
-          //  message as indexed/clean then the enumerator would not tell us
-          //  about it.
-          // Also, if we ran out of headers from the enumerator, this is a dead
-          //  giveaway that this is the expected case.
+        }
+        // - Case 1a
+        // The expected case is that the message referenced by the gloda
+        //  database precedes the header the enumerator told us about.  This
+        //  is expected because if PendingCommitTracker did not mark the
+        //  message as indexed/clean then the enumerator would not tell us
+        //  about it.
+        // Also, if we ran out of headers from the enumerator, this is a dead
+        //  giveaway that this is the expected case.
+        else if (idBasedHeader &&
+             ((msgHdr &&
+               idBasedHeader.messageKey < msgHdr.messageKey) ||
+              !msgHdr)) {
           // tell the pending commit tracker about the gloda database one
           PendingCommitTracker.track(idBasedHeader, oldGlodaId);
           // and we might need to update the message key too
           if (idBasedHeader.messageKey != oldMessageKey) {
             updateGlodaIds.push(oldGlodaId);
             updateMessageKeys.push(idBasedHeader.messageKey);
           }
           // Take another pass through the loop so that we check the
           //  enumerator header against the next message in the gloda
           //  database.
           keepIterHeader = true;
-        } else if (msgHdr) {
-          // - Case 2
-          // Whereas if the message referenced by gloda has a message key
-          //  greater than the one returned by the enumerator, then we have a
-          //  header claiming to be indexed by gloda that gloda does not
-          //  actually know about.  This is exceptional and gets a warning.
+        }
+        // - Case 2
+        // Whereas if the message referenced by gloda has a message key
+        //  greater than the one returned by the enumerator, then we have a
+        //  header claiming to be indexed by gloda that gloda does not
+        //  actually know about.  This is exceptional and gets a warning.
+        else if (msgHdr) {
           this._log.warn("Observed header that claims to be gloda indexed " +
                          "but that gloda has never heard of during " +
                          "compaction." +
                          " In folder: " + msgHdr.folder.URI +
                          " sketchy key: " + msgHdr.messageKey +
                          " subject: " + msgHdr.mime2DecodedSubject);
           // Keep this tuple around for the next enumerator provided header
           keepGlodaTuple = true;
@@ -1276,17 +1299,18 @@ var GlodaMsgIndexer = {
 
     this._indexerLeaveFolder();
     yield this.kWorkDone;
   },
 
   /**
    * Index the contents of a folder.
    */
-  * _worker_folderIndex(aJob, aCallbackHandle) {
+  _worker_folderIndex:
+      function* gloda_worker_folderIndex(aJob, aCallbackHandle) {
     let logDebug = this._log.level <= Log4Moz.Level.Debug;
     yield this._indexerEnterFolder(aJob.id);
 
     if (!this.shouldIndexFolder(this._indexingFolder)) {
       aJob.safelyInvokeCallback(true);
       yield this.kWorkDone;
     }
 
@@ -1402,17 +1426,17 @@ var GlodaMsgIndexer = {
             glodaId >= GLODA_FIRST_VALID_MESSAGE_ID &&
             glodaDirty == this.kMessageClean)
           continue;
 
         if (logDebug)
           this._log.debug(">>>  calling _indexMessage");
         yield aCallbackHandle.pushAndGo(
           this._indexMessage(msgHdr, aCallbackHandle),
-          {what: "indexMessage", msgHdr});
+          {what: "indexMessage", msgHdr: msgHdr});
         GlodaIndexer._indexedMessageCount++;
         if (logDebug)
           this._log.debug("<<<  back from _indexMessage");
       }
     }
 
     // This will trigger an (async) db update which cannot hit the disk prior to
     //  the actual database records that constitute the clean state.
@@ -1430,39 +1454,40 @@ var GlodaMsgIndexer = {
     yield this.kWorkDone;
   },
 
   /**
    * Invoked when a "message" job is scheduled so that we can clear
    *  _pendingAddJob if that is the job.  We do this so that work items are not
    *  added to _pendingAddJob while it is being processed.
    */
-  _schedule_messageIndex(aJob, aCallbackHandle) {
+  _schedule_messageIndex: function(aJob, aCallbackHandle) {
     // we do not want new work items to be added as we are processing, so
     //  clear _pendingAddJob.  A new job will be created as needed.
     if (aJob === this._pendingAddJob)
       this._pendingAddJob = null;
     // update our goal from the items length
     aJob.goal = aJob.items.length;
   },
   /**
    * If the job gets canceled, we need to make sure that we clear out pending
    *  add job or our state will get wonky.
    */
-  _canceled_messageIndex(aJob) {
+  _canceled_messageIndex: function gloda_index_msg_canceled_messageIndex(aJob) {
     if (aJob === this._pendingAddJob)
       this._pendingAddJob = null;
   },
 
 
   /**
    * Index a specific list of messages that we know to index from
    *  event-notification hints.
    */
-  * _worker_messageIndex(aJob, aCallbackHandle) {
+  _worker_messageIndex:
+      function* gloda_worker_messageIndex(aJob, aCallbackHandle) {
     // if we are already in the correct folder, our "get in the folder" clause
     //  will not execute, so we need to make sure this value is accurate in
     //  that case.  (and we want to avoid multiple checks...)
     for (; aJob.offset < aJob.items.length; aJob.offset++) {
       let item = aJob.items[aJob.offset];
       // item is either [folder ID, message key] or
       //                [folder ID, message ID]
 
@@ -1500,17 +1525,17 @@ var GlodaMsgIndexer = {
       else
         // same deal as in move processing.
         // TODO fixme to not assume singular message-id's.
         msgHdr = this._indexingDatabase.getMsgHdrForMessageID(item[1]);
 
       if (msgHdr)
         yield aCallbackHandle.pushAndGo(
           this._indexMessage(msgHdr, aCallbackHandle),
-          {what: "indexMessage", msgHdr});
+          {what: "indexMessage", msgHdr: msgHdr});
       else
         yield this.kWorkSync;
     }
 
     // There is no real reason to stay 'in' the folder.  If we are going to get
     //  more events from the folder, its database would have to be open for us
     //  to get the events, so it's not like we're creating an efficiency
     //  problem where we unload a folder just to load it again in 2 seconds.
@@ -1532,17 +1557,19 @@ var GlodaMsgIndexer = {
    *     invoke pushAndGo for _indexMessage we put something in so we can
    *     detect when it is on the async stack.
    * @param aException The exception that is necessitating we attempt to
    *     recover.
    *
    * @return 1 if we were able to recover (because we want the call stack
    *     popped down to our worker), false if we can't.
    */
-  _recover_indexMessage(aJob, aContextStack, aException) {
+  _recover_indexMessage:
+      function gloda_index_recover_indexMessage(aJob, aContextStack,
+                                                aException) {
     // See if indexMessage is on the stack...
     if (aContextStack.length >= 2 &&
         aContextStack[1] &&
         ("what" in aContextStack[1]) &&
         aContextStack[1].what == "indexMessage") {
       // it is, so this is probably recoverable.
 
       this._log.debug(
@@ -1553,17 +1580,18 @@ var GlodaMsgIndexer = {
       // (In the worst case, the header is no longer valid, which will result in
       //  exceptions.  We need to be prepared for that.)
       try {
         msgHdr.setUint32Property(GLODA_MESSAGE_ID_PROPERTY,
                                  GLODA_BAD_MESSAGE_ID);
         // clear the dirty bit if it has one
         if (msgHdr.getUint32Property(GLODA_DIRTY_PROPERTY))
           msgHdr.setUint32Property(GLODA_DIRTY_PROPERTY, 0);
-      } catch (ex) {
+      }
+      catch (ex) {
         // If we are indexing a folder and the message header is no longer
         //  valid, then it's quite likely the whole folder is no longer valid.
         //  But since in the event-driven message indexing case we could have
         //  other valid things to look at, let's try and recover.  The folder
         //  indexing case will come back to us shortly and we will indicate
         //  recovery is not possible at that point.
         // So do nothing here since by popping the indexing of the specific
         //  message out of existence we are recovering.
@@ -1571,31 +1599,33 @@ var GlodaMsgIndexer = {
       return 1;
     }
     return false;
   },
 
   /**
    * Cleanup after an aborted "folder" or "message" job.
    */
-  _cleanup_indexing(aJob) {
+  _cleanup_indexing: function gloda_index_cleanup_indexing(aJob) {
     this._indexerLeaveFolder();
     aJob.safelyInvokeCallback(false);
   },
 
   /**
    * Maximum number of deleted messages to process at a time.  Arbitrary; there
    *  are no real known performance constraints at this point.
    */
   DELETED_MESSAGE_BLOCK_SIZE: 32,
 
   /**
    * Process pending deletes...
    */
-  * _worker_processDeletes(aJob, aCallbackHandle) {
+  _worker_processDeletes: function* gloda_worker_processDeletes(aJob,
+      aCallbackHandle) {
+
     // Count the number of messages we will eventually process.  People freak
     //  out when the number is constantly increasing because they think gloda
     //  has gone rogue.  (Note: new deletions can still accumulate during
     //  our execution, so we may 'expand' our count a little still.)
     this._datastore.countDeletedMessages(aCallbackHandle.wrappedCallback);
     aJob.goal = yield this.kWorkAsync;
     this._log.debug("There are currently " + aJob.goal + " messages awaiting" +
                     " deletion processing.");
@@ -1628,43 +1658,43 @@ var GlodaMsgIndexer = {
       deletedCollection = query.getCollection(aCallbackHandle);
       yield this.kWorkAsync;
     }
     this.pendingDeletions = false;
 
     yield this.kWorkDone;
   },
 
-  * _worker_fixMissingContacts(aJob, aCallbackHandle) {
-    let identityContactInfos = [];
+  _worker_fixMissingContacts: function*(aJob, aCallbackHandle) {
+    let identityContactInfos = [], fixedContacts = {};
 
     // -- asynchronously get a list of all identities without contacts
     // The upper bound on the number of messed up contacts is the number of
     //  contacts in the user's address book.  This should be small enough
     //  (and the data size small enough) that this won't explode thunderbird.
     let queryStmt = GlodaDatastore._createAsyncStatement(
       "SELECT identities.id, identities.contactID, identities.value " +
         "FROM identities " +
         "LEFT JOIN contacts ON identities.contactID = contacts.id " +
         "WHERE identities.kind = 'email' AND contacts.id IS NULL",
       true);
     queryStmt.executeAsync({
-      handleResult(aResultSet) {
+      handleResult: function(aResultSet) {
         let row;
         while ((row = aResultSet.getNextRow())) {
           identityContactInfos.push({
             identityId: row.getInt64(0),
             contactId: row.getInt64(1),
-            email: row.getString(2),
+            email: row.getString(2)
           });
         }
       },
-      handleError(aError) {
+      handleError: function(aError) {
       },
-      handleCompletion(aReason) {
+      handleCompletion: function(aReason) {
         GlodaDatastore._asyncCompleted();
         aCallbackHandle.wrappedCallback();
       },
     });
     queryStmt.finalize();
     GlodaDatastore._pendingAsyncStatements++;
     yield this.kWorkAsync;
 
@@ -1728,17 +1758,17 @@ var GlodaMsgIndexer = {
   /**
    * Determine whether a folder is suitable for indexing.
    *
    * @param aMsgFolder An nsIMsgFolder you want to see if we should index.
    *
    * @returns true if we want to index messages in this type of folder, false if
    *     we do not.
    */
-  shouldIndexFolder(aMsgFolder) {
+  shouldIndexFolder: function(aMsgFolder) {
     let folderFlags = aMsgFolder.flags;
     // Completely ignore non-mail and virtual folders.  They should never even
     //  get to be GlodaFolder instances.
     if (!(folderFlags & Ci.nsMsgFolderFlags.Mail) ||
         (folderFlags & Ci.nsMsgFolderFlags.Virtual))
       return false;
 
     // Some folders do not really exist; we can detect this by getStringProperty
@@ -1764,17 +1794,18 @@ var GlodaMsgIndexer = {
    * and, for backup purposes, to the nsIMsgFolder via string property as well.
    *
    * Setting this priority may cause the indexer to either reindex this folder,
    * or remove this folder from the existing index.
    *
    * @param {nsIMsgFolder} aFolder
    * @param {Number} aPriority (one of the priority constants from GlodaFolder)
    */
-  setFolderIndexingPriority(aFolder, aPriority) {
+  setFolderIndexingPriority: function glodaSetFolderIndexingPriority(aFolder, aPriority) {
+
     let glodaFolder = GlodaDatastore._mapFolder(aFolder);
 
     // if there's been no change, we're done
     if (aPriority == glodaFolder.indexingPriority) {
       return;
     }
 
     // save off the old priority, and set the new one
@@ -1782,97 +1813,102 @@ var GlodaMsgIndexer = {
     glodaFolder._indexingPriority = aPriority;
 
     // persist the new priority
     GlodaDatastore.updateFolderIndexingPriority(glodaFolder);
     aFolder.setStringProperty("indexingPriority", Number(aPriority).toString());
 
     // if we've been told never to index this folder...
     if (aPriority == glodaFolder.kIndexingNeverPriority) {
+
       // stop doing so
       if (this._indexingFolder == aFolder)
           GlodaIndexer.killActiveJob();
 
       // mark all existing messages as deleted
       GlodaDatastore.markMessagesDeletedByFolderID(glodaFolder.id);
 
       // re-index
       GlodaMsgIndexer.indexingSweepNeeded = true;
+
     } else if (previousPrio == glodaFolder.kIndexingNeverPriority) {
+
       // there's no existing index, but the user now wants one
       glodaFolder._dirtyStatus = glodaFolder.kFolderFilthy;
-      GlodaDatastore.updateFolderDirtyStatus(glodaFolder);
+      GlodaDatastore.updateFolderDirtyStatus(glodaFolder)
       GlodaMsgIndexer.indexingSweepNeeded = true;
     }
   },
 
   /**
    * Resets the indexing priority on the given folder to whatever the default
    * is for folders of that type.
    *
    * @note Calls setFolderIndexingPriority under the hood, so has identical
    *       potential reindexing side-effects
    *
    * @param {nsIMsgFolder} aFolder
    * @param {boolean} aAllowSpecialFolderIndexing
    */
-  resetFolderIndexingPriority(aFolder, aAllowSpecialFolderIndexing) {
+  resetFolderIndexingPriority: function glodaResetFolderIndexingPriority(aFolder, aAllowSpecialFolderIndexing) {
     this.setFolderIndexingPriority(aFolder,
       GlodaDatastore.getDefaultIndexingPriority(aFolder,
                                                 aAllowSpecialFolderIndexing));
   },
 
   /**
    * Queue all of the folders of all of the accounts of the current profile
    *  for indexing.  We traverse all folders and queue them immediately to try
    *  and have an accurate estimate of the number of folders that need to be
    *  indexed.  (We previously queued accounts rather than immediately
    *  walking their list of folders.)
    */
-  indexEverything() {
+  indexEverything: function glodaIndexEverything() {
     this._log.info("Queueing all accounts for indexing.");
 
     GlodaDatastore._beginTransaction();
     for (let account of fixIterator(MailServices.accounts.accounts,
                                     Ci.nsIMsgAccount)) {
       this.indexAccount(account);
     }
     GlodaDatastore._commitTransaction();
   },
 
   /**
    * Queue all of the folders belonging to an account for indexing.
    */
-  indexAccount(aAccount) {
+  indexAccount: function glodaIndexAccount(aAccount) {
     let rootFolder = aAccount.incomingServer.rootFolder;
     if (rootFolder instanceof Ci.nsIMsgFolder) {
       this._log.info("Queueing account folders for indexing: " + aAccount.key);
 
       let allFolders = rootFolder.descendants;
+      let folderJobs = [];
       for (let folder of fixIterator(allFolders, Ci.nsIMsgFolder)) {
         if (this.shouldIndexFolder(folder))
           GlodaIndexer.indexJob(
             new IndexingJob("folder", GlodaDatastore._mapFolder(folder).id));
       }
-    } else {
+    }
+    else {
       this._log.info("Skipping Account, root folder not nsIMsgFolder");
     }
   },
 
   /**
    * Queue a single folder for indexing given an nsIMsgFolder.
    *
    * @param [aOptions.callback] A callback to invoke when the folder finishes
    *     indexing.  First argument is true if the task ran to completion
    *     successfully, false if we had to abort for some reason.
    * @param [aOptions.force=false] Should we force the indexing of all messages
    *     in the folder (true) or just index what hasn't been indexed (false).
    * @return true if we are going to index the folder, false if not.
    */
-  indexFolder(aMsgFolder, aOptions) {
+  indexFolder: function glodaIndexFolder(aMsgFolder, aOptions) {
     if (!this.shouldIndexFolder(aMsgFolder))
       return false;
     let glodaFolder = GlodaDatastore._mapFolder(aMsgFolder);
     // stay out of compacting/compacted folders
     if (glodaFolder.compacting || glodaFolder.compacted)
       return false;
 
     this._log.info("Queue-ing folder for indexing: " +
@@ -1888,34 +1924,34 @@ var GlodaMsgIndexer = {
     return true;
   },
 
   /**
    * Queue a list of messages for indexing.
    *
    * @param aFoldersAndMessages List of [nsIMsgFolder, message key] tuples.
    */
-  indexMessages(aFoldersAndMessages) {
+  indexMessages: function gloda_index_indexMessages(aFoldersAndMessages) {
     let job = new IndexingJob("message", null);
     job.items = aFoldersAndMessages.
       map(fm => [GlodaDatastore._mapFolder(fm[0]).id, fm[1]]);
     GlodaIndexer.indexJob(job);
   },
 
   /**
    * Mark all known folders as dirty so that the next indexing sweep goes
    *  into all folders and checks their contents to see if they need to be
    *  indexed.
    *
    * This is being added for the migration case where we want to try and reindex
    *  all of the messages that had been marked with GLODA_BAD_MESSAGE_ID but
    *  which is now GLODA_OLD_BAD_MESSAGE_ID and so we should attempt to reindex
    *  them.
    */
-  dirtyAllKnownFolders() {
+  dirtyAllKnownFolders: function gloda_index_msg_dirtyAllKnownFolders() {
     // Just iterate over the datastore's folder map and tell each folder to
     //  be dirty if its priority is not disabled.
     for (let folderID in GlodaDatastore._folderByID) {
       let glodaFolder = GlodaDatastore._folderByID[folderID];
       if (glodaFolder.indexingPriority !== glodaFolder.kIndexingNeverPriority)
         glodaFolder._ensureFolderDirty();
     }
   },
@@ -1927,17 +1963,17 @@ var GlodaMsgIndexer = {
    * This means the message must:
    * - Be in a folder eligible for gloda indexing. (Not News, etc.)
    * - Be in a non-filthy folder.
    * - Be gloda-indexed and non-filthy.
    *
    * @param aMsgHdr A message header.
    * @returns true if the message is likely to have been indexed.
    */
-  isMessageIndexed(aMsgHdr) {
+  isMessageIndexed: function gloda_index_isMessageIndexed(aMsgHdr) {
     // If it's in a folder that we flat out do not index, say no.
     if (!this.shouldIndexFolder(aMsgHdr.folder))
       return false;
     let glodaFolder = GlodaDatastore._mapFolder(aMsgHdr.folder);
     let [glodaId, glodaDirty] = PendingCommitTracker.getGlodaState(aMsgHdr);
     return glodaId >= GLODA_FIRST_VALID_MESSAGE_ID &&
            glodaDirty != GlodaMsgIndexer.kMessageFilthy &&
            glodaFolder &&
@@ -1986,17 +2022,18 @@ var GlodaMsgIndexer = {
    *     for user action to do something that dirties the message between the
    *     time we get the msgKeyChanged notification and when we receive the
    *     msgsClassified notification, we want to make sure we don't get
    *     confused.  (Although since we remove the message from our ignore-set
    *     after the first notification, we would likely just mistakenly treat
    *     the msgsClassified notification as something dirtying, so it would
    *     still work out...)
    */
-  _reindexChangedMessages(aMsgHdrs, aDirtyingEvent) {
+  _reindexChangedMessages: function gloda_indexer_reindexChangedMessage(
+                                      aMsgHdrs, aDirtyingEvent) {
     let glodaIdsNeedingDeletion = null;
     let messageKeyChangedIds = null, messageKeyChangedNewKeys = null;
     for (let msgHdr of fixIterator(aMsgHdrs, Ci.nsIMsgDBHdr)) {
       // -- Index this folder?
       let msgFolder = msgHdr.folder;
       if (!this.shouldIndexFolder(msgFolder)) {
         continue;
       }
@@ -2075,34 +2112,37 @@ var GlodaMsgIndexer = {
         //  indexing sweep takes care of things if we don't process this in
         //  an event-driven fashion.  If the message has no gloda-id or does
         //  and it's already dirty or filthy, it is already marked for
         //  indexing.)
         if (glodaDirty == this.kMessageClean)
           msgHdr.setUint32Property(GLODA_DIRTY_PROPERTY, this.kMessageDirty);
         // if the message is pending clean, this change invalidates that.
         PendingCommitTracker.noteDirtyHeader(msgHdr);
-      } else if (isSpam) { // If it's not indexed but is spam, ignore it.
+      }
+      // If it's not indexed but is spam, ignore it.
+      else if (isSpam) {
         continue;
       }
       // (we want to index the message if we are here)
 
       // mark the folder dirty too, so we know to look inside
       glodaFolder._ensureFolderDirty();
 
       if (this._pendingAddJob == null) {
         this._pendingAddJob = new IndexingJob("message", null);
         GlodaIndexer.indexJob(this._pendingAddJob);
       }
       // only queue the message if we haven't overflowed our event-driven budget
       if (this._pendingAddJob.items.length <
           this._indexMaxEventQueueMessages) {
         this._pendingAddJob.items.push(
           [GlodaDatastore._mapFolder(msgFolder).id, msgHdr.messageKey]);
-      } else {
+      }
+      else {
         this.indexingSweepNeeded = true;
       }
     }
 
     // Process any message key changes (from earlier msgKeyChanged events)
     if (messageKeyChangedIds != null)
       GlodaDatastore.updateMessageKeys(messageKeyChangedIds,
                                        messageKeyChangedNewKeys);
@@ -2129,37 +2169,39 @@ var GlodaMsgIndexer = {
   _msgFolderListener: {
     indexer: null,
 
     /**
      * We no longer use the msgAdded notification, instead opting to wait until
      *  junk/trait classification has run (or decided not to run) and all
      *  filters have run.  The msgsClassified notification provides that for us.
      */
-    msgAdded(aMsgHdr) {
+    msgAdded: function gloda_indexer_msgAdded(aMsgHdr) {
       // we are never called! we do not enable this bit!
     },
 
     /**
      * Process (apparently newly added) messages that have been looked at by
      *  the message classifier.  This ensures that if the message was going
      *  to get marked as spam, this will have already happened.
      *
      * Besides truly new (to us) messages, We will also receive this event for
      *  messages that are the result of IMAP message move/copy operations,
      *  including both moves that generated offline fake headers and those that
      *  did not.  In the offline fake header case, however, we are able to
      *  ignore their msgsClassified events because we will have received a
      *  msgKeyChanged notification sometime in the recent past.
      */
-    msgsClassified(aMsgHdrs, aJunkClassified, aTraitClassified) {
+    msgsClassified: function gloda_indexer_msgsClassified(
+                      aMsgHdrs, aJunkClassified, aTraitClassified) {
       this.indexer._log.debug("msgsClassified notification");
       try {
         GlodaMsgIndexer._reindexChangedMessages(aMsgHdrs.enumerate(), false);
-      } catch (ex) {
+      }
+      catch (ex) {
         this.indexer._log.error("Explosion in msgsClassified handling:", ex);
       }
     },
 
     /**
      * Handle real, actual deletion (move to trash and IMAP deletion model
      *  don't count); we only see the deletion here when it becomes forever,
      *  or rather _just before_ it becomes forever.  Because the header is
@@ -2167,17 +2209,17 @@ var GlodaMsgIndexer = {
      *  information required to purge it later without the header.
      * To this end, we mark all messages that were indexed in the gloda message
      *  database as deleted.  We set our pending deletions flag to let our
      *  indexing logic know that after its next wave of folder traversal, it
      *  should perform a deletion pass.  If it turns out the messages are coming
      *  back, the fact that deletion is thus deferred can be handy, as we can
      *  reuse the existing gloda message.
      */
-    msgsDeleted(aMsgHdrs) {
+    msgsDeleted: function gloda_indexer_msgsDeleted(aMsgHdrs) {
       this.indexer._log.debug("msgsDeleted notification");
       let glodaMessageIds = [];
 
       for (let iMsgHdr = 0; iMsgHdr < aMsgHdrs.length; iMsgHdr++) {
         let msgHdr = aMsgHdrs.queryElementAt(iMsgHdr, Ci.nsIMsgDBHdr);
         let [glodaId, glodaDirty] = PendingCommitTracker.getGlodaState(msgHdr);
         if (glodaId >= GLODA_FIRST_VALID_MESSAGE_ID &&
             glodaDirty != GlodaMsgIndexer.kMessageFilthy)
@@ -2231,17 +2273,18 @@ var GlodaMsgIndexer = {
      * Because copied messages are, by their nature, duplicate messages, we
      *  do not particularly care about them.  As such, we defer their processing
      *  to the automatic sync logic that will happen much later on.  This is
      *  potentially desirable in case the user deletes some of the original
      *  messages, allowing us to reuse the gloda message representations when
      *  we finally get around to indexing the messages.  We do need to mark the
      *  folder as dirty, though, to clue in the sync logic.
      */
-    msgsMoveCopyCompleted(aMove, aSrcMsgHdrs, aDestFolder, aDestMsgHdrs) {
+    msgsMoveCopyCompleted: function gloda_indexer_msgsMoveCopyCompleted(aMove,
+                             aSrcMsgHdrs, aDestFolder, aDestMsgHdrs) {
       this.indexer._log.debug("MoveCopy notification.  Move: " + aMove);
       try {
         // ---- Move
         if (aMove) {
           // -- Effectively a deletion?
           // If the destination folder is not indexed, it's like these messages
           //  are being deleted.
           if (!GlodaMsgIndexer.shouldIndexFolder(aDestFolder)) {
@@ -2273,46 +2316,48 @@ var GlodaMsgIndexer = {
               }
 
               // Since we are moving messages from a folder where they were
               //  effectively not indexed, it is up to us to make sure the
               //  messages now get indexed.
               this.indexer._reindexChangedMessages(aDestMsgHdrs.enumerate());
               return;
             }
-
             // IMAP move case, we need to operate on the pending headers using
             //  the source header to get the pending header and as the
             //  indication of what has been already set on the pending header.
-            let destDb;
-            // so, this can fail, and there's not much we can do about it.
-            try {
-              destDb = aDestFolder.msgDatabase;
-            } catch (ex) {
-              this.indexer._log.warn("Destination database for " +
-                                     aDestFolder.prettyName +
-                                     " not ready on IMAP move." +
-                                     " Gloda corruption possible.");
+            else {
+              let destDb;
+              // so, this can fail, and there's not much we can do about it.
+              try {
+                destDb = aDestFolder.msgDatabase;
+              } catch (ex) {
+                this.indexer._log.warn("Destination database for " +
+                                       aDestFolder.prettyName +
+                                       " not ready on IMAP move." +
+                                       " Gloda corruption possible.");
+                return;
+              }
+              for (let srcMsgHdr of fixIterator(aSrcMsgHdrs, Ci.nsIMsgDBHdr)) {
+                // zero it out if it exists
+                // (no need to deal with pending commit issues here; a filthy
+                //  folder by definition has nothing indexed in it.)
+                let glodaId = srcMsgHdr.getUint32Property(
+                                GLODA_MESSAGE_ID_PROPERTY);
+                if (glodaId)
+                  destDb.setUint32AttributeOnPendingHdr(
+                    srcMsgHdr, GLODA_MESSAGE_ID_PROPERTY, 0);
+              }
+
+              // Nothing remains to be done.  The msgClassified event will take
+              //  care of making sure the message gets indexed.
               return;
             }
-            for (let srcMsgHdr of fixIterator(aSrcMsgHdrs, Ci.nsIMsgDBHdr)) {
-              // zero it out if it exists
-              // (no need to deal with pending commit issues here; a filthy
-              //  folder by definition has nothing indexed in it.)
-              let glodaId = srcMsgHdr.getUint32Property(
-                              GLODA_MESSAGE_ID_PROPERTY);
-              if (glodaId)
-                destDb.setUint32AttributeOnPendingHdr(
-                  srcMsgHdr, GLODA_MESSAGE_ID_PROPERTY, 0);
-            }
+          }
 
-            // Nothing remains to be done.  The msgClassified event will take
-            //  care of making sure the message gets indexed.
-            return;
-          }
 
           // --- Have destination headers (local case):
           if (aDestMsgHdrs) {
             // -- Update message keys for valid gloda-id's.
             // (Which means ignore filthy gloda-id's.)
             let glodaIds = [];
             let newMessageKeys = [];
             aSrcMsgHdrs.QueryInterface(Ci.nsIArray);
@@ -2328,17 +2373,18 @@ var GlodaMsgIndexer = {
                 PendingCommitTracker.getGlodaState(srcMsgHdr);
               if (glodaId >= GLODA_FIRST_VALID_MESSAGE_ID &&
                   dirtyStatus != GlodaMsgIndexer.kMessageFilthy) {
                 // we may need to update the pending commit map (it checks)
                 PendingCommitTracker.noteMove(srcMsgHdr, destMsgHdr);
                 // but we always need to update our database
                 glodaIds.push(glodaId);
                 newMessageKeys.push(destMsgHdr.messageKey);
-              } else {
+              }
+              else {
                 sawNonGlodaMessage = true;
               }
             }
 
             // this method takes care to update the in-memory representations
             //  too; we don't need to do anything
             if (glodaIds.length)
               GlodaDatastore.updateMessageLocations(glodaIds, newMessageKeys,
@@ -2346,21 +2392,22 @@ var GlodaMsgIndexer = {
 
             // Mark the destination folder dirty if we saw any messages that
             //  were not already gloda indexed.
             if (sawNonGlodaMessage) {
               let destGlodaFolder = GlodaDatastore._mapFolder(aDestFolder);
               destGlodaFolder._ensureFolderDirty();
               this.indexer.indexingSweepNeeded = true;
             }
-          } else {
-            // --- No dest headers (IMAP case):
-            // Update any valid gloda indexed messages into their new folder to
-            //  make the indexer's life easier when it sees the messages in their
-            //  new folder.
+          }
+          // --- No dest headers (IMAP case):
+          // Update any valid gloda indexed messages into their new folder to
+          //  make the indexer's life easier when it sees the messages in their
+          //  new folder.
+          else {
             let glodaIds = [];
 
             let srcFolderIsLocal =
               (srcMsgFolder instanceof Ci.nsIMsgLocalMailFolder);
             for (let iMsgHdr = 0; iMsgHdr < aSrcMsgHdrs.length; iMsgHdr++) {
               let msgHdr = aSrcMsgHdrs.queryElementAt(iMsgHdr, Ci.nsIMsgDBHdr);
 
               let [glodaId, dirtyStatus] =
@@ -2393,17 +2440,19 @@ var GlodaMsgIndexer = {
             }
 
             // quickly move them to the right folder, zeroing their message keys
             GlodaDatastore.updateMessageFoldersByKeyPurging(glodaIds,
                                                             aDestFolder);
             // we _do not_ need to mark the folder as dirty, because the
             //  message added events will cause that to happen.
           }
-        } else { // ---- Copy case
+        }
+        // ---- Copy case
+        else {
           // -- Do not propagate gloda-id's for copies
           // (Only applies if we have the destination header, which means local)
           if (aDestMsgHdrs) {
             for (let destMsgHdr of fixIterator(aDestMsgHdrs, Ci.nsIMsgDBHdr)) {
               let glodaId = destMsgHdr.getUint32Property(
                 GLODA_MESSAGE_ID_PROPERTY);
               if (glodaId)
                 destMsgHdr.setUint32Property(GLODA_MESSAGE_ID_PROPERTY, 0);
@@ -2428,17 +2477,18 @@ var GlodaMsgIndexer = {
      *  actual work (if there is any to be done; the fake header might have
      *  guessed the right UID correctly) so that we can batch our work.
      *
      * The expectation is that there will be no meaningful time window between
      *  this notification and the msgsClassified notification since the message
      *  classifier should not actually need to classify the messages (they
      *  should already have been classified) and so can fast-path them.
      */
-    msgKeyChanged(aOldMsgKey, aNewMsgHdr) {
+    msgKeyChanged: function gloda_indexer_msgKeyChangeded(aOldMsgKey,
+                             aNewMsgHdr) {
       try {
         let val = null, newKey = aNewMsgHdr.messageKey;
         let [glodaId, glodaDirty] =
           PendingCommitTracker.getGlodaState(aNewMsgHdr);
         // If we haven't indexed this message yet, take no action, and leave it
         // up to msgsClassified to take proper action.
         if (glodaId < GLODA_FIRST_VALID_MESSAGE_ID)
           return;
@@ -2451,58 +2501,60 @@ var GlodaMsgIndexer = {
             id: glodaId,
             key: (aOldMsgKey !== newKey) ? newKey : null,
             isDirty: glodaDirty === GlodaMsgIndexer.kMessageDirty,
           };
         }
 
         let key = aNewMsgHdr.folder.URI + "#" + aNewMsgHdr.messageKey;
         this.indexer._keyChangedBatchInfo[key] = val;
-      } catch (ex) {
-        // this is more for the unit test to fail rather than user error reporting
+      }
+      // this is more for the unit test to fail rather than user error reporting
+      catch (ex) {
         this.indexer._log.error("Problem encountered during msgKeyChanged" +
                                 " notification handling: " + ex + "\n\n" +
                                 ex.stack + " \n\n");
       }
     },
 
     /**
      * Detect newly added folders before they get messages so we map them before
      * they get any messages added to them.  If we only hear about them after
      * they get their 1st message, then we will mark them filthy, but if we mark
      * them before that, they get marked clean.
      */
-    folderAdded(aMsgFolder) {
+    folderAdded: function gloda_indexer_folderAdded(aMsgFolder) {
       // This is invoked for its side-effect of invoking _mapFolder and doing so
       // only after filtering out folders we don't care about.
       GlodaMsgIndexer.shouldIndexFolder(aMsgFolder);
     },
 
     /**
      * Handles folder no-longer-exists-ence.  We mark all messages as deleted
      *  and remove the folder from our URI table.  Currently, if a folder that
      *  contains other folders is deleted, we may either receive one
      *  notification for the folder that is deleted, or a notification for the
      *  folder and one for each of its descendents.  This depends upon the
      *  underlying account implementation, so we explicitly handle each case.
      *  Namely, we treat it as if we're only planning on getting one, but we
      *  handle if the children are already gone for some reason.
      */
-    folderDeleted(aFolder) {
+    folderDeleted: function gloda_indexer_folderDeleted(aFolder) {
       this.indexer._log.debug("folderDeleted notification");
       try {
         let delFunc = function(aFolder, indexer) {
           if (indexer._datastore._folderKnown(aFolder)) {
             indexer._log.info("Processing deletion of folder " +
                               aFolder.prettyName + ".");
             let glodaFolder = GlodaDatastore._mapFolder(aFolder);
             indexer._datastore.markMessagesDeletedByFolderID(glodaFolder.id);
             indexer._datastore.deleteFolderByID(glodaFolder.id);
             GlodaDatastore._killGlodaFolderIntoTombstone(glodaFolder);
-          } else {
+          }
+          else {
             indexer._log.info("Ignoring deletion of folder " +
                               aFolder.prettyName +
                               " because it is unknown to gloda.");
           }
         };
 
         let descendentFolders = aFolder.descendants;
         // (the order of operations does not matter; child, non-child, whatever.)
@@ -2524,38 +2576,41 @@ var GlodaMsgIndexer = {
      * Handle a folder being copied or moved.
      * Moves are handled by a helper function shared with _folderRenameHelper
      *  (which takes care of any nesting involved).
      * Copies are actually ignored, because our periodic indexing traversal
      *  should discover these automatically.  We could hint ourselves into
      *  action, but arguably a set of completely duplicate messages is not
      *  a high priority for indexing.
      */
-    folderMoveCopyCompleted(aMove, aSrcFolder, aDestFolder) {
+    folderMoveCopyCompleted: function gloda_indexer_folderMoveCopyCompleted(
+                               aMove, aSrcFolder, aDestFolder) {
       this.indexer._log.debug("folderMoveCopy notification (Move: " + aMove
                               + ")");
       if (aMove) {
         let srcURI = aSrcFolder.URI;
         let targetURI = aDestFolder.URI +
                         srcURI.substring(srcURI.lastIndexOf("/"));
         this._folderRenameHelper(aSrcFolder, targetURI);
-      } else {
+      }
+      else {
         this.indexer.indexingSweepNeeded = true;
       }
     },
 
     /**
      * We just need to update the URI <-> ID maps and the row in the database,
      *  all of which is actually done by the datastore for us.
      * This method needs to deal with the complexity where local folders will
      *  generate a rename notification for each sub-folder, but IMAP folders
      *  will generate only a single notification.  Our logic primarily handles
      *  this by not exploding if the original folder no longer exists.
      */
-    _folderRenameHelper(aOrigFolder, aNewURI) {
+    _folderRenameHelper: function gloda_indexer_folderRenameHelper(aOrigFolder,
+                                                                   aNewURI) {
       let newFolder = MailUtils.getOrCreateFolder(aNewURI);
       let specialFolderFlags = Ci.nsMsgFolderFlags.Trash | Ci.nsMsgFolderFlags.Junk;
       if (newFolder.isSpecialFolder(specialFolderFlags, true)) {
         let descendentFolders = newFolder.descendants;
 
         // First thing to do: make sure we don't index the resulting folder and
         //  its descendents.
         GlodaMsgIndexer.resetFolderIndexingPriority(newFolder);
@@ -2584,17 +2639,18 @@ var GlodaMsgIndexer = {
         this.indexer._log.debug("folder renamed: " + origURI + " to " + aNewURI);
       }
     },
 
     /**
      * Handle folder renames, dispatching to our rename helper (which also
      *  takes care of any nested folder issues.)
      */
-    folderRenamed(aOrigFolder, aNewFolder) {
+    folderRenamed: function gloda_indexer_folderRenamed(aOrigFolder,
+                                                        aNewFolder) {
       this._folderRenameHelper(aOrigFolder, aNewFolder.URI);
     },
 
     /**
      * This tells us about many exciting things.  What they are and what we do:
      *
      * - FolderCompactStart: Mark the folder as compacting in our in-memory
      *    representation.  This should keep any new indexing out of the folder
@@ -2605,32 +2661,32 @@ var GlodaMsgIndexer = {
      *    not marked filthy, queue a compaction job.
      *
      * - FolderReindexTriggered: We do the same thing as FolderCompactStart
      *    but don't mark the folder as compacting.
      *
      * - JunkStatusChanged: We mark the messages that have had their junk
      *    state change to be reindexed.
      */
-    itemEvent(aItem, aEvent, aData, aString) {
+    itemEvent: function gloda_indexer_itemEvent(aItem, aEvent, aData, aString) {
       // Compact and Reindex are close enough that we can reuse the same code
       //  with one minor difference.
       if (aEvent == "FolderCompactStart" ||
           aEvent == "FolderReindexTriggered") {
         let aMsgFolder = aItem.QueryInterface(Ci.nsIMsgFolder);
         // ignore folders we ignore...
         if (!GlodaMsgIndexer.shouldIndexFolder(aMsgFolder))
           return;
 
         let glodaFolder = GlodaDatastore._mapFolder(aMsgFolder);
         if (aEvent == "FolderCompactStart")
           glodaFolder.compacting = true;
 
         // Purge any explicit indexing of said folder.
-        GlodaIndexer.purgeJobsUsingFilter(function(aJob) {
+        GlodaIndexer.purgeJobsUsingFilter(function (aJob) {
           return (aJob.jobType == "folder" &&
                   aJob.id == aMsgFolder.id);
         });
 
         // Abort the active job if it's in the folder (this covers both
         //  event-driven indexing that happens to be in the folder as well
         //  explicit folder indexing of the folder).
         if (GlodaMsgIndexer._indexingFolder == aMsgFolder)
@@ -2638,17 +2694,18 @@ var GlodaMsgIndexer = {
 
         // Tell the PendingCommitTracker to throw away anything it is tracking
         //  about the folder.  We will pick up the pieces in the compaction
         //  pass.
         PendingCommitTracker.noteFolderDatabaseGettingBlownAway(aMsgFolder);
 
         // (We do not need to mark the folder dirty because if we were indexing
         //  it, it already must have been marked dirty.)
-      } else if (aEvent == "FolderCompactFinish") {
+      }
+      else if (aEvent == "FolderCompactFinish") {
         let aMsgFolder = aItem.QueryInterface(Ci.nsIMsgFolder);
         // ignore folders we ignore...
         if (!GlodaMsgIndexer.shouldIndexFolder(aMsgFolder))
           return;
 
         let glodaFolder = GlodaDatastore._mapFolder(aMsgFolder);
         glodaFolder.compacting = false;
         glodaFolder._setCompactedState(true);
@@ -2662,17 +2719,18 @@ var GlodaMsgIndexer = {
         // Queue indexing of the folder if it is dirty.  We are doing this
         //  mainly in case we were indexing it before the compaction started.
         //  It should be reasonably harmless if we weren't.
         // (It would probably be better to just make sure that there is an
         //  indexing sweep queued or active, and if it's already active that
         //  this folder is in the queue to be processed.)
         if (glodaFolder.dirtyStatus == glodaFolder.kFolderDirty)
           GlodaIndexer.indexJob(new IndexingJob("folder", glodaFolder.id));
-      } else if (aEvent == "JunkStatusChanged") {
+      }
+      else if (aEvent == "JunkStatusChanged") {
         this.indexer._log.debug("JunkStatusChanged notification");
         aItem.QueryInterface(Ci.nsIArray);
         GlodaMsgIndexer._reindexChangedMessages(aItem.enumerate(), true);
       }
     },
   },
 
   /**
@@ -2680,68 +2738,75 @@ var GlodaMsgIndexer = {
    *  these events) PRIMARILY to get folder loaded notifications.  Because of
    *  deficiencies in the nsIMsgFolderListener's events at this time, we also
    *  get our folder-added and newsgroup notifications from here for now.  (This
    *  will be rectified.)
    */
   _folderListener: {
     indexer: null,
 
-    _init(aIndexer) {
+    _init: function gloda_indexer_fl_init(aIndexer) {
       this.indexer = aIndexer;
     },
 
-    OnItemAdded(aParentItem, aItem) {
+    OnItemAdded: function gloda_indexer_OnItemAdded(aParentItem, aItem) {
     },
-    OnItemRemoved(aParentItem, aItem) {
+    OnItemRemoved: function gloda_indexer_OnItemRemoved(aParentItem, aItem) {
     },
-    OnItemPropertyChanged(aItem, aProperty, aOldValue, aNewValue) {
+    OnItemPropertyChanged: function gloda_indexer_OnItemPropertyChanged(
+                             aItem, aProperty, aOldValue, aNewValue) {
     },
     /**
      * Detect changes to folder flags and reset our indexing priority.  This
      * is important because (all?) folders start out without any flags and
      * then get their flags added to them.
      */
-    OnItemIntPropertyChanged(aFolderItem, aProperty, aOldValue, aNewValue) {
+    OnItemIntPropertyChanged: function gloda_indexer_OnItemIntPropertyChanged(
+                                aFolderItem, aProperty, aOldValue, aNewValue) {
       if (aProperty !== "FolderFlag")
         return;
       if (!GlodaMsgIndexer.shouldIndexFolder(aFolderItem))
         return;
       // Only reset priority if folder Special Use changes.
       if ((aOldValue & Ci.nsMsgFolderFlags.SpecialUse) ==
           (aNewValue & Ci.nsMsgFolderFlags.SpecialUse))
         return;
       GlodaMsgIndexer.resetFolderIndexingPriority(aFolderItem);
     },
-    OnItemBoolPropertyChanged(aItem, aProperty, aOldValue, aNewValue) {
+    OnItemBoolPropertyChanged: function gloda_indexer_OnItemBoolPropertyChanged(
+                                aItem, aProperty, aOldValue, aNewValue) {
     },
-    OnItemUnicharPropertyChanged(aItem, aProperty, aOldValue, aNewValue) {
+    OnItemUnicharPropertyChanged:
+        function gloda_indexer_OnItemUnicharPropertyChanged(
+          aItem, aProperty, aOldValue, aNewValue) {
+
     },
     /**
      * Notice when user activity adds/removes tags or changes a message's
      *  status.
      */
-    OnItemPropertyFlagChanged(aMsgHdr, aProperty, aOldValue, aNewValue) {
+    OnItemPropertyFlagChanged: function gloda_indexer_OnItemPropertyFlagChanged(
+                                aMsgHdr, aProperty, aOldValue, aNewValue) {
       if (aProperty == "Keywords" ||
           // We could care less about the new flag changing.
           (aProperty == "Status" &&
            (aOldValue ^ aNewValue) != Ci.nsMsgMessageFlags.New &&
            // We do care about IMAP deletion, but msgsDeleted tells us that, so
            //  ignore IMAPDeleted too...
            (aOldValue ^ aNewValue) != Ci.nsMsgMessageFlags.IMAPDeleted) ||
           aProperty == "Flagged") {
         GlodaMsgIndexer._reindexChangedMessages([aMsgHdr], true);
       }
     },
 
     /**
      * Get folder loaded notifications for folders that had to do some
      *  (asynchronous) processing before they could be opened.
      */
-    OnItemEvent(aFolder, aEvent) {
+    OnItemEvent: function gloda_indexer_OnItemEvent(aFolder, aEvent) {
       if (aEvent == "FolderLoaded")
         this.indexer._onFolderLoaded(aFolder);
     },
   },
 
   /* ***** Rebuilding / Reindexing ***** */
   /**
    * Allow us to invalidate an outstanding folder traversal because the
@@ -2767,36 +2832,39 @@ var GlodaMsgIndexer = {
      * The fact that we already have the database open when getting this means
      *  that it had to be valid before we opened it, which hopefully rules out
      *  modification of the mbox file by an external process (since that is
      *  forbidden when we are running) and many other exotic things.
      *
      * So this really ends up just being a correctness / safety protection
      *  mechanism.  At least now that we have better compaction support.
      */
-    onAnnouncerGoingAway(aDBChangeAnnouncer) {
+    onAnnouncerGoingAway: function gloda_indexer_dbGoingAway(
+                                         aDBChangeAnnouncer) {
       // The fact that we are getting called means we have an active folder and
       //  that we therefore are the active job.  As such, we must kill the
       //  active job.
       // XXX In the future, when we support interleaved event-driven indexing
       //  that bumps long-running indexing tasks, the semantics of this will
       //  have to change a bit since we will want to maintain being active in a
       //  folder even when bumped.  However, we will probably have a more
       //  complex notion of indexing contexts on a per-job basis.
       GlodaIndexer.killActiveJob();
     },
 
-    onHdrFlagsChanged(aHdrChanged, aOldFlags, aNewFlags, aInstigator) {},
-    onHdrDeleted(aHdrChanged, aParentKey, aFlags, aInstigator) {},
-    onHdrAdded(aHdrChanged, aParentKey, aFlags, aInstigator) {},
-    onParentChanged(aKeyChanged, aOldParent, aNewParent, aInstigator) {},
-    onReadChanged(aInstigator) {},
-    onJunkScoreChanged(aInstigator) {},
-    onHdrPropertyChanged(aHdrToChange, aPreChange, aStatus, aInstigator) {},
-    onEvent(aDB, aEvent) {},
+    onHdrFlagsChanged: function(aHdrChanged, aOldFlags, aNewFlags, aInstigator) {},
+    onHdrDeleted: function(aHdrChanged, aParentKey, aFlags, aInstigator) {},
+    onHdrAdded: function(aHdrChanged, aParentKey, aFlags, aInstigator) {},
+    onParentChanged: function(aKeyChanged, aOldParent, aNewParent,
+                              aInstigator) {},
+    onReadChanged: function(aInstigator) {},
+    onJunkScoreChanged: function(aInstigator) {},
+    onHdrPropertyChanged: function (aHdrToChange, aPreChange, aStatus,
+                                    aInstigator) {},
+    onEvent: function (aDB, aEvent) {},
   },
 
   /**
    * Given a list of Message-ID's, return a matching list of lists of messages
    *  matching those Message-ID's.  So if you pass an array with three
    *  Message-ID's ["a", "b", "c"], you would get back an array containing
    *  3 lists, where the first list contains all the messages with a message-id
    *  of "a", and so forth.  The reason a list is returned rather than null/a
@@ -2809,17 +2877,18 @@ var GlodaMsgIndexer = {
    *  could be a lot of message-id's and/or a lot of messages with those
    *  message-id's.
    *
    * The returned collection will include both 'ghost' messages (messages
    *  that exist for conversation-threading purposes only) as well as deleted
    *  messages in addition to the normal 'live' messages that non-privileged
    *  queries might return.
    */
-  getMessagesByMessageID(aMessageIDs, aCallback, aCallbackThis) {
+  getMessagesByMessageID: function gloda_ns_getMessagesByMessageID(aMessageIDs,
+      aCallback, aCallbackThis) {
     let msgIDToIndex = {};
     let results = [];
     for (let iID = 0; iID < aMessageIDs.length; ++iID) {
       let msgID = aMessageIDs[iID];
       results.push([]);
       msgIDToIndex[msgID] = iID;
     }
 
@@ -2856,31 +2925,35 @@ var GlodaMsgIndexer = {
    *
    * Prior to calling this method, the caller must have invoked
    *  |_indexerEnterFolder|, leaving us with the following true invariants
    *  below.
    *
    * @pre aMsgHdr.folder == this._indexingFolder
    * @pre aMsgHdr.folder.msgDatabase == this._indexingDatabase
    */
-  * _indexMessage(aMsgHdr, aCallbackHandle) {
+  _indexMessage: function* gloda_indexMessage(aMsgHdr, aCallbackHandle) {
     let logDebug = this._log.level <= Log4Moz.Level.Debug;
     if (logDebug)
       this._log.debug("*** Indexing message: " + aMsgHdr.messageKey + " : " +
                       aMsgHdr.subject);
 
     // If the message is offline, then get the message body as well
+    let isMsgOffline = false;
     let aMimeMsg;
     if ((aMsgHdr.flags & Ci.nsMsgMessageFlags.Offline) ||
         (aMsgHdr.folder instanceof Ci.nsIMsgLocalMailFolder)) {
+      isMsgOffline = true;
       this._MsgHdrToMimeMessageFunc(aMsgHdr, aCallbackHandle.callbackThis,
           aCallbackHandle.callback, false, {saneBodySize: true});
       aMimeMsg = (yield this.kWorkAsync)[1];
-    } else if (logDebug) {
-      this._log.debug("  * Message is not offline -- only headers indexed");
+    }
+    else {
+      if (logDebug)
+        this._log.debug("  * Message is not offline -- only headers indexed");
     }
 
     if (logDebug)
       this._log.debug("  * Got message, subject " + aMsgHdr.subject);
 
     if (this._unitTestSuperVerbose) {
       if (aMimeMsg)
         this._log.debug("  * Got Mime " + aMimeMsg.prettyString());
@@ -2920,34 +2993,37 @@ var GlodaMsgIndexer = {
 
     let conversationID = null;
     let conversation = null;
     // -- figure out the conversation ID
     // if we have a clone/already exist, just use his conversation ID
     if (candidateCurMsgs.length > 0) {
       conversationID = candidateCurMsgs[0].conversationID;
       conversation = candidateCurMsgs[0].conversation;
-    } else { // otherwise check out our ancestors
+    }
+    // otherwise check out our ancestors
+    else {
       // (walk from closest to furthest ancestor)
-      for (let iAncestor = ancestorLists.length - 1; iAncestor >= 0;
+      for (let iAncestor = ancestorLists.length-1; iAncestor >= 0;
           --iAncestor) {
         let ancestorList = ancestorLists[iAncestor];
 
         if (ancestorList.length > 0) {
           // we only care about the first instance of the message because we are
           //  able to guarantee the invariant that all messages with the same
           //  message id belong to the same conversation.
           let ancestor = ancestorList[0];
           if (conversationID === null) {
             conversationID = ancestor.conversationID;
             conversation = ancestor.conversation;
-          } else if (conversationID != ancestor.conversationID) {
+          }
+          else if (conversationID != ancestor.conversationID) {
             // XXX this inconsistency is known and understood and tracked by
             //  bug 478162 https://bugzilla.mozilla.org/show_bug.cgi?id=478162
-            // this._log.error("Inconsistency in conversations invariant on " +
+            //this._log.error("Inconsistency in conversations invariant on " +
             //                ancestor.headerMessageID + ".  It has conv id " +
             //                ancestor.conversationID + " but expected " +
             //                conversationID + ". ID: " + ancestor.id);
           }
         }
       }
     }
 
@@ -3013,18 +3089,19 @@ var GlodaMsgIndexer = {
           curMsg = candMsg;
         // if (we are in the same folder and) the candidate message's underlying
         //  message no longer exists/matches, we'll assume we are the same but
         //  were betrayed by a re-indexing or something, but we have to make
         //  sure a perfect match doesn't turn up.
         else if ((curMsg === null) &&
                  !this._indexingDatabase.ContainsKey(candMsg.messageKey))
           curMsg = candMsg;
-      } else if ((curMsg === null) && (candMsg.folderID === null)) {
-        // a ghost/deleted message is fine
+      }
+      // a ghost/deleted message is fine
+      else if ((curMsg === null) && (candMsg.folderID === null)) {
         curMsg = candMsg;
       }
     }
 
     let attachmentNames = null;
     if (aMimeMsg) {
       attachmentNames = aMimeMsg.allAttachments.
         filter(att => att.isRealAttachment).map(att => att.name);
@@ -3034,17 +3111,18 @@ var GlodaMsgIndexer = {
     if (curMsg === null) {
       curMsg = this._datastore.createMessage(aMsgHdr.folder,
                                              aMsgHdr.messageKey,
                                              conversationID,
                                              aMsgHdr.date,
                                              aMsgHdr.messageId);
       curMsg._conversation = conversation;
       isConceptuallyNew = isRecordNew = insertFulltext = true;
-    } else {
+    }
+    else {
       isRecordNew = false;
       // the message is conceptually new if it was a ghost or dead.
       isConceptuallyNew = curMsg._isGhost || curMsg._isDeleted;
       // insert fulltext if it was a ghost
       insertFulltext = curMsg._isGhost;
       curMsg._folderID = this._datastore._mapFolder(aMsgHdr.folder).id;
       curMsg._messageKey = aMsgHdr.messageKey;
       curMsg.date = new Date(aMsgHdr.date / 1000);
@@ -3114,17 +3192,18 @@ var GlodaMsgIndexer = {
    *  collecting up all the attributes that accept a message as their object
    *  type and issuing a delete against that.  For example, delete (*, [1,2,3],
    *  message id).
    * (We are punting because we haven't implemented support for generating
    *  attributes like that yet.)
    *
    * @TODO: implement deletion of attributes that reference (deleted) messages
    */
-  * _deleteMessage(aMessage, aCallbackHandle) {
+  _deleteMessage: function* gloda_index_deleteMessage(aMessage,
+                                                      aCallbackHandle) {
     let logDebug = this._log.level <= Log4Moz.Level.Debug;
     if (logDebug)
       this._log.debug("*** Deleting message: " + aMessage);
 
     // -- delete our attributes
     // delete the message's attributes (if we implement the cascade delete, that
     //  could do the honors for us... right now we define the trigger in our
     //  schema but the back-end ignores it)
@@ -3174,26 +3253,31 @@ var GlodaMsgIndexer = {
       for (let msg of conversationMsgs) {
         GlodaDatastore.deleteMessageByID(msg.id);
       }
       // - Obliterate the conversation
       GlodaDatastore.deleteConversationByID(aMessage.conversationID);
       // *no one* should hold a reference or use aMessage after this point,
       //  trash it so such ne'er do'wells are made plain.
       aMessage._objectPurgedMakeYourselfUnpleasant();
-    } else if (twinMessageExists) { // -- Ghost or purge us as appropriate
+    }
+    // -- Ghost or purge us as appropriate
+    else {
       // Purge us if we have a (living) twin; no ghost required.
-      GlodaDatastore.deleteMessageByID(aMessage.id);
-      // *no one* should hold a reference or use aMessage after this point,
-      //  trash it so such ne'er do'wells are made plain.
-      aMessage._objectPurgedMakeYourselfUnpleasant();
-    } else {
+      if (twinMessageExists) {
+        GlodaDatastore.deleteMessageByID(aMessage.id);
+        // *no one* should hold a reference or use aMessage after this point,
+        //  trash it so such ne'er do'wells are made plain.
+        aMessage._objectPurgedMakeYourselfUnpleasant();
+      }
       // No twin, a ghost is required, we become the ghost.
-      aMessage._ghost();
-      GlodaDatastore.updateMessage(aMessage);
-      // ghosts don't have fulltext. purge it.
-      GlodaDatastore.deleteMessageTextByID(aMessage.id);
+      else {
+        aMessage._ghost();
+        GlodaDatastore.updateMessage(aMessage);
+        // ghosts don't have fulltext. purge it.
+        GlodaDatastore.deleteMessageTextByID(aMessage.id);
+      }
     }
 
     yield this.kWorkDone;
   },
 };
 GlodaIndexer.registerIndexer(GlodaMsgIndexer);
--- a/mailnews/db/gloda/modules/indexer.js
+++ b/mailnews/db/gloda/modules/indexer.js
@@ -5,17 +5,17 @@
 /*
  * This file currently contains a fairly general implementation of asynchronous
  *  indexing with a very explicit message indexing implementation.  As gloda
  *  will eventually want to index more than just messages, the message-specific
  *  things should ideally lose their special hold on this file.  This will
  *  benefit readability/size as well.
  */
 
-this.EXPORTED_SYMBOLS = ["GlodaIndexer", "IndexingJob"];
+this.EXPORTED_SYMBOLS = ['GlodaIndexer', 'IndexingJob'];
 
 const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const {Log4Moz} = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
 
 const {GlodaUtils} = ChromeUtils.import("resource:///modules/gloda/utils.js");
 const {GlodaDatastore} = ChromeUtils.import("resource:///modules/gloda/datastore.js");
@@ -53,30 +53,31 @@ function IndexingJob(aJobType, aID, aIte
   this.callback = null;
   this.callbackThis = null;
 }
 IndexingJob.prototype = {
   /**
    * Invoke the callback associated with this job, passing through all arguments
    *  received by this function to the callback function.
    */
-  safelyInvokeCallback(...aArgs) {
+  safelyInvokeCallback: function(...aArgs) {
     if (!this.callback)
       return;
     try {
       this.callback.apply(this.callbackThis, aArgs);
-    } catch (ex) {
+    }
+    catch(ex) {
       GlodaIndexer._log.warn("job callback invocation problem:", ex);
     }
   },
-  toString() {
+  toString: function IndexingJob_toString() {
     return "[job:" + this.jobType +
       " id:" + this.id + " items:" + (this.items ? this.items.length : "no") +
       " offset:" + this.offset + " goal:" + this.goal + "]";
-  },
+  }
 };
 
 /**
  * @namespace Core indexing logic, plus message-specific indexing logic.
  *
  * === Indexing Goals
  * We have the following goals:
  *
@@ -288,17 +289,17 @@ var GlodaIndexer = {
    * Last commit time.  Tracked to try and only commit at reasonable intervals.
    */
   _lastCommitTime: Date.now(),
 
   _inited: false,
   /**
    * Initialize the indexer.
    */
-  _init() {
+  _init: function gloda_index_init() {
     if (this._inited)
       return;
 
     this._inited = true;
 
     this._callbackHandle.init();
 
     if (Services.io.offline)
@@ -313,27 +314,37 @@ var GlodaIndexer = {
                           .getService(Ci.nsIIdleService);
 
     // create our performance stopwatches
     try {
       this._perfIndexStopwatch = Cc["@mozilla.org/stopwatch;1"]
                                    .createInstance(Ci.nsIStopwatch);
       this._perfPauseStopwatch = Cc["@mozilla.org/stopwatch;1"]
                                    .createInstance(Ci.nsIStopwatch);
+
     } catch (ex) {
       this._log.error("problem creating stopwatch!: " + ex);
     }
 
     // register for shutdown notifications
     Services.obs.addObserver(this, "quit-application");
 
     // figure out if event-driven indexing should be enabled...
     let branch = Services.prefs.getBranch("mailnews.database.global.indexer.");
-    let eventDrivenEnabled = branch.getBoolPref("enabled", false);
-    let performInitialSweep = branch.getBoolPref("perform_initial_sweep", true);
+    let eventDrivenEnabled = false; // default
+    let performInitialSweep = true; // default
+    try {
+      eventDrivenEnabled = branch.getBoolPref("enabled");
+    } catch (ex) {
+      dump("%%% annoying exception on pref access: " + ex);
+    }
+    // this is a secret preference mainly intended for testing purposes.
+    try {
+      performInitialSweep = branch.getBoolPref("perform_initial_sweep");
+    } catch (ex) {}
     // pretend we have already performed an initial sweep...
     if (!performInitialSweep)
       this._initialSweepPerformed = true;
 
     this.enabled = eventDrivenEnabled;
   },
 
   /**
@@ -342,17 +353,17 @@ var GlodaIndexer = {
    *  in this state is a destructive thing from whence we cannot recover.
    */
   _indexerIsShutdown: false,
 
   /**
    * Shutdown the indexing process and datastore as quickly as possible in
    *  a synchronous fashion.
    */
-  _shutdown() {
+  _shutdown: function gloda_index_shutdown() {
     // no more timer events, please
     try {
       this._timer.cancel();
     } catch (ex) {}
     this._timer = null;
     try {
       this._longTimer.cancel();
     } catch (ex) {}
@@ -374,17 +385,18 @@ var GlodaIndexer = {
     this.suppressIndexing = true;
 
     // If there is an active job and it has a cleanup handler, run it.
     if (this._curIndexingJob) {
       let workerDef = this._curIndexingJob._workerDef;
       try {
         if (workerDef.cleanup)
           workerDef.cleanup.call(workerDef.indexer, this._curIndexingJob);
-      } catch (ex) {
+      }
+      catch (ex) {
         this._log.error("problem during worker cleanup during shutdown.");
       }
     }
     // Definitely clean out the async call stack and any associated data
     this._callbackHandle.cleanup();
     this._workBatchData = undefined;
 
     // disable ourselves and all of the specific indexers
@@ -422,17 +434,17 @@ var GlodaIndexer = {
    *     finalization required on the job.  Most workers should not need to use
    *     the trigger function.
    * @param aIndexer.initialSweep We call this to tell each indexer when it is
    *     its turn to run its indexing sweep.  The idea of the indexing sweep is
    *     that this is when you traverse things eligible for indexing to make
    *     sure they are indexed.  Right now we just call everyone at the same
    *     time and hope that their jobs don't fight too much.
    */
-  registerIndexer(aIndexer) {
+  registerIndexer: function gloda_index_registerIndexer(aIndexer) {
     this._log.info("Registering indexer: " + aIndexer.name);
     this._indexers.push(aIndexer);
 
     try {
       for (let workerInfo of aIndexer.workers) {
         let workerCode = workerInfo[0];
         let workerDef = workerInfo[1];
         workerDef.name = workerCode;
@@ -442,17 +454,18 @@ var GlodaIndexer = {
           workerDef.recover = null;
         if (!("cleanup" in workerDef))
           workerDef.cleanup = null;
         if (!("onSchedule" in workerDef))
           workerDef.onSchedule = null;
         if (!("jobCanceled" in workerDef))
           workerDef.jobCanceled = null;
       }
-    } catch (ex) {
+    }
+    catch (ex) {
       this._log.warn("Helper indexer threw exception on worker enum.");
     }
 
     if (this._enabled) {
       try {
         aIndexer.enable();
       } catch (ex) {
         this._log.warn("Helper indexer threw exception on enable: " + ex);
@@ -489,33 +502,35 @@ var GlodaIndexer = {
         this.indexing = true;
       }
 
       // if we have not done an initial sweep, schedule scheduling one.
       if (!this._initialSweepPerformed) {
         this._longTimer.initWithCallback(this._scheduleInitialSweep,
           this._INITIAL_SWEEP_DELAY, Ci.nsITimer.TYPE_ONE_SHOT);
       }
-    } else if (this._enabled && !aEnable) {
+    }
+    else if (this._enabled && !aEnable) {
       for (let indexer of this._indexers) {
         try {
           indexer.disable();
         } catch (ex) {
           this._log.warn("Helper indexer threw exception on disable: " + ex);
         }
       }
 
       // remove offline observer
       Services.obs.removeObserver(this, "network:offline-status-changed");
 
       // remove idle
       this._idleService.removeIdleObserver(this, this._indexIdleThresholdSecs);
 
       this._enabled = false;
     }
+
   },
 
   /** Track whether indexing is desired (we have jobs to prosecute). */
   _indexingDesired: false,
   /**
    * Track whether we have an actively pending callback or timer event.  We do
    *  this so we don't experience a transient suppression and accidentally
    *  get multiple event-chains driving indexing at the same time (which the
@@ -584,17 +599,17 @@ var GlodaIndexer = {
    * Our timer-driven callback to schedule our first initial indexing sweep.
    *  Because it is invoked by an nsITimer it operates without the benefit of
    *  a 'this' context and must use GlodaIndexer instead of this.
    * Since an initial sweep could have been performed before we get invoked,
    *  we need to check whether an initial sweep is still desired before trying
    *  to schedule one.  We don't need to worry about whether one is active
    *  because the indexingSweepNeeded takes care of that.
    */
-  _scheduleInitialSweep() {
+  _scheduleInitialSweep: function gloda_index_scheduleInitialSweep() {
     if (GlodaIndexer._initialSweepPerformed)
       return;
     GlodaIndexer._initialSweepPerformed = true;
     for (let indexer of GlodaIndexer._indexers) {
       indexer.initialSweep();
     }
   },
 
@@ -640,101 +655,103 @@ var GlodaIndexer = {
    *