Bug 1436199 - Include the gdata provider in eslint. r=MakeMyDay
authorPhilipp Kewisch <mozilla@kewis.ch>
Tue, 06 Feb 2018 23:30:53 +0100
changeset 31109 f8afcb3f18de1d71de1c52386587995a517033bc
parent 31108 752150efa9fb1b1fcf385b06b0a464bb49a9e006
child 31110 87cad73c874af0a169ba3ecf9118b318b62af1a5
push id383
push userclokep@gmail.com
push dateMon, 07 May 2018 21:52:48 +0000
reviewersMakeMyDay
bugs1436199
Bug 1436199 - Include the gdata provider in eslint. r=MakeMyDay MozReview-Commit-ID: 6LYTd7BIZTB
.eslintignore
calendar/providers/gdata/components/calGoogleCalendar.js
calendar/providers/gdata/content/browserRequest.js
calendar/providers/gdata/content/gdata-calendar-creation.js
calendar/providers/gdata/content/gdata-calendar-event-dialog.js
calendar/providers/gdata/content/gdata-calendar-properties.js
calendar/providers/gdata/content/gdata-event-dialog-reminder.js
calendar/providers/gdata/content/gdata-list-tree.xml
calendar/providers/gdata/content/gdata-migration.js
calendar/providers/gdata/modules/OAuth2.jsm
calendar/providers/gdata/modules/gdataLogging.jsm
calendar/providers/gdata/modules/gdataRequest.jsm
calendar/providers/gdata/modules/gdataSession.jsm
calendar/providers/gdata/modules/gdataUtils.jsm
--- a/.eslintignore
+++ b/.eslintignore
@@ -29,17 +29,14 @@ mailnews/**
 suite/**
 
 # calendar/ exclusions
 
 # prefs files
 calendar/lightning/content/lightning.js
 calendar/locales/en-US/lightning-l10n.js
 
-# gdata-provider uses non-standard javascript for Postbox compatibility
-calendar/providers/gdata/**
-
 # third party library
 calendar/base/modules/ical.js
 
 # preprocessed files
 calendar/base/content/dialogs/calendar-migration-dialog.js
 calendar/base/content/calendar-dnd-listener.js
--- a/calendar/providers/gdata/components/calGoogleCalendar.js
+++ b/calendar/providers/gdata/components/calGoogleCalendar.js
@@ -12,17 +12,16 @@ ChromeUtils.import("resource://calendar/
 ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
 
 ChromeUtils.import("resource://gdata-provider/modules/calUtilsShim.jsm");
 ChromeUtils.import("resource://gdata-provider/modules/gdataLogging.jsm");
 ChromeUtils.import("resource://gdata-provider/modules/gdataRequest.jsm");
 ChromeUtils.import("resource://gdata-provider/modules/gdataSession.jsm");
 ChromeUtils.import("resource://gdata-provider/modules/gdataUtils.jsm");
 
-var cICL = Components.interfaces.calIChangeLog;
 var cIOL = Components.interfaces.calIOperationListener;
 
 var MIN_REFRESH_INTERVAL = 30;
 
 /**
  * calGoogleCalendar
  * This Implements a calICalendar Object adapted to the Google Calendar
  * Provider.
@@ -55,19 +54,19 @@ calGoogleCalendar.prototype = {
 
     /* Used to reset the local cache between releases */
     CACHE_DB_VERSION: 3,
 
     /* Member Variables */
     mCalendarName: null,
     mThrottle: null,
     mThrottleLimits: {
-      "calendarList": 3600 * 1000,
-      "events": 30 * 1000,
-      "tasks": 30 * 1000
+        calendarList: 3600 * 1000,
+        events: 30 * 1000,
+        tasks: 30 * 1000
     },
 
     /* Public Members */
     session: null,
 
     /**
      * Make sure a session is available.
      */
@@ -118,18 +117,19 @@ calGoogleCalendar.prototype = {
 
     get uri() { return this.mUri; },
     set uri(aUri) {
         const protocols = ["http", "https", "webcal", "webcals"];
         this.mUri = aUri;
         if (aUri && aUri.schemeIs("googleapi")) {
             // new format:  googleapi://session-id/?calendar=calhash@group.calendar.google.com&tasks=taskhash
             let [fullUser, path] = aUri.pathQueryRef.substr(2).split("/", 2);
-            let parameters = new Map(path.substr(1).split("&").filter(Boolean)
-                             .map(function(x) { return x.split("=", 2).map(decodeURIComponent); }));
+            let keyvalues = path.substr(1).split("&").filter(Boolean);
+            let pairs = keyvalues.map(keyvalue => keyvalue.split("=", 2).map(decodeURIComponent));
+            let parameters = new Map(pairs);
 
             if (parameters.size == 0) {
                 this.mCalendarName = fullUser;
                 this.mTasklistName = this.isDefaultCalendar ? "@default" : null;
             } else {
                 this.mCalendarName = parameters.get("calendar");
                 this.mTasklistName = parameters.get("tasks");
             }
@@ -147,17 +147,17 @@ calGoogleCalendar.prototype = {
 
             // Unit tests will use a local uri, if the magic parameter is passed.
             let port = parameters.get("testport");
             if (port) {
                 cal.LOG("[calGoogleCalendar] Redirecting request to test port " + port);
                 API_BASE.EVENTS = "http://localhost:" + port + "/calendar/v3/";
                 API_BASE.TASKS = "http://localhost:" + port + "/tasks/v1/";
             }
-        } else if (aUri && protocols.some(function(scheme) { return aUri.schemeIs(scheme); })) {
+        } else if (aUri && protocols.some(scheme => aUri.schemeIs(scheme))) {
             // Parse google url, catch private cookies, public calendars,
             // basic and full types, bogus ics file extensions, invalid hostnames
             let re = new RegExp("/calendar/(feeds|ical)/" +
                                 "([^/]+)/(public|private|free-busy)-?([^/]+)?/" +
                                 "(full|basic)(.ics)?$");
 
             let matches = aUri.pathQueryRef.match(re);
             if (matches) {
@@ -181,17 +181,17 @@ calGoogleCalendar.prototype = {
 
         if (this.id && this.uri) {
             this.ensureSession();
         }
 
         return this.mUri;
     },
 
-    createEventsURI: function (...extraParts) {
+    createEventsURI: function(...extraParts) {
         let eventsURI = null;
         if (this.mCalendarName) {
             let encodedName = encodeURIComponent(this.mCalendarName);
             let parts = ["calendars", encodedName].concat(extraParts.filter(Boolean));
             eventsURI = API_BASE.EVENTS + parts.join("/");
         }
         return eventsURI;
     },
@@ -206,17 +206,17 @@ calGoogleCalendar.prototype = {
         if (this.mTasklistName) {
             let encodedName = encodeURIComponent(this.mTasklistName);
             let parts = ["lists", encodedName].concat(extraParts.filter(Boolean));
             tasksURI = API_BASE.TASKS + parts.join("/");
         }
         return tasksURI;
     },
 
-    getUpdatedMin: function getUpdatedMin(aWhich) {
+    getUpdatedMin: function(aWhich) {
         let updatedMin = null;
         let lastUpdated = this.getProperty("lastUpdated." + aWhich);
         if (lastUpdated) {
             updatedMin = cal.createDateTime(lastUpdated);
             let lastWeek = cal.dtz.now();
             lastWeek.day -= 7;
             if (updatedMin.compare(lastWeek) <= 0) {
                 cal.LOG("[calGoogleCalendar] Last updated time for " + aWhich +
@@ -263,36 +263,38 @@ calGoogleCalendar.prototype = {
             case "capabilities.timezones.floating.supported":
             case "capabilities.attachments.supported":
             case "capabilities.priority.supported":
                 return false;
             case "capabilities.privacy.values":
                 return ["DEFAULT", "PUBLIC", "PRIVATE"];
             case "capabilities.alarms.maxCount":
                 return 5;
-            case "capabilities.alarms.actionValues":
+            case "capabilities.alarms.actionValues": {
                 let actionValues = ["DISPLAY", "EMAIL"];
                 if (Preferences.get("calendar.google.enableSMSReminders", false)) {
                     actionValues.push("SMS");
                 }
                 return actionValues;
+            }
             case "capabilities.tasks.supported":
                 return !!this.mTasklistName;
             case "capabilities.events.supported":
                 return !!this.mCalendarName;
-            case "readOnly":
+            case "readOnly": {
                 // If this calendar displays events, make it readonly if we are
                 // not the owner or have write access.
                 let accessRole = this.getProperty("settings.accessRole");
                 let isReader = (accessRole == "freeBusyReader" || accessRole == "reader");
                 if (this.mCalendarName && isReader) {
                     return true;
                 }
                 // Otherwise fall through
                 break;
+            }
             case "organizerId":
                 return "mailto:" + this.mCalendarName;
             case "itip.transport":
                 if (!this.isDefaultCalendar ||
                     !Preferences.get("calendar.google.enableEmailInvitations", false)) {
                     // If we explicitly return null here, then these calendars
                     // will not be included in the list of calendars to accept
                     // invitations to and imip will effectively be disabled.
@@ -317,28 +319,27 @@ calGoogleCalendar.prototype = {
     setProperty: function(aName, aValue) {
         switch (aName) {
             case "refreshInterval":
                 if (aValue < MIN_REFRESH_INTERVAL && aValue != 0) {
                     cal.LOG("[calGoogleCalendar] Sorry, auto-refresh intervals under " +
                             MIN_REFRESH_INTERVAL + " minutes would cause the quota " +
                             "to be reached too fast.");
                     this.superCalendar.setProperty("refreshInterval", 2 * MIN_REFRESH_INTERVAL);
-                    return;
+                    return undefined;
                 }
                 break;
         }
 
         return this.__proto__.__proto__.setProperty.apply(this, arguments);
     },
 
     addItem: function(aItem, aListener) { return this.adoptItem(aItem.clone(), aListener); },
     adoptItem: function(aItem, aListener) {
-        function stackContains(part, max) {
-            if (max === undefined) max = 8;
+        function stackContains(part, max=8) {
             let stack = Components.stack.caller;
             while (stack && --max) {
                 if (stack.filename && stack.filename.endsWith(part)) {
                     return true;
                 }
                 stack = stack.caller;
             }
             return false;
@@ -402,34 +403,34 @@ calGoogleCalendar.prototype = {
                 // item. This really sucks for us now, because the cache will
                 // reset the wrong item. As a hack, delete the item with its
                 // original id and complete the adoptItem call with the new
                 // item. This will add the new item to the calendar.
                 let pcal = cal.async.promisifyCalendar(this.offlineStorage);
                 await pcal.deleteItem(aItem);
             }
             return item;
-        })().then(function(item) {
+        })().then((item) => {
             cal.LOG("[calGoogleCalendar] Adding " + item.title + " succeeded");
             this.observers.notify("onAddItem", [item]);
             this.notifyOperationComplete(aListener, Components.results.NS_OK,
                                          cIOL.ADD, item.id, item);
-        }.bind(this), function(e) {
+        }, (e) => {
             let code = e.result || Components.results.NS_ERROR_FAILURE;
             cal.ERROR("[calGoogleCalendar] Adding Item " + aItem.title +
                       " failed:" + code + ": " + e.message);
             this.notifyPureOperationComplete(aListener, code, cIOL.ADD, aItem.id, e.message);
-        }.bind(this));
+        });
         return request;
     },
 
     modifyItem: function(aNewItem, aOldItem, aListener) {
         cal.LOG("[calGoogleCalendar] Modifying item " + aNewItem.title + " (" +
-                (aNewItem.recurrenceId ? aNewItem.recurrenceId.icalString :
-                "master item") + ")");
+                (aNewItem.recurrenceId ? aNewItem.recurrenceId.icalString
+                                       : "master item") + ")");
 
         // Set up the request
         let request = new calGoogleRequest();
         (async () => {
             request.type = request.MODIFY;
             request.calendar = this;
             if (cal.item.isEvent(aNewItem)) {
                 let googleId = getGoogleId(aNewItem, this.offlineStorage);
@@ -502,30 +503,29 @@ calGoogleCalendar.prototype = {
                 } else {
                     // Not canceled means the occurrence was modified.
                     modifiedItem.recurrenceInfo.modifyException(item, true);
                 }
                 item = modifiedItem;
             }
 
             return item;
-        })().then(function (item) {
+        })().then((item) => {
             cal.LOG("[calGoogleCalendar] Modifying " + aNewItem.title + " succeeded");
             this.observers.notify("onModifyItem", [item, aOldItem]);
             this.notifyOperationComplete(aListener, Components.results.NS_OK,
                                          cIOL.MODIFY, item.id, item);
-
-        }.bind(this), function(e) {
+        }, (e) => {
             let code = e.result || Components.results.NS_ERROR_FAILURE;
             if (code != Components.interfaces.calIErrors.OPERATION_CANCELLED) {
                 cal.ERROR("[calGoogleCalendar] Modifying item " + aNewItem.title +
                           " failed:" + code + ": " + e.message);
             }
             this.notifyPureOperationComplete(aListener, code, cIOL.MODIFY, aNewItem.id, e.message);
-        }.bind(this));
+        });
         return request;
     },
 
     deleteItem: function(aItem, aListener) {
         cal.LOG("[calGoogleCalendar] Deleting item " + aItem.title + "(" + aItem.id + ")");
 
         let request = new calGoogleRequest();
         (async () => {
@@ -555,46 +555,46 @@ calGoogleCalendar.prototype = {
             }
 
             try {
                 await this.session.asyncItemRequest(request);
             } catch (e) {
                 if (e.result == calGoogleRequest.CONFLICT_MODIFY ||
                     e.result == calGoogleRequest.CONFLICT_DELETED) {
                     await checkResolveConflict(request, this, aItem);
-                 } else {
+                } else {
                     throw e;
-                 }
+                }
             }
 
             deleteItemMetadata(this.offlineStorage, aItem);
 
             return aItem;
-        })().then(function (item) {
+        })().then((item) => {
             cal.LOG("[calGoogleCalendar] Deleting " + aItem.title + " succeeded");
             this.observers.notify("onDeleteItem", [item]);
             this.notifyOperationComplete(aListener, Components.results.NS_OK,
                                          cIOL.DELETE, item.id, item);
-        }.bind(this), function(e) {
+        }, (e) => {
             let code = e.result || Components.results.NS_ERROR_FAILURE;
             if (code != Components.interfaces.calIErrors.OPERATION_CANCELLED) {
                 cal.ERROR("[calGoogleCalendar] Deleting item " + aItem.title +
                           " failed:" + code + ": " + e.message);
             }
             this.notifyPureOperationComplete(aListener, code, cIOL.DELETE, aItem.id, e.message);
-        }.bind(this));
+        });
         return request;
     },
 
     getItem: function(aId, aListener) {
-        this.mOfflineStorage.getItem.apply(this.mOfflineStorage, arguments);
+        this.mOfflineStorage.getItem(...arguments);
     },
 
     getItems: function(aFilter, aCount, aRangeStart, aRangeEnd, aListener) {
-        this.mOfflineStorage.getItems.apply(this.mOfflineStorage, arguments);
+        this.mOfflineStorage.getItems(...arguments);
     },
 
     refresh: function() {
         this.mObservers.notify("onLoad", [this]);
     },
 
     migrateStorageCache: function() {
         let cacheVersion = this.getProperty("cache.version");
@@ -620,20 +620,20 @@ calGoogleCalendar.prototype = {
             let birthdayCalendar = "#contacts@group.v.calendar.google.com";
             if (this.mCalendarName && this.mCalendarName == birthdayCalendar) {
                 needsReset = true;
             }
         }
 
         // Migration all done. Reset if requested.
         if (needsReset) {
-            return this.resetSync().then(function() {
+            return this.resetSync().then(() => {
                 this.setProperty("cache.version", this.CACHE_DB_VERSION);
                 return needsReset;
-            }.bind(this));
+            });
         } else {
             this.setProperty("cache.version", this.CACHE_DB_VERSION);
             return Promise.resolve(needsReset);
         }
     },
 
     /**
      * Implement calIChangeLog
@@ -641,38 +641,39 @@ calGoogleCalendar.prototype = {
     get offlineStorage() { return this.mOfflineStorage; },
     set offlineStorage(val) {
         this.mOfflineStorage = val;
         this.migrateStorageCache();
         return val;
     },
 
     resetLog: function() {
-        this.resetSync().then(function() {
+        this.resetSync().then(() => {
             this.mObservers.notify("onLoad", [this]);
-        }.bind(this));
+        });
     },
 
     resetSync: function() {
-        let deferred = PromiseUtils.defer();
-        cal.LOG("[calGoogleCalendar] Resetting last updated counter for " + this.name);
-        this.setProperty("syncToken.events", "");
-        this.setProperty("lastUpdated.tasks", "");
-        this.mThrottle = Object.create(null);
-        this.mOfflineStorage.QueryInterface(Components.interfaces.calICalendarProvider)
-                            .deleteCalendar(this.mOfflineStorage, {
-            onDeleteCalendar: function(aCalendar, aStatus, aDetail) {
-                if (Components.isSuccessCode(aStatus)) {
-                    deferred.resolve();
-                } else {
-                    deferred.reject(aDetail);
+        return new Promise((resolve, reject) => {
+            cal.LOG("[calGoogleCalendar] Resetting last updated counter for " + this.name);
+            this.setProperty("syncToken.events", "");
+            this.setProperty("lastUpdated.tasks", "");
+            this.mThrottle = Object.create(null);
+            let listener = {
+                onDeleteCalendar: function(aCalendar, aStatus, aDetail) {
+                    if (Components.isSuccessCode(aStatus)) {
+                        resolve();
+                    } else {
+                        reject(aDetail);
+                    }
                 }
-            }
-       });
-       return deferred.promise;
+            };
+            this.mOfflineStorage.QueryInterface(Components.interfaces.calICalendarProvider)
+                                .deleteCalendar(this.mOfflineStorage, listener);
+        });
     },
 
     replayChangesOn: function(aListener) {
         // Figure out if the user is idle, no need to synchronize if so.
         let idleTime = Components.classes["@mozilla.org/widget/idleservice;1"]
                                  .getService(Components.interfaces.nsIIdleService)
                                  .idleTime;
         let maxIdleTime = Preferences.get("calendar.google.idleTime", 300) * 1000;
@@ -691,119 +692,123 @@ calGoogleCalendar.prototype = {
         this.mOfflineStorage.startBatch();
 
         // Update the calendar settings
         let calendarPromise = Promise.resolve();
         if (this.mCalendarName && this.checkThrottle("calendarList")) {
             let calendarRequest = new calGoogleRequest();
             calendarRequest.calendar = this;
             calendarRequest.type = calendarRequest.GET;
-            calendarRequest.uri = this.createUsersURI("calendarList", this.mCalendarName)
-            calendarPromise = this.session.asyncItemRequest(calendarRequest).then(function(aData) {
+            calendarRequest.uri = this.createUsersURI("calendarList", this.mCalendarName);
+            calendarPromise = this.session.asyncItemRequest(calendarRequest).then((aData) => {
                 if (aData.defaultReminders) {
-                    this.defaultReminders = aData.defaultReminders.map(function(x) { return JSONToAlarm(x, true); });
+                    this.defaultReminders = aData.defaultReminders.map(reminder => JSONToAlarm(reminder, true));
                 } else {
                     this.defaultReminders = [];
                 }
 
-                for (let k of ["accessRole", "backgroundColor", "description",
-                               "foregroundColor", "location", "primary",
-                               "summary", "summaryOverride", "timeZone"]) {
+                let settings = [
+                    "accessRole", "backgroundColor", "description",
+                    "foregroundColor", "location", "primary", "summary",
+                    "summaryOverride", "timeZone"
+                ];
+
+                for (let k of settings) {
                     this.setProperty("settings." + k, aData[k]);
                 }
                 this.setProperty("settings.defaultReminders", JSON.stringify(aData.defaultReminders));
-            }.bind(this));
+            });
         }
 
         // Set up a request for the events
         let eventsRequest = new calGoogleRequest();
         let eventsPromise = Promise.resolve();
         eventsRequest.calendar = this;
         eventsRequest.type = eventsRequest.GET;
         eventsRequest.uri = this.createEventsURI("events");
         eventsRequest.addQueryParameter("maxResults", maxResults);
         let syncToken = this.getProperty("syncToken.events");
         if (syncToken) {
             eventsRequest.addQueryParameter("showDeleted", "true");
             eventsRequest.addQueryParameter("syncToken", syncToken);
         }
         if (eventsRequest.uri && this.checkThrottle("events")) {
             let saver = new ItemSaver(this);
-            eventsPromise = this.session.asyncPaginatedRequest(eventsRequest, null, function(aData) {
+            eventsPromise = this.session.asyncPaginatedRequest(eventsRequest, null, (aData) => {
                 // On each request...
                 return saver.parseItemStream(aData);
-            }.bind(this), function(aData) {
+            }, (aData) => {
                 // On last request...
-                return saver.complete().then(function() {
+                return saver.complete().then(() => {
                     if (aData.nextSyncToken) {
                         cal.LOG("[calGoogleCalendar] New sync token for " +
                                 this.name + "(events) is now: " + aData.nextSyncToken);
                         this.setProperty("syncToken.events", aData.nextSyncToken);
                     }
-                }.bind(this));
-            }.bind(this));
+                });
+            });
         }
 
         // Set up a request for tasks
         let tasksRequest = new calGoogleRequest();
         let tasksPromise = Promise.resolve();
         tasksRequest.calendar = this;
         tasksRequest.type = tasksRequest.GET;
         tasksRequest.uri = this.createTasksURI("tasks");
         tasksRequest.addQueryParameter("maxResults", maxResults);
         let lastUpdated = this.getUpdatedMin("tasks");
         if (lastUpdated) {
             tasksRequest.addQueryParameter("updatedMin", cal.toRFC3339(lastUpdated));
             tasksRequest.addQueryParameter("showDeleted", "true");
         }
         if (tasksRequest.uri && this.checkThrottle("tasks")) {
             let saver = new ItemSaver(this);
-            let lastUpdated = null;
-            tasksPromise = this.session.asyncPaginatedRequest(tasksRequest, function(aData) {
+            let newLastUpdated = null;
+            tasksPromise = this.session.asyncPaginatedRequest(tasksRequest, (aData) => {
                 // On the first request...
-                lastUpdated = tasksRequest.requestDate.icalString;
-            }.bind(this), function(aData) {
+                newLastUpdated = tasksRequest.requestDate.icalString;
+            }, (aData) => {
                 // On each request...
                 return saver.parseItemStream(aData);
-            }.bind(this), function(aData) {
+            }, (aData) => {
                 // On last request...
-                return saver.complete().then(function() {
+                return saver.complete().then(() => {
                     cal.LOG("[calGoogleCalendar] Last sync date for " + this.name +
                             "(tasks) is now: " + tasksRequest.requestDate.toString());
-                    this.setProperty("lastUpdated.tasks", lastUpdated);
-                }.bind(this));
-            }.bind(this));
+                    this.setProperty("newLastUpdated.tasks", newLastUpdated);
+                });
+            });
         }
 
-        return Promise.all([calendarPromise, eventsPromise, tasksPromise]).then(function() {
+        return Promise.all([calendarPromise, eventsPromise, tasksPromise]).then(() => {
             this.mOfflineStorage.endBatch();
             aListener.onResult({ status: Components.results.NS_OK }, null);
-        }.bind(this), function(e) {
+        }, (e) => {
             this.mOfflineStorage.endBatch();
             let code = e.result || Components.results.NS_ERROR_FAILURE;
             if (code == calGoogleRequest.RESOURCE_GONE) {
                 cal.LOG("[calGoogleCalendar] Server did not accept " +
                         "incremental update, resetting calendar and " +
                         "starting over.");
-                this.resetSync().then(function() {
+                this.resetSync().then(() => {
                     this.replayChangesOn(aListener);
-                }.bind(this), function(e) {
+                }, (err) => {
                     cal.ERROR("[calGoogleCalendar] Error resetting calendar:\n" +
-                            stringException(e));
-                    aListener.onResult({ status: e.result }, e.message);
-                }.bind(this));
+                              stringException(err));
+                    aListener.onResult({ status: err.result }, err.message);
+                });
             } else {
                 cal.LOG("[calGoogleCalendar] Error syncing:\n" + code + ":" +
                         stringException(e));
                 aListener.onResult({ status: code }, e.message);
             }
-        }.bind(this));
+        });
     },
 
     /**
      * Implement calISchedulingSupport. Most is taken care of by the base
      * provider, but we want to advertise that we will always take care of
      * notifications.
      */
     canNotify: function(aMethod, aItem) { return true; }
 };
 
-var NSGetFactory = XPCOMUtils.generateNSGetFactory([calGoogleCalendar]);
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([calGoogleCalendar]); /* exported NSGetFactory */
--- a/calendar/providers/gdata/content/browserRequest.js
+++ b/calendar/providers/gdata/content/browserRequest.js
@@ -1,120 +1,103 @@
 /* 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/. */
 
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+/* exported cancelRequest, loadRequestedUrl, reportUserClosed */
+
 var wpl = Components.interfaces.nsIWebProgressListener;
 
 var reporterListener = {
-  _isBusy: false,
-  get securityButton() {
-    delete this.securityButton;
-    return this.securityButton = document.getElementById("security-button");
-  },
+    _isBusy: false,
+    get securityButton() {
+        delete this.securityButton;
+        return (this.securityButton = document.getElementById("security-button"));
+    },
 
-  QueryInterface: function(aIID) {
-    if (aIID.equals(Components.interfaces.nsIWebProgressListener)   ||
-        aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
-        aIID.equals(Components.interfaces.nsISupports))
-      return this;
-    throw Components.results.NS_NOINTERFACE;
-  },
+    QueryInterface: XPCOMUtils.generateQI([
+        Components.interfaces.nsIWebProgressListener,
+        Components.interfaces.nsISupportsWeakReference,
+    ]),
 
-  onStateChange: function(/*in nsIWebProgress*/ aWebProgress,
-                     /*in nsIRequest*/ aRequest,
-                     /*in unsigned long*/ aStateFlags,
-                     /*in nsresult*/ aStatus) {
-  },
+    onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
+    },
+
+    onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress,
+                               aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {
+    },
 
-  onProgressChange: function(/*in nsIWebProgress*/ aWebProgress,
-                        /*in nsIRequest*/ aRequest,
-                        /*in long*/ aCurSelfProgress,
-                        /*in long */aMaxSelfProgress,
-                        /*in long */aCurTotalProgress,
-                        /*in long */aMaxTotalProgress) {
-  },
+    onLocationChange: function(aWebProgress, aRequest, aLocation) {
+        document.getElementById("headerMessage").textContent = aLocation.spec;
+    },
 
-  onLocationChange: function(/*in nsIWebProgress*/ aWebProgress,
-                        /*in nsIRequest*/ aRequest,
-                        /*in nsIURI*/ aLocation) {
-    document.getElementById("headerMessage").textContent = aLocation.spec;
-  },
+    onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {
+    },
 
-  onStatusChange: function(/*in nsIWebProgress*/ aWebProgress,
-                      /*in nsIRequest*/ aRequest,
-                      /*in nsresult*/ aStatus,
-                      /*in wstring*/ aMessage) {
-  },
-
-  onSecurityChange: function(/*in nsIWebProgress*/ aWebProgress,
-                        /*in nsIRequest*/ aRequest,
-                        /*in unsigned long*/ aState) {
-    const wpl_security_bits = wpl.STATE_IS_SECURE |
-                              wpl.STATE_IS_BROKEN |
-                              wpl.STATE_IS_INSECURE |
-                              wpl.STATE_SECURE_HIGH |
-                              wpl.STATE_SECURE_MED |
-                              wpl.STATE_SECURE_LOW;
-    var browser = document.getElementById("requestFrame");
-    var level;
+    onSecurityChange: function(aWebProgress, aRequest, aState) {
+        const wpl_security_bits = wpl.STATE_IS_SECURE |
+                                    wpl.STATE_IS_BROKEN |
+                                    wpl.STATE_IS_INSECURE |
+                                    wpl.STATE_SECURE_HIGH |
+                                    wpl.STATE_SECURE_MED |
+                                    wpl.STATE_SECURE_LOW;
+        let browser = document.getElementById("requestFrame");
+        let level;
 
-    switch (aState & wpl_security_bits) {
-      case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_HIGH:
-        level = "high";
-        break;
-      case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_MED:
-      case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_LOW:
-        level = "low";
-        break;
-      case wpl.STATE_IS_BROKEN:
-        level = "broken";
-        break;
+        switch (aState & wpl_security_bits) {
+            case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_HIGH:
+                level = "high";
+                break;
+            case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_MED:
+            case wpl.STATE_IS_SECURE | wpl.STATE_SECURE_LOW:
+                level = "low";
+                break;
+            case wpl.STATE_IS_BROKEN:
+                level = "broken";
+                break;
+        }
+        if (level) {
+            this.securityButton.setAttribute("level", level);
+            this.securityButton.hidden = false;
+        } else {
+            this.securityButton.hidden = true;
+            this.securityButton.removeAttribute("level");
+        }
+        this.securityButton.setAttribute("tooltiptext", browser.securityUI.tooltipText);
     }
-    if (level) {
-      this.securityButton.setAttribute("level", level);
-      this.securityButton.hidden = false;
-    } else {
-      this.securityButton.hidden = true;
-      this.securityButton.removeAttribute("level");
-    }
-    this.securityButton.setAttribute("tooltiptext",
-                                     browser.securityUI.tooltipText);
-  }
+};
+
+function cancelRequest() {
+    reportUserClosed();
+    window.close();
 }
 
-function cancelRequest()
-{
-  reportUserClosed();
-  window.close();
-}
-
-function reportUserClosed()
-{
-  let request = window.arguments[0].wrappedJSObject;
-  request.cancelled();
+function reportUserClosed() {
+    let request = window.arguments[0].wrappedJSObject;
+    request.cancelled();
 }
 
-function loadRequestedUrl()
-{
-  let request = window.arguments[0].wrappedJSObject;
-  document.getElementById("headerMessage").textContent = request.promptText;
-  let account = request.account;
-  if (request.iconURI != "")
-    document.getElementById("headerImage").src = request.iconURI;
+function loadRequestedUrl() {
+    let request = window.arguments[0].wrappedJSObject;
+    document.getElementById("headerMessage").textContent = request.promptText;
+    if (request.iconURI != "") {
+        document.getElementById("headerImage").src = request.iconURI;
+    }
 
-  var browser = document.getElementById("requestFrame");
-  browser.addProgressListener(reporterListener,
-                              Components.interfaces.nsIWebProgress.NOTIFY_ALL);
-  var url = request.url;
-  if (url != "") {
-    browser.setAttribute("src", url);
-    document.getElementById("headerMessage").textContent = url;
-  }
+    let browser = document.getElementById("requestFrame");
+    browser.addProgressListener(reporterListener,
+                                Components.interfaces.nsIWebProgress.NOTIFY_ALL);
+    let url = request.url;
+    if (url != "") {
+        browser.setAttribute("src", url);
+        document.getElementById("headerMessage").textContent = url;
+    }
 
-  var dialogMessage =  document.getElementById("dialogMessage");
-  if (request.description) {
-    dialogMessage.textContent = request.description;
-  } else {
-    dialogMessage.setAttribute("hidden", "true");
-  }
-  request.loaded(window, browser.webProgress);
+    let dialogMessage = document.getElementById("dialogMessage");
+    if (request.description) {
+        dialogMessage.textContent = request.description;
+    } else {
+        dialogMessage.setAttribute("hidden", "true");
+    }
+    request.loaded(window, browser.webProgress);
 }
--- a/calendar/providers/gdata/content/gdata-calendar-creation.js
+++ b/calendar/providers/gdata/content/gdata-calendar-creation.js
@@ -25,17 +25,16 @@ ChromeUtils.import("resource://gdata-pro
             }
         };
     }
 
     let previousUriValue = null;
     function selectProvider(type) {
         let isGdata = (type == "gdata");
         let curi = document.getElementById("calendar-uri");
-        let wizard = document.documentElement;
 
         curi.parentNode.style.visibility = (isGdata ? "hidden" : "visible");
         document.getElementById("cache").parentNode.style.visibility = (isGdata ? "hidden" : "visible");
 
         // Move the next step descrition to the right place
         let locationRows = document.querySelector("#calendar-wizard > [pageid='locationPage'] > grid > rows");
         let nextStepDescr = document.getElementById("gdata-nextstep-description");
         locationRows.appendChild(nextStepDescr);
@@ -54,83 +53,84 @@ ChromeUtils.import("resource://gdata-pro
             }
         }
 
         checkRequired();
     }
     this.gdataSelectProvider = selectProvider;
 
     if (typeof tmpCalendarCreation == "undefined") {
-        monkeyPatch(window, "onSelectProvider", function(protofunc, type) {
+        monkeyPatch(window, "onSelectProvider", (protofunc, type) => {
             selectProvider(type);
             return protofunc(type);
         });
     } else {
         // The exchange provider overwrites the select handler, which causes
         // our provider to fail. The exchange provider overwrites the select
         // handler, which causes our provider to fail. Given the exchange
         // provider is currently not maintained and we want them to work
         // together, here is a workaround.
-        monkeyPatch(tmpCalendarCreation, "doRadioExchangeCalendar", function(protofunc, target) {
+        monkeyPatch(tmpCalendarCreation, "doRadioExchangeCalendar", (protofunc, target) => {
             // We need to run our function first, otherwise resetting the
             // pageorder will overwrite what the exchange provider does.
             selectProvider(target.value);
             let rv = protofunc(target);
 
             // But then again, when switching to the gdata provider, the
             // exchange provider overwrites the uri we set.
             if (target.value == "gdata") {
                 let curi = document.getElementById("calendar-uri");
                 curi.value = "googleapi://unknown";
                 checkRequired();
             }
             return rv;
         });
     }
 
-    monkeyPatch(window, "prepareCreateCalendar", function(protofunc) {
-        let type = document.getElementById('calendar-format').selectedItem.value;
+    monkeyPatch(window, "prepareCreateCalendar", (protofunc) => {
+        let type = document.getElementById("calendar-format").selectedItem.value;
         return (type == "gdata" ? true : protofunc());
     });
 
-    monkeyPatch(window, "checkRequired", function(protofunc) {
+    monkeyPatch(window, "checkRequired", (protofunc) => {
         let wizard = document.documentElement;
         let currentPageId = wizard.currentPage && wizard.currentPage.pageid;
 
         if (currentPageId == "gdata-session") {
             let sessionGroup = document.getElementById("gdata-session-group");
             let sessionName = document.getElementById("gdata-session-name");
             let sessionNameIsValid = document.getAnonymousElementByAttribute(sessionName, "anonid", "input").validity.valid;
             // TODO for some reason the validity doesn't work on windows. Here is a hack:
+            // eslint-disable-next-line no-useless-escape
             sessionNameIsValid = !!sessionName.value.match(/^[^\/]+@[^\/]+\.[^\/]+$/);
             wizard.canAdvance = sessionGroup.value || (sessionName.value && sessionNameIsValid);
         } else if (currentPageId == "gdata-calendars") {
             let calendarList = document.getElementById("calendar-list");
-            let calendars = calendarList.selectedCalendars.filter(function(x) { return !x.getProperty("disabled") && !x.readOnly; });
+            let calendars = calendarList.selectedCalendars.filter(calendar => !calendar.getProperty("disabled") && !calendar.readOnly);
             wizard.canAdvance = !!calendars.length;
         } else {
             protofunc();
         }
     });
 
-    this.gdataSessionShow = trycatch(function() {
+    this.gdataSessionShow = trycatch(() => {
         let sessionMgr = getGoogleSessionManager();
         let sessionContainer = document.getElementById("gdata-session-group");
         let newSessionItem = document.getElementById("session-new");
         let calendars = cal.getCalendarManager().getCalendars({});
-        let sessions = new Set(calendars.map(function(calendar) {
-          return sessionMgr.getSessionByCalendar(calendar, true);
+        let sessions = new Set(calendars.map((calendar) => {
+            return sessionMgr.getSessionByCalendar(calendar, true);
         }));
 
         while (sessionContainer.firstChild.id != "session-new") {
-            sessionContainer.removeChild(sessionContainer.firstChild);
+            sessionContainer.firstChild.remove();
         }
 
         // forEach is needed for backwards compatibility.
-        sessions.forEach(function(session) {
+        sessions.forEach((session) => {
             if (!session) {
                 return;
             }
 
             let radio = document.createElement("radio");
             radio.setAttribute("value", session.id);
             radio.setAttribute("label", session.id);
             sessionContainer.insertBefore(radio, newSessionItem);
@@ -139,58 +139,57 @@ ChromeUtils.import("resource://gdata-pro
 
         sessionContainer.value = sessionContainer.firstChild.value;
         if (sessionContainer.value == "") {
             let sessionName = document.getElementById("gdata-session-name");
             sessionName.focus();
         }
     });
 
-    this.gdataCalendarsShow = trycatch(function() {
+    this.gdataCalendarsShow = trycatch(() => {
         let calMgr = cal.getCalendarManager();
         let sessionMgr = getGoogleSessionManager();
         let sessionContainer = document.getElementById("gdata-session-group");
         let calendarListWidget = document.getElementById("calendar-list");
         calendarListWidget.clear();
 
         let session = sessionContainer.selectedItem.gdataSession;
         if (!session) {
             let newSessionItem = document.getElementById("gdata-session-name");
             session = sessionMgr.getSessionById(newSessionItem.value, true);
         }
 
-        Promise.all([session.getTasksList(), session.getCalendarList()])
-               .then(function([tasksLists, calendarList]) {
+        Promise.all([session.getTasksList(), session.getCalendarList()]).then(([tasksLists, calendarList]) => {
             let existing = new Set();
             let sessionPrefix = "googleapi://" + session.id;
             for (let calendar of calMgr.getCalendars({})) {
                 let spec = calendar.uri.spec;
                 if (calendar.type == "gdata" && spec.substr(0, sessionPrefix.length) == sessionPrefix) {
                     let match;
                     if ((match = spec.match(/calendar=([^&]*)/))) {
                         existing.add(decodeURIComponent(match[0]));
                     }
                     if ((match = spec.match(/tasks=([^&]*)/))) {
                         existing.add(decodeURIComponent(match[0]));
                     }
                 }
             }
 
-            let taskcals = tasksLists.map(function(tasklist) {
+            let taskcals = tasksLists.map((tasklist) => {
                 let uri = "googleapi://" + session.id + "/?tasks=" + encodeURIComponent(tasklist.id);
                 let calendar = calMgr.createCalendar("gdata", Services.io.newURI(uri));
                 calendar.id = cal.getUUID();
                 calendar.setProperty("color", cal.view.hashColor(tasklist.title));
                 calendar.name = tasklist.title;
                 if (existing.has("tasks=" + tasklist.id)) {
                     calendar.readOnly = true;
                 }
                 return calendar;
             });
-            let calcals = calendarList.map(function(calendarEntry) {
+            let calcals = calendarList.map((calendarEntry) => {
                 let uri = "googleapi://" + session.id + "/?calendar=" + encodeURIComponent(calendarEntry.id);
                 let calendar = calMgr.createCalendar("gdata", Services.io.newURI(uri));
                 calendar.name = calendarEntry.summary;
                 calendar.id = cal.getUUID();
                 calendar.setProperty("color", calendarEntry.backgroundColor);
                 if (existing.has("calendar=" + calendarEntry.id)) {
                     calendar.readOnly = true;
                 }
@@ -198,35 +197,35 @@ ChromeUtils.import("resource://gdata-pro
             });
 
             let calendars = [calendarListWidget.mockCalendarHeader]
                             .concat(calcals)
                             .concat([calendarListWidget.mockTaskHeader])
                             .concat(taskcals);
 
             calendarListWidget.calendars = calendars;
-        }.bind(this), function(e) {
+        }, (e) => {
             Components.utils.reportError(e);
-        }.bind(this));
+        });
     });
 
-    this.gdataCalendarsAdvance = trycatch(function() {
+    this.gdataCalendarsAdvance = trycatch(() => {
         let calendarList = document.getElementById("calendar-list");
-        let calendars = calendarList.selectedCalendars.filter(function(x) { return !x.getProperty("disabled") && !x.readOnly; });
+        let calendars = calendarList.selectedCalendars.filter(calendar => !calendar.getProperty("disabled") && !calendar.readOnly);
         let calMgr = cal.getCalendarManager();
         calendars.forEach(calMgr.registerCalendar, calMgr);
         return true;
     });
 
-    this.gdataFocusNewSession = trycatch(function() {
+    this.gdataFocusNewSession = trycatch(() => {
         let sessionContainer = document.getElementById("gdata-session-group");
         sessionContainer.value = "";
     });
 
-    document.addEventListener("DOMContentLoaded", function() {
+    document.addEventListener("DOMContentLoaded", () => {
         // Older versions of Lightning don't set the onselect attribute at all.
         let calendarFormat = document.getElementById("calendar-format");
         if (!calendarFormat.hasAttribute("onselect")) {
             calendarFormat.setAttribute("onselect", "gdataSelectProvider(this.value)");
         }
 
         if (!("updateStyleSheetForViews" in window)) {
             window.updateStyleSheetForViews = function() {};
--- a/calendar/providers/gdata/content/gdata-calendar-event-dialog.js
+++ b/calendar/providers/gdata/content/gdata-calendar-event-dialog.js
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 ChromeUtils.import("resource://gdata-provider/modules/gdataUtils.jsm");
 
 ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
 ChromeUtils.import("resource://gdata-provider/modules/calUtilsShim.jsm");
 
 (function() {
-
     // Older versions of Lightning don't have this variable.
     if (!("gOldEndTimezone" in window)) {
         window.gOldEndTimezone = null;
     }
 
     monkeyPatch(window, "updateCalendar", function(protofunc, ...args) {
         let rv = protofunc.apply(this, args);
         let calendar = getCurrentCalendar();
@@ -78,17 +77,17 @@ ChromeUtils.import("resource://gdata-pro
         let duedate = document.getElementById("todo-duedate");
         let duetime = document.getAnonymousElementByAttribute(duedate, "anonid", "time-picker");
         duetime.style.display = isGoogleTask ? "none" : "";
 
         if (gEndTime) {
             if (isGoogleTask) {
                 let floating = cal.dtz.floating;
                 if (gEndTimezone != floating) {
-                  gOldEndTimezone = gEndTimezone;
+                    gOldEndTimezone = gEndTimezone;
                 }
                 gEndTimezone = cal.dtz.floating;
                 gEndTime = gEndTime.getInTimezone(gEndTimezone);
                 gEndTime.isDate = true;
             } else {
                 if (gOldEndTimezone) {
                     gEndTimezone = gOldEndTimezone;
                 }
@@ -110,17 +109,19 @@ ChromeUtils.import("resource://gdata-pro
         }
 
         document.getElementById("gdata-reminder-default-menuitem").style.display = hasDefaultReminders ? "" : "none";
 
         // Older versions of Lightning don't update the category menulist.
         if (!document.getElementById("item-categories-panel")) {
             let categoriesLabel = document.getElementById("event-grid-category-color-row").firstChild;
             let calendarLabel = document.getElementById("item-categories").nextSibling;
-            if (!categoriesLabel.origLabel) categoriesLabel.origLabel = categoriesLabel.value;
+            if (!categoriesLabel.origLabel) {
+                categoriesLabel.origLabel = categoriesLabel.value;
+            }
 
             setBooleanAttribute("item-categories", "hidden", isGoogleTask);
             setBooleanAttribute(calendarLabel, "hidden", isGoogleTask);
 
             if (isGoogleTask) {
                 categoriesLabel.value = calendarLabel.value;
             } else {
                 categoriesLabel.value = categoriesLabel.origLabel;
@@ -129,19 +130,19 @@ ChromeUtils.import("resource://gdata-pro
         return rv;
     });
 
     monkeyPatch(window, "updateCategoryMenulist", function(protofunc, ...args) {
         let rv;
         let calendar = getCurrentCalendar();
         if (calendar.type == "gdata" && cal.item.isToDo(window.calendarItem)) {
             let unwrappedCal = calendar.getProperty("cache.uncachedCalendar").wrappedJSObject;
-            unwrappedCal.mProperties['capabilities.categories.maxCount'] = 0;
+            unwrappedCal.mProperties["capabilities.categories.maxCount"] = 0;
             rv = protofunc.apply(this, args);
-            delete unwrappedCal.mProperties['capabilities.categories.maxCount'];
+            delete unwrappedCal.mProperties["capabilities.categories.maxCount"];
         } else {
             rv = protofunc.apply(this, args);
         }
         return rv;
     });
 
     monkeyPatch(window, "updateReminderDetails", function(protofunc, ...args) {
         let rv = protofunc.apply(this, args);
@@ -166,32 +167,32 @@ ChromeUtils.import("resource://gdata-pro
             if (!defaultReminders.length) {
                 item.setProperty("X-DEFAULT-ALARM", "TRUE");
             }
             return null;
         } else {
             item.deleteProperty("X-DEFAULT-ALARM");
             return protofunc.apply(this, args);
         }
-    })
+    });
 
     monkeyPatch(window, "loadReminders", function(protofunc, reminders, ...args) {
         let reminderList = document.getElementById("item-alarm");
 
         // Set up the default reminders item
         let defaultItem = document.getElementById("gdata-reminder-default-menuitem");
         let calendar = getCurrentCalendar().getProperty("cache.uncachedCalendar");
         let unwrappedCal = calendar && calendar.wrappedJSObject;
         let defaultReminders = unwrappedCal.defaultReminders ? unwrappedCal.defaultReminders.concat([]) : [];
         defaultItem.reminders = defaultReminders;
 
         let rv = null;
         let usesDefault;
         if (reminders.length) {
-            usesDefault = reminders.every(function(x) { return x.hasProperty("X-DEFAULT-ALARM"); });
+            usesDefault = reminders.every(reminder => reminder.hasProperty("X-DEFAULT-ALARM"));
         } else {
             usesDefault = window.calendarItem.getProperty("X-DEFAULT-ALARM") == "TRUE";
         }
 
         if (calendar.type == "gdata" && (window.mode == "new" || usesDefault)) {
             // If all reminders are default reminders, then select the menuitem.
             reminderList.value = "default";
 
--- a/calendar/providers/gdata/content/gdata-calendar-properties.js
+++ b/calendar/providers/gdata/content/gdata-calendar-properties.js
@@ -12,20 +12,20 @@
             let isEventsCalendar = gCalendar.getProperty("capabilities.events.supported");
             let isDisabled = gCalendar.getProperty("disabled");
 
             // Disable setting read-only if the calendar is readonly anyway
             document.getElementById("read-only").disabled = isDisabled || (isEventsCalendar && isReader);
 
             // Don't allow setting refresh interval to less than 30 minutes
             let refInterval = document.getElementById("calendar-refreshInterval-menupopup");
-            Array.from(refInterval.childNodes).filter(function(n) {
-                let nv = parseInt(n.getAttribute("value"), 10);
-                return nv < 30 && nv != 0;
-            }).forEach(function(n) { refInterval.removeChild(n); });
+            Array.from(refInterval.childNodes).filter((node) => {
+                let nodeval = parseInt(node.getAttribute("value"), 10);
+                return nodeval < 30 && nodeval != 0;
+            }).forEach((node) => { refInterval.removeChild(node); });
 
             // Old Lightning doesn't hide the cache label
             let oldCacheLabel = document.getElementById("cache");
             if (oldCacheLabel) {
                 oldCacheLabel.setAttribute("hidden", "true");
             }
         }
         return rv;
--- a/calendar/providers/gdata/content/gdata-event-dialog-reminder.js
+++ b/calendar/providers/gdata/content/gdata-event-dialog-reminder.js
@@ -14,18 +14,18 @@
     }
 
     let label = getProviderString("reminderOutOfRange");
     let notification = createXULElement("notification");
     notification.setAttribute("label", label);
     notification.setAttribute("type", "critical");
     notification.setAttribute("hideclose", "true");
 
-    function calculateAlarmOffset(item, reminder) {
-        let offset = cal.alarms.calculateAlarmOffset(item, reminder);
+    function calculateAlarmOffset(alarmitem, reminder) {
+        let offset = cal.alarms.calculateAlarmOffset(alarmitem, reminder);
         // bug 1196455: The offset calcuated for absolute alarms is flipped
         if (Services.vc.compare(Services.appinfo.platformVersion, "43.0") < 0) {
             if (reminder.related == reminder.ALARM_RELATED_ABSOLUTE) {
                 offset.isNegative = !offset.isNegative;
             }
         }
         return offset;
     }
@@ -82,23 +82,23 @@
     }
 
     monkeyPatch(window, "updateReminder", function(protofunc, event) {
         let rv = protofunc.apply(this, Array.from(arguments).slice(1));
         if (event.explicitOriginalTarget.localName == "listitem" ||
             event.explicitOriginalTarget.id == "reminder-remove-button" ||
             !document.commandDispatcher.focusedElement) {
             // Same hack from the original dialog
-            return;
+            return undefined;
         }
 
         checkAllReminders();
         return rv;
     });
 
-    monkeyPatch(window, "loadReminders", function(protofunc /*, ...args */) {
-        let rv = protofunc.apply(this, Array.from(arguments).slice(1));
+    monkeyPatch(window, "loadReminders", function(protofunc, ...args) {
+        let rv = protofunc.apply(this, args);
         checkAllReminders();
         hideReminderRelations();
         hideSMSReminders();
         return rv;
     });
 })();
--- a/calendar/providers/gdata/content/gdata-list-tree.xml
+++ b/calendar/providers/gdata/content/gdata-list-tree.xml
@@ -59,180 +59,180 @@
                           onunderflow="displayScrollbarSpacer(false)">
           <children includes="tooltip|menupopup"/>
         </xul:treechildren>
       </xul:tree>
     </content>
 
     <implementation>
       <constructor><![CDATA[
-        this.tree.view = this;
+          this.tree.view = this;
       ]]></constructor>
 
       <property name="mockCalendarHeader" readonly="true">
         <getter><![CDATA[
-          let calmgr = cal.getCalendarManager();
-          let uri = "dummy://calendar";
-          let mem = calmgr.createCalendar("memory", Services.io.newURI(uri));
-          mem.setProperty("disabled", true);
-          mem.name = "Calendars";
-          mem.id = cal.getUUID();
-          return mem;
+            let calmgr = cal.getCalendarManager();
+            let uri = "dummy://calendar";
+            let mem = calmgr.createCalendar("memory", Services.io.newURI(uri));
+            mem.setProperty("disabled", true);
+            mem.name = "Calendars";
+            mem.id = cal.getUUID();
+            return mem;
         ]]></getter>
       </property>
 
       <property name="mockTaskHeader" readonly="true">
         <getter><![CDATA[
-          let calmgr = cal.getCalendarManager();
-          let uri = "dummy://tasks";
-          let mem = calmgr.createCalendar("memory", Services.io.newURI(uri));
-          mem.setProperty("disabled", true);
-          mem.name = "Task Lists";
-          mem.id = cal.getUUID();
-          return mem;
+            let calmgr = cal.getCalendarManager();
+            let uri = "dummy://tasks";
+            let mem = calmgr.createCalendar("memory", Services.io.newURI(uri));
+            mem.setProperty("disabled", true);
+            mem.name = "Task Lists";
+            mem.id = cal.getUUID();
+            return mem;
         ]]></getter>
       </property>
 
       <field name="mCalendarHeaderIndex">0</field>
       <field name="mTasksHeaderIndex">0</field>
 
       <field name="QueryInterface">XPCOMUtils.generateQI([Components.interfaces.nsITreeView])</field>
 
       <property name="calendars">
         <getter><![CDATA[
-          return this.mCalendarList;
+            return this.mCalendarList;
         ]]></getter>
         <setter><![CDATA[
-          for (let i = 0; i < val.length; i++) {
-              let calendar = val[i];
-              let spec = calendar.uri.spec;
-              if (calendar.type == "memory") {
-                  if (spec == "dummy://calendar") {
-                      this.mCalendarHeaderIndex = i;
-                  } else if (spec == "dummy://tasks") {
-                      this.mTasksHeaderIndex = i;
-                  }
-              }
-              this.addCalendar(calendar);
-          }
-          return this.mCalendarList;
+            for (let i = 0; i < val.length; i++) {
+                let calendar = val[i];
+                let spec = calendar.uri.spec;
+                if (calendar.type == "memory") {
+                    if (spec == "dummy://calendar") {
+                        this.mCalendarHeaderIndex = i;
+                    } else if (spec == "dummy://tasks") {
+                        this.mTasksHeaderIndex = i;
+                    }
+                }
+                this.addCalendar(calendar);
+            }
+            return this.mCalendarList;
         ]]></setter>
       </property>
 
       <method name="removeCalendar">
         <parameter name="aCalendar"/>
         <body><![CDATA[
-          let index = this.findIndexById(aCalendar.id);
-          if (index < this.mCalendarHeaderIndex) {
-            this.mCalendarHeaderIndex--;
-          }
-          if (index < this.mTasksHeaderIndex) {
-            this.mTasksHeaderIndex--;
-          }
-          return this.__proto__.__proto__.removeCalendar.call(this, aCalendar);
+            let index = this.findIndexById(aCalendar.id);
+            if (index < this.mCalendarHeaderIndex) {
+                this.mCalendarHeaderIndex--;
+            }
+            if (index < this.mTasksHeaderIndex) {
+                this.mTasksHeaderIndex--;
+            }
+            return this.__proto__.__proto__.removeCalendar.call(this, aCalendar);
         ]]></body>
       </method>
 
       <method name="clear">
         <body><![CDATA[
-          let calendars = this.mCalendarList.concat([]);
-          calendars.forEach(this.removeCalendar, this);
+            let calendars = this.mCalendarList.concat([]);
+            calendars.forEach(this.removeCalendar, this);
         ]]></body>
       </method>
 
       <method name="getRowProperties">
         <parameter name="aRow"/>
         <parameter name="aProps"/>
         <body><![CDATA[
-          let props = this.__proto__.__proto__.getRowProperties.call(this, aRow, aProps);
-          let calendar = this.getCalendar(aRow);
+            let props = this.__proto__.__proto__.getRowProperties.call(this, aRow, aProps);
+            let calendar = this.getCalendar(aRow);
 
-          if (calendar.readOnly) {
-              if (aProps) {
-                  // Compatibility with old tree props code
-                  aProps.AppendElement(cal.getAtomFromService("checked"));
-              } else {
-                  props += " checked";
-              }
-          }
+            if (calendar.readOnly) {
+                if (aProps) {
+                    // Compatibility with old tree props code
+                    aProps.AppendElement(cal.getAtomFromService("checked"));
+                } else {
+                    props += " checked";
+                }
+            }
 
-          return props;
+            return props;
         ]]></body>
       </method>
 
       <method name="isContainerEmpty">
         <parameter name="aRow"/>
         <body><![CDATA[
-          return (aRow == this.mCalendarHeaderIndex &&
-                  aRow + 1 == this.mTasksHeaderIndex) ||
-                 (aRow == this.mTasksHeaderIndex &&
-                  aRow == this.mCalendarList.length);
+            return (aRow == this.mCalendarHeaderIndex &&
+                    aRow + 1 == this.mTasksHeaderIndex) ||
+                   (aRow == this.mTasksHeaderIndex &&
+                    aRow == this.mCalendarList.length);
         ]]></body>
       </method>
 
       <method name="isContainer">
         <parameter name="aRow"/>
         <body><![CDATA[
-          let calendar = this.getCalendar(aRow);
-          return (calendar.type == "memory" && calendar.uri.schemeIs("dummy"));
+            let calendar = this.getCalendar(aRow);
+            return (calendar.type == "memory" && calendar.uri.schemeIs("dummy"));
         ]]></body>
       </method>
 
       <method name="isContainerOpen">
         <parameter name="aRow"/>
         <body><![CDATA[
-          return true;
+            return true;
         ]]></body>
       </method>
 
       <method name="getParentIndex">
         <parameter name="aRow"/>
         <body><![CDATA[
-          let calendar = this.getCalendar(aRow);
-          if (calendar.uri.path.includes("?calendar")) {
-              return this.mCalendarHeaderIndex;
-          } else if (calendar.uri.path.includes("?tasks")) {
-              return this.mTasksHeaderIndex;
-          } else {
-              return -1;
-          }
+            let calendar = this.getCalendar(aRow);
+            if (calendar.uri.path.includes("?calendar")) {
+                return this.mCalendarHeaderIndex;
+            } else if (calendar.uri.path.includes("?tasks")) {
+                return this.mTasksHeaderIndex;
+            } else {
+                return -1;
+            }
         ]]></body>
       </method>
 
       <method name="hasNextSibling">
         <parameter name="aRow"/>
         <parameter name="aAfterIndex"/>
         <body><![CDATA[
-          if (aRow == this.mCalendarHeaderIndex) {
-              return aAfterIndex < this.mTasksHeaderIndex;
-          } else if (aRow == this.mTasksHeaderIndex) {
-              return false;
-          } else {
-              return aAfterIndex != this.mCalendarHeaderIndex - 1 &&
-                     aAfterIndex != this.mTasksHeaderIndex - 1;
-          }
+            if (aRow == this.mCalendarHeaderIndex) {
+                return aAfterIndex < this.mTasksHeaderIndex;
+            } else if (aRow == this.mTasksHeaderIndex) {
+                return false;
+            } else {
+                return aAfterIndex != this.mCalendarHeaderIndex - 1 &&
+                       aAfterIndex != this.mTasksHeaderIndex - 1;
+            }
         ]]></body>
       </method>
 
       <method name="cycleCell">
         <parameter name="aRow"/>
         <parameter name="aCol"/>
         <body><![CDATA[
-          let calendar = this.getCalendar(aRow);
-          let composite = this.compositeCalendar;
-          if (composite.getCalendarById(calendar.id)) {
-              composite.removeCalendar(calendar);
-          } else {
-              composite.addCalendar(calendar);
-          }
-          this.treebox.invalidateRow(aRow);
+            let calendar = this.getCalendar(aRow);
+            let composite = this.compositeCalendar;
+            if (composite.getCalendarById(calendar.id)) {
+                composite.removeCalendar(calendar);
+            } else {
+                composite.addCalendar(calendar);
+            }
+            this.treebox.invalidateRow(aRow);
         ]]></body>
       </method>
 
       <method name="getLevel">
         <parameter name="aRow"/>
         <body><![CDATA[
-          return this.isContainer(aRow) ? 0 : 1;
+            return this.isContainer(aRow) ? 0 : 1;
         ]]></body>
       </method>
     </implementation>
   </binding>
 </bindings>
--- a/calendar/providers/gdata/content/gdata-migration.js
+++ b/calendar/providers/gdata/content/gdata-migration.js
@@ -1,15 +1,17 @@
 /* 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/. */
 
 ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Preferences.jsm");
 
+/* exported migrateSelectedCalendars */
+
 /**
  * Migrate the calendar selected in the wizard from ics to gdata.
  */
 function migrateSelectedCalendars() {
     let listbox = document.getElementById("calendars-listbox");
     let calmgr = cal.getCalendarManager();
 
     for (let i = 0; i < listbox.childNodes.length; i++) {
@@ -50,22 +52,22 @@ function migrateSelectedCalendars() {
 }
 
 /**
  * Get all calendars that are ics and point to a google calendar
  *
  * @return An array of calendars that are migratable
  */
 function getMigratableCalendars() {
-    function isMigratable(c) {
+    function isMigratable(calendar) {
         let re = new RegExp("^http[s]?://www\\.google\\.com/calendar/ical/" +
                             "[^/]+/(private(-[^/]+)?|public)/" +
                             "(full|full-noattendees|composite|" +
                             "attendees-only|free-busy|basic)(\\.ics)?$");
-        return c.type == "ics" && c.uri.spec.match(re);
+        return calendar.type == "ics" && calendar.uri.spec.match(re);
     }
 
     return cal.getCalendarManager().getCalendars({}).filter(isMigratable);
 }
 
 /**
  * Load Handler for both the wizard and the Thunderbird main window.
  */
@@ -78,33 +80,30 @@ function gdata_migration_loader() {
             let item = listbox.appendItem(calendar.name, calendar.id);
             item.setAttribute("type", "checkbox");
             item.calendar = calendar;
         }
 
         // Set up the "always check" field
         document.getElementById("showagain-checkbox").checked =
             Preferences.get("calendar.google.migrate", true);
-    } else {
+    } else if (Preferences.get("calendar.google.migrate", true) &&
+               getMigratableCalendars().length > 0) {
         // This is not the migration wizard, so it must be a main window. Check
-        // if the migration wizard needs to be shown.
-        if (Preferences.get("calendar.google.migrate", true)) {
-            // Check if there are calendars that are worth migrating.
-            if (getMigratableCalendars().length > 0) {
-                // Do this after load, so the calendar window appears before the
-                // wizard is opened.
+        // if the migration wizard needs to be shown and calendars are worth
+        // migrating.
 
-                // XXX Waiting a second gives the views enough time to display
-                // right, at least on my system. The viewloaded event is quite
-                // view specific, so there is no good non-hacked way to do this.
-                setTimeout(function() {
-                    window.openDialog("chrome://gdata-provider/content/gdata-migration-wizard.xul",
-                                      "GdataMigrationWizard",
-                                      "chrome,titlebar,modal,alwaysRaised");
-                }, 1000);
-            }
-        }
+        // Do this after load, so the calendar window appears before the
+        // wizard is opened.
+        // XXX Waiting a second gives the views enough time to display
+        // right, at least on my system. The viewloaded event is quite
+        // view specific, so there is no good non-hacked way to do this.
+        setTimeout(() => {
+            window.openDialog("chrome://gdata-provider/content/gdata-migration-wizard.xul",
+                              "GdataMigrationWizard",
+                              "chrome,titlebar,modal,alwaysRaised");
+        }, 1000);
     }
 }
 
 // Add a Load handler to check for migratable calendars in the main window, or
 // to load the migration wizard if this is the migration wizard
 window.addEventListener("load", gdata_migration_loader, { capture: false, once: true });
--- a/calendar/providers/gdata/modules/OAuth2.jsm
+++ b/calendar/providers/gdata/modules/OAuth2.jsm
@@ -1,31 +1,29 @@
 /* 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/. */
 
 /**
  * Provides OAuth 2.0 authentication
  */
-var EXPORTED_SYMBOLS = ["OAuth2"];
-
-var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
+var EXPORTED_SYMBOLS = ["OAuth2"]; /* exported OAuth2 */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource:///modules/gloda/log4moz.js");
 ChromeUtils.import("resource://gre/modules/Http.jsm");
 
 function parseURLData(aData) {
-  let result = {};
-  aData.split(/[?#]/, 2)[1].split("&").forEach(function (aParam) {
-    let [key, value] = aParam.split("=");
-    result[key] = value;
-  });
-  return result;
+    let result = {};
+    aData.split(/[?#]/, 2)[1].split("&").forEach((aParam) => {
+        let [key, value] = aParam.split("=");
+        result[key] = value;
+    });
+    return result;
 }
 
 function OAuth2(aBaseURI, aScope, aAppKey, aAppSecret) {
     this.authURI = aBaseURI + "oauth2/auth";
     this.tokenURI = aBaseURI + "oauth2/token";
     this.consumerKey = aAppKey;
     this.consumerSecret = aAppSecret;
     this.scope = aScope;
@@ -49,17 +47,17 @@ OAuth2.prototype = {
     requestWindowDescription: "",
     scope: null,
 
     accessToken: null,
     refreshToken: null,
     tokenExpires: 0,
     connecting: false,
 
-    connect: function connect(aSuccess, aFailure, aWithUI, aRefresh) {
+    connect: function(aSuccess, aFailure, aWithUI, aRefresh) {
         if (this.connecting) {
             return;
         }
 
         this.connectSuccessCallback = aSuccess;
         this.connectFailureCallback = aFailure;
 
         if (!aRefresh && this.accessToken) {
@@ -72,108 +70,111 @@ OAuth2.prototype = {
                 aFailure('{ "error": "auth_noui" }');
                 return;
             }
             this.connecting = true;
             this.requestAuthorization();
         }
     },
 
-    requestAuthorization: function requestAuthorization() {
+    requestAuthorization: function() {
         let params = [
             ["response_type", this.responseType],
             ["client_id", this.consumerKey],
             ["redirect_uri", this.completionURI],
         ];
         // The scope can be optional.
         if (this.scope) {
             params.push(["scope", this.scope]);
         }
 
         // Add extra parameters, if they exist
         Array.prototype.push.apply(params, this.extraAuthParams);
 
         // Now map the parameters to a string
-        params = params.map(function([k, v]) { return k + "=" + encodeURIComponent(v); }).join("&");
+        params = params.map(([k, v]) => k + "=" + encodeURIComponent(v)).join("&");
 
         this._browserRequest = {
             account: this,
             url: this.authURI + "?" + params,
             description: this.requestWindowDescription,
             _active: true,
             iconURI: "",
             cancelled: function() {
                 if (!this._active) {
                     return;
                 }
 
                 this.account.finishAuthorizationRequest();
                 this.account.onAuthorizationFailed(Components.results.NS_ERROR_ABORT, '{ "error": "cancelled"}');
             },
 
-            loaded: function (aWindow, aWebProgress) {
+            loaded: function(aWindow, aWebProgress) {
                 if (!this._active) {
                     return;
                 }
 
                 this._listener = {
                     window: aWindow,
                     webProgress: aWebProgress,
                     _parent: this.account,
 
-                    QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
-                                                           Ci.nsISupportsWeakReference]),
+                    QueryInterface: XPCOMUtils.generateQI([
+                        Components.interfaces.nsIWebProgressListener,
+                        Components.interfaces.nsISupportsWeakReference
+                    ]),
 
                     _cleanUp: function() {
-                      this.webProgress.removeProgressListener(this);
-                      this.window.close();
-                      delete this.window;
+                        this.webProgress.removeProgressListener(this);
+                        this.window.close();
+                        delete this.window;
                     },
 
                     _checkForRedirect: function(aURL) {
-                      if (!aURL.startsWith(this._parent.completionURI)) {
-                        return;
-                      }
+                        if (!aURL.startsWith(this._parent.completionURI)) {
+                            return;
+                        }
 
-                      this._parent.finishAuthorizationRequest();
-                      this._parent.onAuthorizationReceived(aURL);
+                        this._parent.finishAuthorizationRequest();
+                        this._parent.onAuthorizationReceived(aURL);
                     },
 
-                    onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
-                      const wpl = Ci.nsIWebProgressListener;
-                      if (aStateFlags & (wpl.STATE_STOP)) {
-                        try {
-                            let httpchannel = aRequest.QueryInterface(Components.interfaces.nsIHttpChannel);
+                    onStateChange: function(aChangedWebProgress, aRequest, aStateFlags, aStatus) {
+                        const wpl = Components.interfaces.nsIWebProgressListener;
+                        if (aStateFlags & (wpl.STATE_STOP)) {
+                            try {
+                                let httpchannel = aRequest.QueryInterface(Components.interfaces.nsIHttpChannel);
 
-                            let responseCategory = Math.floor(httpchannel.responseStatus / 100);
+                                let responseCategory = Math.floor(httpchannel.responseStatus / 100);
 
-                            if (responseCategory != 2 && responseCategory != 3) {
-                                this._parent.finishAuthorizationRequest();
-                                this._parent.onAuthorizationFailed(null, '{ "error": "http_' + httpchannel.responseStatus + '" }');
-                            }
-                        } catch (e) {
-                            // Throw the case where it's a http channel.
-                            if (e.result != Components.results.NS_ERROR_NO_INTERFACE) {
-                                throw e;
+                                if (responseCategory != 2 && responseCategory != 3) {
+                                    this._parent.finishAuthorizationRequest();
+                                    this._parent.onAuthorizationFailed(null, '{ "error": "http_' + httpchannel.responseStatus + '" }');
+                                }
+                            } catch (e) {
+                                // Throw the case where it's a http channel.
+                                if (e.result != Components.results.NS_ERROR_NO_INTERFACE) {
+                                    throw e;
+                                }
                             }
                         }
-                      }
 
-                      if (aStateFlags & (wpl.STATE_START | wpl.STATE_IS_NETWORK))
-                        this._checkForRedirect(aRequest.name);
+                        if (aStateFlags & (wpl.STATE_START | wpl.STATE_IS_NETWORK)) {
+                            this._checkForRedirect(aRequest.name);
+                        }
                     },
-                    onLocationChange: function(aWebProgress, aRequest, aLocation) {
-                      this._checkForRedirect(aLocation.spec);
+                    onLocationChange: function(aChangedWebProgress, aRequest, aLocation) {
+                        this._checkForRedirect(aLocation.spec);
                     },
                     onProgressChange: function() {},
                     onStatusChange: function() {},
                     onSecurityChange: function() {},
                 };
                 aWebProgress.addProgressListener(this._listener,
-                                                 Ci.nsIWebProgress.NOTIFY_ALL);
+                                                 Components.interfaces.nsIWebProgress.NOTIFY_ALL);
                 aWindow.document.title = this.account.requestWindowTitle;
             }
         };
 
         this.wrappedJSObject = this._browserRequest;
         Services.ww.openWindow(null, this.requestWindowURI, null, this.requestWindowFeatures, this);
     },
     finishAuthorizationRequest: function() {
@@ -198,47 +199,47 @@ OAuth2.prototype = {
         }
     },
 
     onAuthorizationFailed: function(aError, aData) {
         this.connecting = false;
         this.connectFailureCallback(aData);
     },
 
-    requestAccessToken: function requestAccessToken(aCode, aType) {
+    requestAccessToken: function(aCode, aType) {
         let params = [
             ["client_id", this.consumerKey],
             ["client_secret", this.consumerSecret],
             ["grant_type", aType],
         ];
 
         if (aType == OAuth2.CODE_AUTHORIZATION) {
             params.push(["code", aCode]);
             params.push(["redirect_uri", this.completionURI]);
         } else if (aType == OAuth2.CODE_REFRESH) {
             params.push(["refresh_token", aCode]);
         }
 
         let options = {
-          postData: params,
-          onLoad: this.onAccessTokenReceived.bind(this),
-          onError: this.onAccessTokenFailed.bind(this)
-        }
+            postData: params,
+            onLoad: this.onAccessTokenReceived.bind(this),
+            onError: this.onAccessTokenFailed.bind(this)
+        };
         httpRequest(this.tokenURI, options);
     },
 
-    onAccessTokenFailed: function onAccessTokenFailed(aError, aData) {
+    onAccessTokenFailed: function(aError, aData) {
         if (aError != "offline") {
             this.refreshToken = null;
         }
         this.connecting = false;
         this.connectFailureCallback(aData);
     },
 
-    onAccessTokenReceived: function onRequestTokenReceived(aData) {
+    onAccessTokenReceived: function(aData) {
         let result = JSON.parse(aData);
 
         this.accessToken = result.access_token;
         if ("refresh_token" in result) {
             this.refreshToken = result.refresh_token;
         }
         if ("expires_in" in result) {
             this.tokenExpires = (new Date()).getTime() + (result.expires_in * 1000);
--- a/calendar/providers/gdata/modules/gdataLogging.jsm
+++ b/calendar/providers/gdata/modules/gdataLogging.jsm
@@ -90,19 +90,21 @@ function LOGattendee(aAttendee, asString
 
 function LOGalarm(aAlarm) {
     if (!aAlarm) {
         return "";
     }
 
     let enumerator = aAlarm.propertyEnumerator;
     let xpropstr = "";
-    while (enumerator && enumerator.hasMoreElements()) {
-        let el = enumerator.getNext();
-        xpropstr += "\n\t\t\t" + el.key + ":" + el.value;
+    if (enumerator) {
+        while (enumerator.hasMoreElements()) {
+            let elem = enumerator.getNext();
+            xpropstr += "\n\t\t\t" + elem.key + ":" + elem.value;
+        }
     }
 
     return ("\n\t\tAction: " + aAlarm.action +
             "\n\t\tOffset: " + (aAlarm.offset && aAlarm.offset.toString()) +
             "\n\t\talarmDate: " + (aAlarm.alarmDate && aAlarm.alarmDate.toString()) +
             "\n\t\trelated: " + aAlarm.related +
             "\n\t\trepeat: " + aAlarm.repeat +
             "\n\t\trepeatOffset: " + (aAlarm.repeatOffset && aAlarm.repeatOffset.toString()) +
--- a/calendar/providers/gdata/modules/gdataRequest.jsm
+++ b/calendar/providers/gdata/modules/gdataRequest.jsm
@@ -105,78 +105,78 @@ calGoogleRequest.prototype = {
     get status() {
         if (this.isPending) {
             return this.mLoader.request.status;
         } else {
             return this.mStatus;
         }
     },
 
-    cancel: function cGR_cancel(aStatus) {
+    cancel: function(aStatus) {
         if (this.isPending) {
             if (this.mLoader) {
                 this.mLoader.request.cancel(aStatus);
             }
             this.mStatus = aStatus;
         }
     },
 
     /**
      * attribute type
      * The type of this reqest. Must be one of
      * GET, ADD, MODIFY, DELETE
      */
     get type() { return this.method; },
 
-    set type(v) {
+    set type(val) {
         let valid = [this.GET, this.ADD, this.MODIFY, this.PATCH, this.DELETE];
-        if (!valid.includes(v)) {
-            throw new Components.Exception("Invalid request type: " + v,
+        if (!valid.includes(val)) {
+            throw new Components.Exception("Invalid request type: " + val,
                                             Components.results.NS_ERROR_ILLEGAL_VALUE);
         }
-        return (this.method = v);
+        return (this.method = val);
     },
 
     /**
      * setUploadData
      * The HTTP body data for a POST or PUT request.
      *
      * @param aContentType The Content type of the Data.
      * @param aData        The Data to upload.
      */
-    setUploadData: function cGR_setUploadData(aContentType, aData) {
+    setUploadData: function(aContentType, aData) {
         this.mUploadContent = aContentType;
         this.mUploadData = aData;
     },
 
-    addQueryParameter: function cGR_addQueryParameter(aKey, aValue) {
+    addQueryParameter: function(aKey, aValue) {
         if (aValue) {
             this.mQueryParameters.set(aKey, aValue);
         } else {
             this.mQueryParameters.delete(aKey);
         }
     },
 
-    addRequestHeader: function cGR_addRequestHeader(aKey, aValue) {
+    addRequestHeader: function(aKey, aValue) {
         if (aValue) {
             this.mRequestHeaders.set(aKey, aValue);
         } else {
             this.mRequestHeaders.delete(aKey);
         }
     },
 
     /**
      * commit
      * Starts the request process. This can be called multiple times if the
      * request should be repeated
      *
      * @param aSession  The session object this request should be made with.
      *                  This parameter is optional.
      */
-    commit: function cGR_commit(aSession) {
+    commit: function(aSession) {
         if (!this.mDeferred) {
             this.mDeferred = PromiseUtils.defer();
         }
         let promise = this.mDeferred.promise;
 
         try {
             // Set the session to request with
             if (aSession) {
@@ -184,18 +184,18 @@ calGoogleRequest.prototype = {
             }
 
             // create the channel
             let uristring = this.uri;
             if (this.mQueryParameters.size > 0) {
                 let params = [];
 
                 // Using forEach is needed for backwards compatibility
-                this.mQueryParameters.forEach(function(v, k) {
-                    params.push(k + "=" + encodeURIComponent(v));
+                this.mQueryParameters.forEach((val, key) => {
+                    params.push(key + "=" + encodeURIComponent(val));
                 });
                 uristring += "?" + params.join("&");
             }
             let uri = Services.io.newURI(uristring);
             let channel;
             if ("newChannelFromURI2" in Services.io) {
                 // Lightning 4.3+
                 channel = Services.io.newChannelFromURI2(uri,
@@ -230,68 +230,67 @@ calGoogleRequest.prototype = {
     /**
      * fail
      * Call this request's listener with the given code and Message
      *
      * @param aCode     The Error code to fail with.
      * @param aMessage  The Error message. If this is null, an error Message
      *                  from calGoogleRequest will be used.
      */
-    fail: function cGR_fail(aCode, aMessage) {
+    fail: function(aCode, aMessage) {
         let ex = new Components.Exception(aMessage, aCode);
         this.mLoader = null;
         this.mStatus = aCode;
         this.mDeferred.reject(ex);
         this.mDeferred = null;
     },
 
     /**
      * succeed
      * Call this request's listener with a Success Code and the given Result.
      *
      * @param aResult   The result Text of this request.
      */
-    succeed: function cGR_succeed(aResult) {
+    succeed: function(aResult) {
         this.mLoader = null;
         this.mStatus = Components.results.NS_OK;
         this.mDeferred.resolve(aResult);
         this.mDeferred = null;
     },
 
     /**
      * prepareChannel
      * Prepares the passed channel to match this objects properties
      *
      * @param aChannel    The Channel to be prepared.
      */
-    prepareChannel: function cGR_prepareChannel(aChannel) {
+    prepareChannel: function(aChannel) {
         // No caching
         aChannel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
 
         // Set upload Data
         if (this.mUploadData) {
-            let converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
-                            createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
+            let converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
+                                      .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
             converter.charset = "UTF-8";
 
             let stream = converter.convertToInputStream(this.mUploadData);
             aChannel = aChannel.QueryInterface(Components.interfaces.nsIUploadChannel);
             aChannel.setUploadStream(stream, this.mUploadContent, -1);
 
             cal.LOG("[calGoogleCalendar] Setting Upload Data (" +
                     this.mUploadContent + "):\n" + this.mUploadData);
         }
 
         aChannel = aChannel.QueryInterface(Components.interfaces.nsIHttpChannel);
 
         // Depending on the preference, we will use X-HTTP-Method-Override to
         // get around some proxies. This will default to true.
         if (Preferences.get("calendar.google.useHTTPMethodOverride", true) &&
             (this.method == "PUT" || this.method == "DELETE")) {
-
             aChannel.requestMethod = "POST";
             aChannel.setRequestHeader("X-HTTP-Method-Override",
                                       this.method,
                                       false);
             if (this.method == "DELETE") {
                 // DELETE has no body, set an empty one so that Google accepts
                 // the request.
                 aChannel.setRequestHeader("Content-Type",
@@ -303,18 +302,18 @@ calGoogleRequest.prototype = {
             aChannel.requestMethod = this.method;
         }
 
         if (this.mRequestHeaders.size) {
             cal.LOG("[calGoogleCalendar] Sending request headers: " + this.mRequestHeaders.toSource());
         }
 
         // Using forEach is needed for backwards compatibility
-        this.mRequestHeaders.forEach(function(v, k) {
-            aChannel.setRequestHeader(k, v, false);
+        this.mRequestHeaders.forEach((val, key) => {
+            aChannel.setRequestHeader(key, val, false);
         });
 
         // Add Authorization
         let token = this.mSession.accessToken;
         if (token) {
             aChannel.setRequestHeader("Authorization",
                                       "Bearer " + token,
                                       false);
@@ -328,33 +327,26 @@ calGoogleRequest.prototype = {
      * @see nsIInterfaceRequestor
      * @see calProviderUtils.jsm
      */
     getInterface: cal.InterfaceRequestor_getInterface,
 
     /**
      * @see nsIChannelEventSink
      */
-    asyncOnChannelRedirect: function cGR_onChannelRedirect(aOldChannel,
-                                                           aNewChannel,
-                                                           aFlags,
-                                                           aCallback) {
+    asyncOnChannelRedirect: function(aOldChannel, aNewChannel, aFlags, aCallback) {
         // all we need to do to the new channel is the basic preparation
         this.prepareChannel(aNewChannel);
         aCallback.onRedirectVerifyCallback(Components.results.NS_OK);
     },
 
     /**
      * @see nsIStreamLoaderObserver
      */
-    onStreamComplete: function cGR_onStreamComplete(aLoader,
-                                                    aContext,
-                                                    aStatus,
-                                                    aResultLength,
-                                                    aResult) {
+    onStreamComplete: function(aLoader, aContext, aStatus, aResultLength, aResult) {
         if (!aResult || !Components.isSuccessCode(aStatus)) {
             this.fail(aStatus, aResult);
             return;
         }
 
         let httpChannel = aLoader.request.QueryInterface(Components.interfaces.nsIHttpChannel);
 
         // Convert the stream, falling back to utf-8 in case its not given.
@@ -392,18 +384,18 @@ calGoogleRequest.prototype = {
             cal.LOG("[calGoogleRequest] Clock skew is " + getCorrectedDate.mClockSkew + " seconds");
         }
 
         // Remember when this request happened
         this.requestDate = cal.createDateTime();
         this.requestDate.nativeTime = serverDate.getTime() * 1000;
 
         cal.LOG("[calGoogleCalendar] Request " + this.method + " " +
-                httpChannel.URI.spec + " responded with HTTP "
-                + httpChannel.responseStatus);
+                httpChannel.URI.spec + " responded with HTTP " +
+                httpChannel.responseStatus);
 
         // Handle all (documented) error codes
         switch (httpChannel.responseStatus) {
             case 200: /* No error. */
             case 201: /* Creation of a resource was successful. */
             case 204: /* No content */
                 // Everything worked out, we are done
                 if (this.calendar) {
@@ -433,17 +425,17 @@ calGoogleRequest.prototype = {
                         this.fail(calGoogleRequest.TOKEN_FAILURE, reason);
                         break;
                     case "unauthorized_client":
                         // This often happens when the client makes a request
                         // authorized with an old api token. Retry the request
                         // once.
                         this.mSession.invalidate();
                         if (this.reauthenticate) {
-                            cal.LOG("[calGoogleRequest] The access token is not authorized, trying to refresh token.")
+                            cal.LOG("[calGoogleRequest] The access token is not authorized, trying to refresh token.");
                             this.reauthenticate = false;
                             this.mSession.asyncItemRequest(this);
                         } else {
                             cal.LOG("[calGoogleRequest] Even refreshed token is not authorized, looks like the client is outdated");
                             this.mSession.notifyOutdated();
                             if (this.calendar) {
                                 this.calendar.setProperty("disabled", true);
                                 this.calendar.setProperty("currentStatus", calGoogleRequest.TOKEN_FAILURE);
@@ -510,27 +502,28 @@ calGoogleRequest.prototype = {
                             objData.error.errors && objData.error.errors[0];
 
                 if (error.message == "Invalid sync token value.") {
                     this.fail(calGoogleRequest.RESOURCE_GONE, objData);
                     return;
                 }
             }
             // Otherwise fall through
-            default:
+            default: {
                 // The following codes are caught here:
                 //  500 INTERNAL SERVER ERROR: Internal error. This is the
                 //                             default code that is used for
                 //                             all unrecognized errors.
                 //
 
                 // Something else went wrong
                 let msg = "A request Error Occurred. Status Code: " +
                           httpChannel.responseStatus + " " +
                           httpChannel.responseStatusText + " Body: " +
                           result;
                 cal.LOG("[calGoogleCalendar] " + msg);
 
                 this.fail(Components.results.NS_ERROR_NOT_AVAILABLE, msg);
                 break;
+            }
         }
     }
 };
--- a/calendar/providers/gdata/modules/gdataSession.jsm
+++ b/calendar/providers/gdata/modules/gdataSession.jsm
@@ -36,29 +36,35 @@ var calGoogleSessionManager = {
      *
      * @param aCalendar  The calendar to get the session for.
      * @param aCreate    If true, the session will be created prior to returning.
      * @return           The initialized session object.
      */
     getSessionByCalendar: function(aCalendar, aCreate) {
         let id = null;
         let uri = aCalendar.uri;
-        let host = (function() { try { return uri.host; } catch (e) {} })();
+        let host = (function() {
+            try {
+                return uri.host;
+            } catch (e) {
+                return null;
+            }
+        })();
         const protocols = ["http", "https", "webcal", "webcals"];
 
         if (aCalendar.type != "gdata") {
-            return;
+            return null;
         }
 
         if (uri.schemeIs("googleapi")) {
-            let [fullUser, path] = uri.pathQueryRef.substr(2).split("/", 2);
-            id = fullUser || cal.getUUID();
-        } else if (host == "www.google.com" && uri.pathQueryRef.startsWith("/calendar/feeds") && protocols.some(function(s) { return uri.schemeIs(s); })) {
+            let parts = uri.pathQueryRef.substr(2).split("/", 2);
+            id = parts[0] || cal.getUUID();
+        } else if (host == "www.google.com" && uri.pathQueryRef.startsWith("/calendar/feeds") && protocols.some(scheme => uri.schemeIs(scheme))) {
             let googleCalendarName = aCalendar.getProperty("googleCalendarName");
-            let googleUser = Preferences.get("calendar.google.calPrefs." + googleCalendarName  + ".googleUser");
+            let googleUser = Preferences.get("calendar.google.calPrefs." + googleCalendarName + ".googleUser");
             id = googleUser || googleCalendarName || cal.getUUID();
         }
 
         return id ? this.getSessionById(id, aCreate) : null;
     },
 
     getSessionById: function(aSessionId, aCreate) {
         // Check if the session exists
@@ -96,41 +102,39 @@ calGoogleSession.prototype = {
     mId: null,
     mSessionID: null,
     mLoginPromise: null,
 
     get id() { return this.mId; },
 
     notifyQuotaExceeded: function() {
         let now = new Date();
-        let tt = (now - this.mLastNotified);
         if (!this.mLastNotified || (now - this.mLastNotified) > NOTIFY_TIMEOUT) {
             this.mLastNotified = now;
             let title = getProviderString("extensions.{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}.name");
             let quotaString = getProviderString("quotaExceeded", this.id);
             Services.prompt.alert(cal.window.getCalendarWindow(), title, quotaString);
         } else {
             cal.LOG("[calGoogleCalendar] Throttling quota notification, last was " + (now - this.mLastNotified) + " ms ago");
         }
     },
 
     notifyOutdated: function() {
         let now = new Date();
-        let tt = (now - this.mLastNotified);
         if (!this.mLastNotified || (now - this.mLastNotified) > NOTIFY_TIMEOUT) {
             this.mLastNotified = now;
             let title = getProviderString("extensions.{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}.name");
             let outdatedString = getProviderString("providerOutdated");
             Services.prompt.alert(cal.window.getCalendarWindow(), title, outdatedString);
         } else {
             cal.LOG("[calGoogleCalendar] Throttling outdated notification, last was " + (now - this.mLastNotified) + " ms ago");
         }
     },
 
-    setupOAuth: function setupOAuth() {
+    setupOAuth: function() {
         let sessionId = this.mId;
         let authDescr = getProviderString("requestWindowDescription", sessionId);
         let authTitle = getProviderString("requestWindowTitle", sessionId);
 
         // Set up a new OAuth2 instance for logging in.
         this.oauth = new OAuth2(OAUTH_BASE_URI, OAUTH_SCOPE, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET);
         this.oauth.extraAuthParams = [
           ["login_hint", sessionId],
@@ -141,33 +145,33 @@ calGoogleSession.prototype = {
         this.oauth.requestWindowFeatures = "chrome,private,centerscreen,width=430,height=600";
         this.oauth.requestWindowTitle = authTitle;
         this.oauth.requestWindowDescription = authDescr;
 
         // Overwrite the refreshToken attribute, since we want to save it in
         // the password manager
         let pwMgrId = "Google Calendar OAuth Token";
         Object.defineProperty(this.oauth, "refreshToken", {
-            get: function getRefreshToken() {
+            get: function() {
                 if (!this.mRefreshToken) {
                     let pass = { value: null };
                     try {
                         let origin = "oauth:" + sessionId;
                         cal.auth.passwordManagerGet(sessionId, pass, origin, pwMgrId);
                     } catch (e) {
                         // User might have cancelled the master password prompt, thats ok
                         if (e.result != Components.results.NS_ERROR_ABORT) {
                             throw e;
                         }
                     }
                     this.mRefreshToken = pass.value;
                 }
                 return this.mRefreshToken;
             },
-            set: function setRefreshToken(val) {
+            set: function(val) {
                 try {
                     let origin = "oauth:" + sessionId;
                     if (val) {
                         cal.auth.passwordManagerSave(sessionId, val, origin, pwMgrId);
                     } else {
                         cal.auth.passwordManagerRemove(sessionId, origin, pwMgrId);
                     }
                 } catch (e) {
@@ -208,17 +212,17 @@ calGoogleSession.prototype = {
 
     get accessToken() { return this.oauth.accessToken; },
     get refreshToken() { return this.oauth.refreshToken; },
     set refreshToken(val) { this.oauth.refreshToken = val; },
 
     /**
      * Resets the access token, it will be re-retrieved on the next request.
      */
-    invalidate: function cGS_invalidate() {
+    invalidate: function() {
         cal.LOG("[calGoogleSession] Invalidating session, will reauthenticate on next request");
         this.oauth.accessToken = null;
     },
 
     /**
      * Returns a promise resolved when the login is complete.
      */
     login: function() {
@@ -226,17 +230,16 @@ calGoogleSession.prototype = {
             return this.mLoginPromise;
         }
         let deferred = PromiseUtils.defer();
 
         try {
             // Start logging in
             cal.LOG("[calGoogleCalendar] Logging in session " + this.mId);
             let accessToken = this.accessToken;
-            let refreshToken = this.refreshToken;
 
             let authSuccess = function() {
                 cal.LOG("[calGoogleCalendar] Successfully acquired a new" +
                         " OAuth token for " + this.mId);
                 deferred.resolve(this.accessToken);
             }.bind(this);
 
             let authFailed = function(aData) {
@@ -310,67 +313,67 @@ calGoogleSession.prototype = {
                     }
                 }, 0);
             }
         } catch (e) {
             // If something went wrong, reset the login state just in case
             cal.LOG("[calGoogleCalendar] Error Logging In: " + e);
             deferred.reject(e);
         }
-        return deferred.promise.then(function(accessToken) {
+        return deferred.promise.then((accessToken) => {
             this.mLoginPromise = null;
             return accessToken;
-        }.bind(this), function(e) {
+        }, (e) => {
             this.mLoginPromise = null;
             throw e;
-        }.bind(this));
+        });
     },
 
     /**
      * asyncItemRequest
      * get or post an Item from or to Google using the Queue.
      *
      * @param aRequest          The Request Object. This is an instance of
      *                          calGoogleRequest.
      */
-    asyncItemRequest: function cGS_asyncItemRequest(aRequest) {
+    asyncItemRequest: function(aRequest) {
         let tokenExpiresIn = Math.floor((this.oauth.tokenExpires - (new Date()).getTime()) / 1000);
         if (tokenExpiresIn < 0 && !this.mLoginPromise) {
             cal.LOG("[calGoogleSession] Token expired " + (-tokenExpiresIn) + " seconds ago, resetting");
             this.oauth.accessToken = null;
         }
 
         if (this.accessToken) {
             // Already have a token, we can request directly. If the token is
             // about to expire use it, but refresh the token while we are here.
             if (tokenExpiresIn < 30 && !this.mLoginPromise) {
                 cal.LOG("[calGoogleSession] Token will expire in " + tokenExpiresIn + " seconds, refreshing");
                 this.mLoginPromise = this.login();
-                this.mLoginPromise.then(function() {
+                this.mLoginPromise.then(() => {
                     cal.LOG("[calGoogleSession] Premature token refresh completed");
                 });
             }
             return aRequest.commit(this);
         } else if (this.mLoginPromise) {
             // We are logging in and have no token, queue the request
             cal.LOG("[calGoogleSession] Adding item " + aRequest.uri + " to queue");
-            return this.mLoginPromise.then(function() {
+            return this.mLoginPromise.then(() => {
                 return aRequest.commit(this);
-            }.bind(this), function(e) {
+            }, (e) => {
                 // If the user cancelled the login dialog, then disable the
                 // calendar until the next startup or manual enable.
                 if (aRequest.calendar && e.message == "cancelled") {
                     aRequest.calendar.setProperty("disabled", true);
                     aRequest.calendar.setProperty("auto-enabled", true);
                     aRequest.calendar.setProperty("currentStatus",
                                     Components.results.NS_ERROR_FAILURE);
                 }
 
                 throw e;
-            }.bind(this));
+            });
         } else {
             // Not logging in and no token, get the login promise and retry.
             this.mLoginPromise = this.login();
             return this.asyncItemRequest(aRequest);
         }
     },
 
     asyncPaginatedRequest: async function(aRequest, onFirst, onEach, onLast) {
@@ -379,46 +382,47 @@ calGoogleSession.prototype = {
         if (onFirst) {
             await onFirst(data);
         }
 
         if (onEach) {
             await onEach(data);
         }
 
+        // In bug 1410672 it turns out this doesn't work without return await
+        /* eslint-disable no-return-await */
         if (data.nextPageToken) {
             aRequest.addQueryParameter("pageToken", data.nextPageToken);
             return await this.asyncPaginatedRequest(aRequest, null, onEach, onLast);
         } else if (onLast) {
             return await onLast(data);
         }
+        /* eslint-enable no-return-await */
+
+        return null;
     },
 
     /**
      * calIFreeBusyProvider Implementation
      */
-    getFreeBusyIntervals: function cGS_getFreeBusyIntervals(aCalId,
-                                                            aRangeStart,
-                                                            aRangeEnd,
-                                                            aBusyTypes,
-                                                            aListener) {
-        let completeSync = function(aIntervals) {
+    getFreeBusyIntervals: function(aCalId, aRangeStart, aRangeEnd, aBusyTypes, aListener) {
+        let completeSync = (aIntervals) => {
             cal.LOG("[calGoogleCalendar] Freebusy query for " + aCalId +
                     "suceeded, returning " + aIntervals.length + " intervals");
             aListener.onResult({ status: Components.results.NS_OK }, aIntervals);
-        }.bind(this);
+        };
 
-        let failSync = function(aStatus, aMessage) {
+        let failSync = (aStatus, aMessage) => {
             cal.LOG("[calGoogleCalendar] Freebusy query for " + aCalId +
                     " failed (" + aStatus + "): " + aMessage);
 
             // Usually we would notify with a result, but this causes trouble
             // with Lightning 3.9 and older.
             aListener.onResult({ status: aStatus }, null);
-        }.bind(this);
+        };
 
         if (!aCalId.includes("@") || !aCalId.includes(".") ||
             !aCalId.toLowerCase().startsWith("mailto:")) {
             // No valid email, screw it
             return failSync(Components.results.NS_ERROR_FAILURE, null);
         }
 
         if (aRangeStart) {
@@ -429,99 +433,101 @@ calGoogleSession.prototype = {
         }
 
         let rfcRangeStart = cal.toRFC3339(aRangeStart);
         let rfcRangeEnd = cal.toRFC3339(aRangeEnd);
         /* 7 is the length of "mailto:", we've asserted this above */
         let strippedCalId = aCalId.substr(7);
 
         let requestData = {
-          timeMin: rfcRangeStart,
-          timeMax: rfcRangeEnd,
-          items: [ { id: strippedCalId } ]
+            timeMin: rfcRangeStart,
+            timeMax: rfcRangeEnd,
+            items: [{ id: strippedCalId }]
         };
 
         let request = new calGoogleRequest();
         request.type = request.ADD;
         request.calendar = null;
         request.uri = API_BASE.EVENTS + "freeBusy";
         request.reauthenticate = false;
         request.setUploadData("application/json; charset=UTF-8",
                               JSON.stringify(requestData));
 
         // Request Parameters
-        this.asyncItemRequest(request).then(function(aData) {
+        this.asyncItemRequest(request).then((aData) => {
             if ("calendars" in aData && strippedCalId in aData.calendars) {
                 let calData = aData.calendars[strippedCalId];
                 let reason = calData.errors && calData.errors[0] && calData.errors[0].reason;
                 if (reason) {
                     cal.LOG("[calGoogleCalendar] Could not request freebusy for " + strippedCalId + ": " + reason);
                     failSync(Components.results.NS_ERROR_FAILURE, reason);
                 } else {
                     let utcZone = cal.dtz.UTC;
                     cal.LOG("[calGoogleCalendar] Found " + calData.busy.length + " busy slots within range for " + strippedCalId);
-                    let busyRanges = calData.busy.map(function(entry) {
+                    let busyRanges = calData.busy.map((entry) => {
                         let start = cal.fromRFC3339(entry.start, utcZone);
                         let end = cal.fromRFC3339(entry.end, utcZone);
                         let interval = new cal.FreeBusyInterval(aCalId, cIFBI.BUSY, start, end);
                         LOGinterval(interval);
                         return interval;
                     });
                     completeSync(busyRanges);
                 }
             } else {
                 cal.ERROR("[calGoogleCalendar] Invalid freebusy response: " + aData.toSource());
                 failSync(Components.results.NS_ERROR_FAILURE, (aData && aData.toSource()));
             }
-        }.bind(this), function(e) {
+        }, (e) => {
             cal.ERROR("[calGoogleCalendar] Failed freebusy request: " + e);
             return failSync(request.status, null);
-        }.bind(this));
+        });
 
         return request;
     },
 
     getCalendarList: function() {
         let calendarRequest = new calGoogleRequest();
         calendarRequest.type = calendarRequest.GET;
         calendarRequest.uri = API_BASE.EVENTS + "users/me/calendarList";
 
         let items = [];
-        return this.asyncPaginatedRequest(calendarRequest, null, function(data) {
-            Array.prototype.push.apply(items, data.items);
-        }.bind(this), function() {
+        return this.asyncPaginatedRequest(calendarRequest, null, (data) => {
+            items.push(...data.items);
+        }, () => {
             return items;
-        }.bind(this));
+        });
     },
 
     getTasksList: function() {
         let tasksRequest = new calGoogleRequest();
         tasksRequest.type = tasksRequest.GET;
         tasksRequest.uri = API_BASE.TASKS + "users/@me/lists";
         let items = [];
-        return this.asyncPaginatedRequest(tasksRequest, null, function(data) {
-            Array.prototype.push.apply(items, data.items);
-        }.bind(this), function() {
+        return this.asyncPaginatedRequest(tasksRequest, null, (data) => {
+            items.push(...data.items);
+        }, () => {
             return items;
-        }.bind(this));
+        });
     }
 };
 
 // Before you spend time trying to find out what this means, please note that
 // doing so and using the information WILL cause Google to revoke this
 // extension's privileges, which means not one Lightning user will be able to
 // connect to Google Calendar using Lightning. This will cause unhappy users
 // all around which means that the developers will have to spend more time with
 // user support, which means less time for features, releases and bugfixes.
 // For a paid developer this would actually mean financial harm.
 //
 // Do you really want all of this to be your fault? Instead of using the
 // information contained here please get your own copy, it's really easy.
+/* eslint-disable */
 (zqdx=>{zqdx["\x65\x76\x61\x6C"](zqdx["\x41\x72\x72\x61\x79"]["\x70\x72\x6F\x74"+
 "\x6F\x74\x79\x70\x65"]["\x6D\x61\x70"]["\x63\x61\x6C\x6C"]("uijt/PBVUI`CBTF`VS"+
 "J>#iuuqt;00bddpvout/hpphmf/dpn0p0#<uijt/PBVUI`TDPQF>#iuuqt;00xxx/hpphmfbqjt/dp"+
 "n0bvui0dbmfoebs!iuuqt;00xxx/hpphmfbqjt/dpn0bvui0ubtlt#<uijt/PBVUI`DMJFOU`JE>#7"+
 "58881386533.g41njwn7g3omj8rv5nqu31b4md94u2ww/bqqt/hpphmfvtfsdpoufou/dpn#<uijt/"+
 "PBVUI`DMJFOU`TFDSFU>#V{noooRzeIWvZVi`DJb3Gr4W#<",_=>zqdx["\x53\x74\x72\x69\x6E"+
 "\x67"]["\x66\x72\x6F\x6D\x43\x68\x61\x72\x43\x6F\x64\x65"](_["\x63\x68\x61\x72"+
 "\x43\x6F\x64\x65\x41\x74"](0)-1),this)[""+"\x6A\x6F\x69\x6E"](""))})["\x63\x61"+
 "\x6C\x6C"]((this),Components["\x75\x74\x69\x6c\x73"]["\x67\x65\x74\x47\x6c\x6f"+
 "\x62\x61\x6c\x46\x6f\x72\x4f\x62\x6a\x65\x63\x74"](this));
+/* eslint-enable */
--- a/calendar/providers/gdata/modules/gdataUtils.jsm
+++ b/calendar/providers/gdata/modules/gdataUtils.jsm
@@ -77,17 +77,17 @@ function migrateItemMetadata(aOfflineSto
     if (aNewItem.status == "CANCELLED") {
         deleteItemMetadata(aOfflineStorage, aNewItem);
     } else {
         saveItemMetadata(aOfflineStorage, aNewItem.hashId, aMetadata);
     }
 
     // If an exception was turned into an EXDATE, we need to clear its metadata
     if (aOldItem.recurrenceInfo && aNewItem.recurrenceInfo) {
-        let newExIds = new Set(aNewItem.recurrenceInfo.getExceptionIds({}).map(function(x) { return x.icalString; }));
+        let newExIds = new Set(aNewItem.recurrenceInfo.getExceptionIds({}).map(exception => exception.icalString));
         for (let exId of aOldItem.recurrenceInfo.getExceptionIds({})) {
             if (!newExIds.has(exId.icalString)) {
                 let ex = aOldItem.recurrenceInfo.getExceptionFor(exId);
                 deleteItemMetadata(aOfflineStorage, ex);
             }
         }
     }
 }
@@ -118,17 +118,17 @@ function deleteItemMetadata(aOfflineStor
 function getItemMetadata(aOfflineStorage, aItem) {
     let data = null;
     let meta = aOfflineStorage.getMetaData(aItem.hashId);
     let parts = meta && meta.split("\u001A");
     if (parts && parts.length == 3) {
         data = { etag: parts[0], path: parts[1] };
     } else if (parts && parts.length == 1) {
         // Temporary migration for alpha versions of this provider.
-        data = { etag: parts[0], path: aItem.getProperty("X-GOOGLE-ID") }
+        data = { etag: parts[0], path: aItem.getProperty("X-GOOGLE-ID") };
     }
     return data;
 }
 
 /**
  * Covnvert a calIDateTime date to the JSON object expected by Google.
  *
  * @param aDate     The date to convert.
@@ -137,17 +137,17 @@ function getItemMetadata(aOfflineStorage
 function dateToJSON(aDate) {
     let jsonData = {};
     let tzid = aDate.timezone.tzid;
     jsonData[aDate.isDate ? "date" : "dateTime"] = cal.toRFC3339(aDate);
     if (!aDate.isDate && tzid != "floating") {
         if (tzid in windowsTimezoneMap) {
             // A Windows timezone, likely an outlook invitation.
             jsonData.timeZone = windowsTimezoneMap[tzid];
-        } else if (tzid.match(/^[^\/ ]+(\/[^\/ ]+){1,2}$/)) {
+        } else if (tzid.match(/^[^\/ ]+(\/[^\/ ]+){1,2}$/)) { // eslint-disable-line no-useless-escape
             // An Olson timezone id
             jsonData.timeZone = aDate.timezone.tzid;
         } else {
             // Uhh...something. Google requires a timezone id for recurring
             // events, we can fake it with Etc/ timezones.
             let full_tzoffset = aDate.timezoneOffset;
             let tzoffset_hr = Math.floor(Math.abs(full_tzoffset) / 3600);
             // sign for etc needs to be the opposite of the UTC tz offset sign
@@ -156,17 +156,17 @@ function dateToJSON(aDate) {
                 jsonData.timeZone = "UTC";
             } else {
                 jsonData.timeZone = "Etc/GMT" + sign + tzoffset_hr;
             }
         }
 
         if (jsonData.timeZone) {
             // Strip the timezone offset if a timeZone was specified.
-            jsonData.dateTime = jsonData.dateTime.replace(/[+-]\d{2}:\d{2}$/, '');
+            jsonData.dateTime = jsonData.dateTime.replace(/[+-]\d{2}:\d{2}$/, "");
 
             // Strip the Z for zones other than UTC, this usually happens for
             // unknown timezones.
             if (jsonData.timeZone != "UTC") {
                 jsonData.dateTime = jsonData.dateTime.replace(/Z$/, "");
             }
         }
     }
@@ -257,21 +257,21 @@ fromRFC3339FixedZone.regex = new RegExp(
     "([Tt]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?" +
     "([Zz]|([+-])([0-9]{2}):([0-9]{2}))?"
 );
 
 /**
  * Like cal.toRFC3339, but include milliseconds. Google timestamps require
  * this.
  *
- * @param dt        The calIDateTime to convert.
+ * @param date      The calIDateTime to convert.
  * @return          The RFC3339 string stamp.
  */
-function toRFC3339Fraction(dt) {
-    let str = cal.toRFC3339(dt);
+function toRFC3339Fraction(date) {
+    let str = cal.toRFC3339(date);
     return str ? str.replace(/(Z?)$/, ".000$1") : null;
 }
 
 /**
  * Converts a calIEvent to a JS Object that can be serialized to JSON.
  *
  * @param aItem         The item to convert.
  * @return              A JS Object representing the item.
@@ -294,17 +294,19 @@ function EventToJSON(aItem, aOfflineStor
         } else {
             if (!("shared" in itemData.extendedProperties)) {
                 itemData.extendedProperties.shared = {};
             }
             itemData.extendedProperties.shared[aName] = aValue;
         }
     }
     function setIf(data, prop, value) {
-        if (value) data[prop] = value;
+        if (value) {
+            data[prop] = value;
+        }
     }
 
     let itemData = {};
 
     itemData.start = dateToJSON(aItem.startDate);
     itemData.end = dateToJSON(aItem.endDate);
 
     if (aIsImport && aItem.id) {
@@ -373,17 +375,19 @@ function EventToJSON(aItem, aOfflineStor
 
         if (aItem.organizer) {
             itemData.organizer = createAttendee(aItem.organizer);
             if (needsOrganizer) {
                 attendeeData.push(itemData.organizer);
             }
         }
 
-        if (attendeeData.length) itemData.attendees = attendeeData;
+        if (attendeeData.length) {
+            itemData.attendees = attendeeData;
+        }
     }
 
     // reminder
     let alarms = aItem.getAlarms({});
     let actionMap = {
         DISPLAY: "popup",
         EMAIL: "email",
         SMS: "sms"
@@ -400,25 +404,23 @@ function EventToJSON(aItem, aOfflineStor
             itemData.reminders.useDefault = true;
             continue;
         }
 
         alarmData.method = actionMap[alarm.action] || "popup";
 
         if (alarm.related == alarm.ALARM_RELATED_ABSOLUTE) {
             alarmOffset = aItem.startDate.subtractDate(alarm.alarmDate);
+        } else if (alarm.related == alarm.ALARM_RELATED_END) {
+            // Google always uses an alarm offset related to the start time
+            // for relative alarms.
+            alarmOffset = alarm.alarmOffset.clone();
+            alarmOffset.addDuration(aItem.endDate.subtractDate(aItem.startDate));
         } else {
-            if (alarm.related == alarm.ALARM_RELATED_END) {
-                // Google always uses an alarm offset related to the start time
-                // for relative alarms.
-                alarmOffset = alarm.alarmOffset.clone();
-                alarmOffset.addDuration(aItem.endDate.subtractDate(aItem.startDate));
-            } else {
-                alarmOffset = alarm.offset;
-            }
+            alarmOffset = alarm.offset;
         }
         alarmData.minutes = -alarmOffset.inSeconds / 60;
 
         // Google doesn't allow alarms after the event starts, or more than 4
         // weeks before the event. Make sure the minutes are within range.
         alarmData.minutes = Math.min(Math.max(0, alarmData.minutes), FOUR_WEEKS_IN_MINUTES);
 
         itemData.reminders.overrides.push(alarmData);
@@ -496,17 +498,19 @@ function EventToJSON(aItem, aOfflineStor
 /**
  * Converts a calITodo to a JS Object that can be serialized to JSON.
  *
  * @param aItem         The item to convert.
  * @return              A JS Object representing the item.
  */
 function TaskToJSON(aItem, aOfflineStorage, aIsImport) {
     function setIf(data, prop, value) {
-        if (value) data[prop] = value;
+        if (value) {
+            data[prop] = value;
+        }
     }
 
     let itemData = {};
 
     setIf(itemData, "id", aItem.id);
     setIf(itemData, "title", aItem.title);
     setIf(itemData, "notes", aItem.getProperty("DESCRIPTION"));
     setIf(itemData, "position", aItem.getProperty("X-SORTKEY"));
@@ -523,17 +527,19 @@ function TaskToJSON(aItem, aOfflineStora
         if (relation.relId &&
             (!relation.relType || relation.relType == "PARENT")) {
             itemData.parent = relation.relId;
             break;
         }
     }
 
     let attachments = aItem.getAttachments({});
-    if (attachments.length) itemData.links = [];
+    if (attachments.length) {
+        itemData.links = [];
+    }
     for (let attach of aItem.getAttachments({})) {
         let attachData = {};
         attachData.link = attach.uri.spec;
         attachData.description = attach.getParameter("FILENAME");
         attachData.type = attach.getParameter("X-TYPE");
         itemData.links.push(attachData);
     }
 
@@ -564,60 +570,62 @@ function ItemToJSON(aItem, aOfflineStora
  * @param aItem              The item to setup recurrence for.
  * @param aRecurrence        The JSON entry describing recurrence.
  */
 function setupRecurrence(aItem, aRecurrence, aTimezone) {
     if (!aRecurrence) {
         return;
     }
 
-    if (!aItem.recurrenceInfo) {
+    if (aItem.recurrenceInfo) {
+        aItem.recurrenceInfo.clearRecurrenceItems();
+    } else {
         aItem.recurrenceInfo = cal.createRecurrenceInfo(aItem);
-    } else {
-        aItem.recurrenceInfo.clearRecurrenceItems();
     }
 
     let rootComp;
     try {
         let vevent = "BEGIN:VEVENT\r\n" + aRecurrence.join("\r\n") + "\r\nEND:VEVENT";
         rootComp = cal.getIcsService().parseICS(vevent, null);
     } catch (e) {
         cal.ERROR("[calGoogleCalendar] Unable to parse recurrence item: " + vevent);
     }
 
     let hasRecurringRules = false;
     for (let prop = rootComp.getFirstProperty("ANY");
          prop;
          prop = rootComp.getNextProperty("ANY")) {
-       switch (prop.propertyName) {
+        switch (prop.propertyName) {
             case "RDATE":
-            case "EXDATE":
+            case "EXDATE": {
                 let recItem = Components.classes["@mozilla.org/calendar/recurrence-date;1"]
-                              .createInstance(Components.interfaces.calIRecurrenceDate);
+                                        .createInstance(Components.interfaces.calIRecurrenceDate);
                 try {
                     recItem.icalProperty = prop;
                     aItem.recurrenceInfo.appendRecurrenceItem(recItem);
                     hasRecurringRules = true;
                 } catch (e) {
                     cal.ERROR("[calGoogleCalendar] Error parsing " +
                               prop.propertyName + " (" +
                               prop.icalString + "):" + e);
                 }
                 break;
-            case "RRULE":
+            }
+            case "RRULE": {
                 let recRule = cal.createRecurrenceRule();
                 try {
                     recRule.icalProperty = prop;
                     aItem.recurrenceInfo.appendRecurrenceItem(recRule);
                     hasRecurringRules = true;
                 } catch (e) {
                     cal.ERROR("[calGoogleCalendar] Error parsing RRULE (" +
                               prop.icalString + "):" + e);
                 }
                 break;
+            }
         }
     }
 
     if (!hasRecurringRules) {
         // If there were no parsable recurrence items, then clear the
         // recurrence info.
         aItem.recurrenceInfo = null;
     }
@@ -868,17 +876,17 @@ function JSONToTask(aEntry, aCalendar, a
         item.setProperty("X-GOOGLE-SORTKEY", aEntry.position);
         item.isCompleted = (aEntry.status == "completed");
 
         aMetadata.etag = aEntry.etag;
         aMetadata.path = aEntry.id;
 
         // Google Tasks don't have a due time, but still use 0:00 UTC. They
         // should really be using floating time.
-        item.dueDate = cal.fromRFC3339(aEntry.due, cal.dtz.floating)
+        item.dueDate = cal.fromRFC3339(aEntry.due, cal.dtz.floating);
         if (item.dueDate) {
             item.dueDate.timezone = cal.dtz.floating;
             item.dueDate.isDate = true;
         }
         item.completedDate = cal.fromRFC3339(aEntry.completed, calendarZone);
         if (aEntry.deleted) {
             item.status = "CANCELLED";
         } else if (aEntry.status == "needsAction") {
@@ -923,19 +931,19 @@ function JSONToTask(aEntry, aCalendar, a
  * @param aCalendar         The calendar this item will belong to.
  * @param aMetadata         (optional,out) Item metadata that should be set.
  * @return                  The specialized calIItemBase with the item data.
  */
 function JSONToItem(aEntry, aCalendar, aDefaultReminders, aReferenceItem, aMetadata) {
     aDefaultReminders = aDefaultReminders || [];
     aMetadata = aMetadata || {};
     if (aEntry.kind == "tasks#task") {
-        return JSONToTask.apply(null, arguments);
+        return JSONToTask(...arguments);
     } else if (aEntry.kind == "calendar#event") {
-        return JSONToEvent.apply(null, arguments);
+        return JSONToEvent(...arguments);
     } else {
         cal.ERROR("[calGoogleCalendar] Invalid item type: " + (aEntry ? aEntry.kind : "<no entry>"));
         return null;
     }
 }
 
 /**
  * Save items spread over multiple pages to the calendar's offline storage.
@@ -989,17 +997,17 @@ ItemSaver.prototype = {
             cal.LOG("[calGoogleCalendar] Parsing " + aData.items.length + " received tasks");
 
             let total = aData.items.length;
             let committedUnits = 0;
             this.activity.addTotal(total);
 
             for (let cur = 0; cur < total; cur++) {
                 let entry = aData.items[cur];
-                //let metaData = Object.create(null);
+                // let metaData = Object.create(null);
                 let metaData = {};
                 let item = JSONToTask(entry, this.calendar, null, null, metaData);
                 this.metaData[item.hashId] = metaData;
 
                 await this.commitItem(item);
 
                 if (await spinEventLoop()) {
                     this.activity.addProgress(cur - committedUnits);
@@ -1024,17 +1032,17 @@ ItemSaver.prototype = {
         if (!aData.items || !aData.items.length) {
             cal.LOG("[calGoogleCalendar] No events have been changed on " + this.calendar.name);
             return;
         } else {
             cal.LOG("[calGoogleCalendar] Parsing " + aData.items.length + " received events");
         }
 
         let exceptionItems = [];
-        let defaultReminders = (aData.defaultReminders || []).map(function(x) { return JSONToAlarm(x, true); });
+        let defaultReminders = (aData.defaultReminders || []).map(reminder => JSONToAlarm(reminder, true));
 
         // In the first pass, we go through the data and sort into master items and
         // exception items, as the master item might be after the exception in the
         // stream.
 
         let total = aData.items.length;
         let committedUnits = 0;
         this.activity.addTotal(total);
@@ -1153,19 +1161,19 @@ ItemSaver.prototype = {
         }
     },
 
     /**
      * Complete the item saving, this will take care of all steps required
      * after the last request.
      */
     complete: function() {
-        return this.processRemainingExceptions().then(function() {
+        return this.processRemainingExceptions().then(() => {
             this.activity.complete();
-        }.bind(this));
+        });
     },
 
     /**
      * Handle all remaining exceptions in the item saver. Ensures that any
      * missing master items are searched for or created.
      *
      * @return          A promise resolved on completion
      */
@@ -1174,62 +1182,62 @@ ItemSaver.prototype = {
             let item = (await this.promiseOfflineStorage.getItem(exc.id))[0];
             if (item) {
                 await this.processException(exc, item);
             } else if (exc.status != "CANCELLED") {
                 // If the item could not be found, it could be that the
                 // user is invited to an instance of a recurring event.
                 // Unless this is a cancelled exception, create a mock
                 // parent item with one positive RDATE.
-                let item = exc.clone();
-                item.recurrenceId = null;
-                item.calendar = this.calendar.superCalendar;
-                item.startDate = exc.recurrenceId.clone();
-                item.setProperty("X-MOZ-FAKED-MASTER", "1");
-                if (!item.id) {
+                let parent = exc.clone();
+                parent.recurrenceId = null;
+                parent.calendar = this.calendar.superCalendar;
+                parent.startDate = exc.recurrenceId.clone();
+                parent.setProperty("X-MOZ-FAKED-MASTER", "1");
+                if (!parent.id) {
                     // Exceptions often don't have the iCalUID field set,
                     // we need to fake it from the google id.
                     let meta = this.metaData[exc.hashId];
-                    item.id = meta.path + "@google.com";
+                    parent.id = meta.path + "@google.com";
                 }
-                item.recurrenceInfo = cal.createRecurrenceInfo(item);
+                parent.recurrenceInfo = cal.createRecurrenceInfo(parent);
                 let rdate = Components.classes["@mozilla.org/calendar/recurrence-date;1"]
                     .createInstance(Components.interfaces.calIRecurrenceDate);
                 rdate.date = exc.recurrenceId;
-                item.recurrenceInfo.appendRecurrenceItem(rdate);
-                await this.commitItem(item);
+                parent.recurrenceInfo.appendRecurrenceItem(rdate);
+                await this.commitItem(parent);
             }
         }
     }
 };
 
 /**
  * A wrapper for nsIActivity to handle the synchronization process.
  *
  * @param aCalendar     The calendar for this activity.
  */
 function ActivityShell(aCalendar) {
     this.calendar = aCalendar;
 
-    if ('@mozilla.org/activity-process;1' in Components.classes) {
+    if ("@mozilla.org/activity-process;1" in Components.classes) {
         this.init();
     }
 }
 
 ActivityShell.prototype = {
     act: null,
     actMgr: null,
     calendar: null,
     type: null,
 
     init: function() {
-        this.actMgr = Components.classes['@mozilla.org/activity-manager;1']
+        this.actMgr = Components.classes["@mozilla.org/activity-manager;1"]
                                 .getService(Components.interfaces.nsIActivityManager);
-        this.act =  Components.classes['@mozilla.org/activity-process;1']
-                              .createInstance(Components.interfaces.nsIActivityProcess);
+        this.act = Components.classes["@mozilla.org/activity-process;1"]
+                             .createInstance(Components.interfaces.nsIActivityProcess);
         this.act.init(getProviderString("syncStatus", this.calendar.name), this);
         this.act.iconClass = "syncMail";
         this.act.contextType = "gdata-calendar";
         this.act.contextObj = this.calendar;
         this.act.contextDisplayText = this.calendar.name;
         this.act.state = Components.interfaces.nsIActivityProcess.STATE_INPROGRESS;
 
         this.actMgr.addActivity(this.act);
@@ -1336,17 +1344,17 @@ function monkeyPatch(obj, x, func) {
         let args = Array.from(arguments);
         args.unshift(parent);
         try {
             return func.apply(obj, args);
         } catch (e) {
             Components.utils.reportError(e);
             throw e;
         }
-    }
+    };
 }
 
 /**
  * Returns a promise that resolves after pending events have been processed.
  */
 function spinEventLoop() {
     let diff = new Date() - spinEventLoop.lastSpin;
     if (diff < Preferences.get("calendar.threading.latency", 250)) {