Merge "ES6ify /gr-message/*"
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
index 5117328..3ab4a88 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/TestAccount.java
@@ -16,12 +16,15 @@
 
 import static java.util.stream.Collectors.toList;
 
+import com.google.common.net.InetAddresses;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.mail.Address;
 import com.jcraft.jsch.KeyPair;
 import java.io.ByteArrayOutputStream;
+import java.net.InetSocketAddress;
 import java.util.Arrays;
 import java.util.List;
+import org.apache.http.client.utils.URIBuilder;
 import org.eclipse.jgit.lib.PersonIdent;
 
 public class TestAccount {
@@ -77,12 +80,13 @@
   }
 
   public String getHttpUrl(GerritServer server) {
-    return String.format(
-        "http://%s:%s@%s:%d",
-        username,
-        httpPassword,
-        server.getHttpAddress().getAddress().getHostAddress(),
-        server.getHttpAddress().getPort());
+    InetSocketAddress addr = server.getHttpAddress();
+    return new URIBuilder()
+        .setScheme("http")
+        .setUserInfo(username, httpPassword)
+        .setHost(InetAddresses.toUriString(addr.getAddress()))
+        .setPort(addr.getPort())
+        .toString();
   }
 
   public Account.Id getId() {
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java b/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java
index 1ac42d1..624bcea 100644
--- a/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java
+++ b/gerrit-common/src/main/java/com/google/gerrit/common/IoUtil.java
@@ -56,6 +56,10 @@
   }
 
   public static void loadJARs(Collection<Path> jars) {
+    if (jars.isEmpty()) {
+      return;
+    }
+
     ClassLoader cl = IoUtil.class.getClassLoader();
     if (!(cl instanceof URLClassLoader)) {
       throw noAddURL("Not loaded by URLClassLoader", null);
diff --git a/gerrit-plugin-api/BUILD b/gerrit-plugin-api/BUILD
index ebc5619..2e768ee 100644
--- a/gerrit-plugin-api/BUILD
+++ b/gerrit-plugin-api/BUILD
@@ -19,6 +19,7 @@
     "//gerrit-extension-api:api",
     "//gerrit-gwtexpui:server",
     "//gerrit-reviewdb:server",
+    "//gerrit-server/src/main/prolog:common",
     "//lib/commons:lang",
     "//lib/commons:lang3",
     "//lib/dropwizard:dropwizard-core",
diff --git a/lib/prolog/BUILD b/lib/prolog/BUILD
index 875f135..f6b4c5f 100644
--- a/lib/prolog/BUILD
+++ b/lib/prolog/BUILD
@@ -6,6 +6,13 @@
 )
 
 java_library(
+    name = "runtime-neverlink",
+    data = ["//lib:LICENSE-prologcafe"],
+    visibility = ["//visibility:public"],
+    exports = ["@prolog_runtime//jar:neverlink"],
+)
+
+java_library(
     name = "compiler",
     data = ["//lib:LICENSE-prologcafe"],
     visibility = ["//visibility:public"],
diff --git a/lib/prolog/prolog.bzl b/lib/prolog/prolog.bzl
index cae85ad..43a8bab 100644
--- a/lib/prolog/prolog.bzl
+++ b/lib/prolog/prolog.bzl
@@ -12,14 +12,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("//tools/bzl:genrule2.bzl", "genrule2")
-
 def prolog_cafe_library(
     name,
     srcs,
     deps = [],
     **kwargs):
-  genrule2(
+  native.genrule(
     name = name + '__pl2j',
     cmd = '$(location //lib/prolog:compiler_bin) ' +
       '$$(dirname $@) $@ ' +
@@ -31,6 +29,6 @@
   native.java_library(
     name = name,
     srcs = [':' + name + '__pl2j'],
-    deps = ['//lib/prolog:runtime'] + deps,
+    deps = ['//lib/prolog:runtime-neverlink'] + deps,
     **kwargs
   )
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
index e47f14f..074e39e 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.js
@@ -33,16 +33,16 @@
       message: String,
     },
 
-    resetFocus: function() {
+    resetFocus() {
       this.$.messageInput.textarea.focus();
     },
 
-    _handleConfirmTap: function(e) {
+    _handleConfirmTap(e) {
       e.preventDefault();
       this.fire('confirm', {reason: this.message}, {bubbles: false});
     },
 
-    _handleCancelTap: function(e) {
+    _handleCancelTap(e) {
       e.preventDefault();
       this.fire('cancel', null, {bubbles: false});
     },
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
index f843ee8..b26802d 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.js
@@ -35,7 +35,7 @@
 
       _schemes: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
         computed: '_computeSchemes(change, patchNum)',
         observer: '_schemesChanged',
       },
@@ -50,7 +50,7 @@
       Gerrit.RESTClientBehavior,
     ],
 
-    focus: function() {
+    focus() {
       if (this._schemes.length) {
         this.$$('.copyToClipboard').focus();
       } else {
@@ -58,59 +58,60 @@
       }
     },
 
-    getFocusStops: function() {
-      var links = this.$$('#archives').querySelectorAll('a');
+    getFocusStops() {
+      const links = this.$$('#archives').querySelectorAll('a');
       return {
         start: this.$.closeButton,
         end: links[links.length - 1],
       };
     },
 
-    _loggedInChanged: function(loggedIn) {
+    _loggedInChanged(loggedIn) {
       if (!loggedIn) { return; }
-      this.$.restAPI.getPreferences().then(function(prefs) {
+      this.$.restAPI.getPreferences().then(prefs => {
         if (prefs.download_scheme) {
           // Note (issue 5180): normalize the download scheme with lower-case.
           this._selectedScheme = prefs.download_scheme.toLowerCase();
         }
-      }.bind(this));
+      });
     },
 
-    _computeDownloadCommands: function(change, patchNum, _selectedScheme) {
-      var commandObj;
-      for (var rev in change.revisions) {
+    _computeDownloadCommands(change, patchNum, _selectedScheme) {
+      let commandObj;
+      for (const rev in change.revisions) {
         if (change.revisions[rev]._number === patchNum &&
             change.revisions[rev].fetch.hasOwnProperty(_selectedScheme)) {
           commandObj = change.revisions[rev].fetch[_selectedScheme].commands;
           break;
         }
       }
-      var commands = [];
-      for (var title in commandObj) {
+      const commands = [];
+      for (const title in commandObj) {
+        if (!commandObj.hasOwnProperty(title)) { continue; }
         commands.push({
-          title: title,
+          title,
           command: commandObj[title],
         });
       }
       return commands;
     },
 
-    _computeZipDownloadLink: function(change, patchNum) {
+    _computeZipDownloadLink(change, patchNum) {
       return this._computeDownloadLink(change, patchNum, true);
     },
 
-    _computeZipDownloadFilename: function(change, patchNum) {
+    _computeZipDownloadFilename(change, patchNum) {
       return this._computeDownloadFilename(change, patchNum, true);
     },
 
-    _computeDownloadLink: function(change, patchNum, zip) {
+    _computeDownloadLink(change, patchNum, zip) {
       return this.changeBaseURL(change._number, patchNum) + '/patch?' +
           (zip ? 'zip' : 'download');
     },
 
-    _computeDownloadFilename: function(change, patchNum, zip) {
-      var shortRev;
-      for (var rev in change.revisions) {
+    _computeDownloadFilename(change, patchNum, zip) {
+      let shortRev;
+      for (const rev in change.revisions) {
         if (change.revisions[rev]._number === patchNum) {
           shortRev = rev.substr(0, 7);
           break;
@@ -119,15 +120,15 @@
       return shortRev + '.diff.' + (zip ? 'zip' : 'base64');
     },
 
-    _computeArchiveDownloadLink: function(change, patchNum, format) {
+    _computeArchiveDownloadLink(change, patchNum, format) {
       return this.changeBaseURL(change._number, patchNum) +
           '/archive?format=' + format;
     },
 
-    _computeSchemes: function(change, patchNum) {
-      for (var rev in change.revisions) {
+    _computeSchemes(change, patchNum) {
+      for (const rev in change.revisions) {
         if (change.revisions[rev]._number === patchNum) {
-          var fetch = change.revisions[rev].fetch;
+          const fetch = change.revisions[rev].fetch;
           if (fetch) {
             return Object.keys(fetch).sort();
           }
@@ -137,47 +138,47 @@
       return [];
     },
 
-    _computePatchSetQuantity: function(revisions) {
+    _computePatchSetQuantity(revisions) {
       if (!revisions) { return 0; }
       return Object.keys(revisions).length;
     },
 
-    _computeSchemeSelected: function(scheme, selectedScheme) {
+    _computeSchemeSelected(scheme, selectedScheme) {
       return scheme === selectedScheme;
     },
 
-    _handleSchemeTap: function(e) {
+    _handleSchemeTap(e) {
       e.preventDefault();
-      var el = Polymer.dom(e).rootTarget;
+      const el = Polymer.dom(e).rootTarget;
       this._selectedScheme = el.getAttribute('data-scheme');
       if (this.loggedIn) {
         this.$.restAPI.savePreferences({download_scheme: this._selectedScheme});
       }
     },
 
-    _handleInputTap: function(e) {
+    _handleInputTap(e) {
       e.preventDefault();
       Polymer.dom(e).rootTarget.select();
     },
 
-    _handleCloseTap: function(e) {
+    _handleCloseTap(e) {
       e.preventDefault();
       this.fire('close', null, {bubbles: false});
     },
 
-    _schemesChanged: function(schemes) {
+    _schemesChanged(schemes) {
       if (schemes.length === 0) { return; }
-      if (schemes.indexOf(this._selectedScheme) === -1) {
+      if (!schemes.includes(this._selectedScheme)) {
         this._selectedScheme = schemes.sort()[0];
       }
     },
 
-    _copyToClipboard: function(e) {
+    _copyToClipboard(e) {
       e.target.parentElement.querySelector('.copyCommand').select();
       document.execCommand('copy');
       getSelection().removeAllRanges();
       e.target.textContent = 'done';
-      setTimeout(function() { e.target.textContent = 'copy'; }, 1000);
+      setTimeout(() => { e.target.textContent = 'copy'; }, 1000);
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
index 0635d6d..4a8d2d9 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_test.html
@@ -48,8 +48,8 @@
           fetch: {
             repo: {
               commands: {
-                repo: 'repo download test-project 5/1'
-              }
+                repo: 'repo download test-project 5/1',
+              },
             },
             ssh: {
               commands: {
@@ -69,8 +69,8 @@
                 'Pull':
                   'git pull ' +
                   'ssh://andybons@localhost:29418/test-project ' +
-                  'refs/changes/05/5/1'
-              }
+                  'refs/changes/05/5/1',
+              },
             },
             http: {
               commands: {
@@ -90,12 +90,12 @@
                 'Pull':
                   'git pull ' +
                   'http://andybons@localhost:8080/a/test-project ' +
-                  'refs/changes/05/5/1'
-              }
-            }
-          }
-        }
-      }
+                  'refs/changes/05/5/1',
+              },
+            },
+          },
+        },
+      },
     };
   }
 
@@ -106,74 +106,74 @@
         '34685798fe548b6d17d1e8e5edc43a26d055cc72': {
           _number: 1,
           fetch: {},
-        }
-      }
+        },
+      },
     };
   }
 
-  suite('gr-download-dialog tests with no fetch options', function() {
-    var element;
+  suite('gr-download-dialog tests with no fetch options', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       element.change = getChangeObjectNoFetch();
       element.patchNum = 1;
       element.config = {
         schemes: {
           'anonymous http': {},
-          http: {},
-          repo: {},
-          ssh: {},
+          'http': {},
+          'repo': {},
+          'ssh': {},
         },
         archives: ['tgz', 'tar', 'tbz2', 'txz'],
       };
     });
 
-    test('focuses on first download link if no copy links', function() {
+    test('focuses on first download link if no copy links', () => {
       flushAsynchronousOperations();
-      var focusStub = sinon.stub(element.$.download, 'focus');
+      const focusStub = sinon.stub(element.$.download, 'focus');
       element.focus();
       assert.isTrue(focusStub.called);
       focusStub.restore();
     });
   });
 
-  suite('gr-download-dialog tests', function() {
-    var element;
+  suite('gr-download-dialog tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       element.change = getChangeObject();
       element.patchNum = 1;
       element.config = {
         schemes: {
           'anonymous http': {},
-          http: {},
-          repo: {},
-          ssh: {},
+          'http': {},
+          'repo': {},
+          'ssh': {},
         },
         archives: ['tgz', 'tar', 'tbz2', 'txz'],
       };
     });
 
-    test('focuses on first copy link', function() {
+    test('focuses on first copy link', () => {
       flushAsynchronousOperations();
-      var focusStub = sinon.stub(element.$$('.copyToClipboard'), 'focus');
+      const focusStub = sinon.stub(element.$$('.copyToClipboard'), 'focus');
       element.focus();
       flushAsynchronousOperations();
       assert.isTrue(focusStub.called);
       focusStub.restore();
     });
 
-    test('copy to clipboard', function() {
+    test('copy to clipboard', () => {
       flushAsynchronousOperations();
-      var clipboardSpy = sinon.spy(element, '_copyToClipboard');
-      var copyBtn = element.$$('.copyToClipboard');
+      const clipboardSpy = sinon.spy(element, '_copyToClipboard');
+      const copyBtn = element.$$('.copyToClipboard');
       MockInteractions.tap(copyBtn);
       assert.isTrue(clipboardSpy.called);
     });
 
-    test('element visibility', function() {
+    test('element visibility', () => {
       assert.isFalse(element.$$('ul').hasAttribute('hidden'));
       assert.isFalse(element.$$('main').hasAttribute('hidden'));
       assert.isFalse(element.$$('.archivesContainer').hasAttribute('hidden'));
@@ -182,40 +182,40 @@
       assert.isTrue(element.$$('.archivesContainer').hasAttribute('hidden'));
     });
 
-    test('computed fields', function() {
+    test('computed fields', () => {
       assert.equal(element._computeArchiveDownloadLink(
           {_number: 123}, 2, 'tgz'),
           '/changes/123/revisions/2/archive?format=tgz');
     });
 
-    test('close event', function(done) {
-      element.addEventListener('close', function() {
+    test('close event', done => {
+      element.addEventListener('close', () => {
         done();
       });
       MockInteractions.tap(element.$$('.closeButtonContainer gr-button'));
     });
 
-    test('tab selection', function() {
+    test('tab selection', () => {
       flushAsynchronousOperations();
-      var el = element.$$('[data-scheme="http"]').parentElement;
+      let el = element.$$('[data-scheme="http"]').parentElement;
       assert.isTrue(el.hasAttribute('selected'));
-      ['repo', 'ssh'].forEach(function(scheme) {
-        var el = element.$$('[data-scheme="' + scheme + '"]').parentElement;
+      for (const scheme of ['repo', 'ssh']) {
+        const el = element.$$('[data-scheme="' + scheme + '"]').parentElement;
         assert.isFalse(el.hasAttribute('selected'));
-      });
+      }
 
       MockInteractions.tap(element.$$('[data-scheme="ssh"]'));
       el = element.$$('[data-scheme="ssh"]').parentElement;
       assert.isTrue(el.hasAttribute('selected'));
-      ['http', 'repo'].forEach(function(scheme) {
-        var el = element.$$('[data-scheme="' + scheme + '"]').parentElement;
+      for (const scheme of ['http', 'repo']) {
+        const el = element.$$('[data-scheme="' + scheme + '"]').parentElement;
         assert.isFalse(el.hasAttribute('selected'));
-      });
+      }
     });
 
-    test('loads scheme from preferences w/o initial login', function(done) {
+    test('loads scheme from preferences w/o initial login', done => {
       stub('gr-rest-api-interface', {
-        getPreferences: function() {
+        getPreferences() {
           return Promise.resolve({download_scheme: 'repo'});
         },
       });
@@ -223,19 +223,19 @@
       element.loggedIn = true;
 
       assert.isTrue(element.$.restAPI.getPreferences.called);
-      element.$.restAPI.getPreferences.lastCall.returnValue.then(function() {
+      element.$.restAPI.getPreferences.lastCall.returnValue.then(() => {
         assert.equal(element._selectedScheme, 'repo');
         done();
       });
     });
   });
 
-  suite('gr-download-dialog tests', function() {
-    var element;
+  suite('gr-download-dialog tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        getPreferences: function() {
+        getPreferences() {
           return Promise.resolve({download_scheme: 'repo'});
         },
       });
@@ -246,28 +246,28 @@
       element.config = {
         schemes: {
           'anonymous http': {},
-          http: {},
-          repo: {},
-          ssh: {},
+          'http': {},
+          'repo': {},
+          'ssh': {},
         },
         archives: ['tgz', 'tar', 'tbz2', 'txz'],
       };
     });
 
-    test('loads scheme from preferences', function(done) {
-      element.$.restAPI.getPreferences.lastCall.returnValue.then(function() {
+    test('loads scheme from preferences', done => {
+      element.$.restAPI.getPreferences.lastCall.returnValue.then(() => {
         assert.equal(element._selectedScheme, 'repo');
         done();
       });
     });
 
-    test('saves scheme to preferences', function() {
-      var savePrefsStub = sinon.stub(element.$.restAPI, 'savePreferences',
-          function() { return Promise.resolve(); });
+    test('saves scheme to preferences', () => {
+      const savePrefsStub = sinon.stub(element.$.restAPI, 'savePreferences',
+          () => { return Promise.resolve(); });
 
       Polymer.dom.flush();
 
-      var firstSchemeButton = element.$$('li gr-button[data-scheme]');
+      const firstSchemeButton = element.$$('li gr-button[data-scheme]');
 
       MockInteractions.tap(firstSchemeButton);
 
@@ -277,9 +277,9 @@
     });
   });
 
-  test('normalize scheme from preferences', function(done) {
+  test('normalize scheme from preferences', done => {
     stub('gr-rest-api-interface', {
-      getPreferences: function() {
+      getPreferences() {
         return Promise.resolve({download_scheme: 'REPO'});
       },
     });
@@ -287,10 +287,10 @@
     element.change = getChangeObject();
     element.patchNum = 1;
     element.config = {
-      schemes: {'anonymous http': {}, http: {}, repo: {}, ssh: {}},
+      schemes: {'anonymous http': {}, 'http': {}, 'repo': {}, 'ssh': {}},
       archives: ['tgz', 'tar', 'tbz2', 'txz'],
     };
-    element.$.restAPI.getPreferences.lastCall.returnValue.then(function() {
+    element.$.restAPI.getPreferences.lastCall.returnValue.then(() => {
       assert.equal(element._selectedScheme, 'repo');
       done();
     });
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
index 8501b20..fe35c7f 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
@@ -41,23 +41,23 @@
       },
       _relatedResponse: {
         type: Object,
-        value: function() { return {changes: []}; },
+        value() { return {changes: []}; },
       },
       _submittedTogether: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       _conflicts: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       _cherryPicks: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       _sameTopic: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
     },
 
@@ -71,53 +71,52 @@
           '_conflicts, _cherryPicks, _sameTopic)',
     ],
 
-    clear: function() {
+    clear() {
       this.loading = true;
       this.hidden = true;
     },
 
-    reload: function() {
+    reload() {
       if (!this.change || !this.patchNum) {
         return Promise.resolve();
       }
       this.loading = true;
-      var promises = [
-        this._getRelatedChanges().then(function(response) {
+      const promises = [
+        this._getRelatedChanges().then(response => {
           this._relatedResponse = response;
 
           this.hasParent = this._calculateHasParent(this.change.change_id,
               response.changes);
-
-        }.bind(this)),
-        this._getSubmittedTogether().then(function(response) {
+        }),
+        this._getSubmittedTogether().then(response => {
           this._submittedTogether = response;
-        }.bind(this)),
-        this._getCherryPicks().then(function(response) {
+        }),
+        this._getCherryPicks().then(response => {
           this._cherryPicks = response;
-        }.bind(this)),
+        }),
       ];
 
       // Get conflicts if change is open and is mergeable.
       if (this.changeIsOpen(this.change.status) && this.change.mergeable) {
-        promises.push(this._getConflicts().then(function(response) {
+        promises.push(this._getConflicts().then(response => {
           this._conflicts = response;
-        }.bind(this)));
+        }));
       }
 
-      promises.push(this._getServerConfig().then(function(config) {
+      promises.push(this._getServerConfig().then(config => {
         if (this.change.topic && !config.change.submit_whole_topic) {
-          return this._getChangesWithSameTopic().then(function(response) {
+          return this._getChangesWithSameTopic().then(response => {
             this._sameTopic = response;
-          }.bind(this));
+          });
         } else {
           this._sameTopic = [];
         }
         return this._sameTopic;
-      }.bind(this)));
+      }));
 
-      return Promise.all(promises).then(function() {
+      return Promise.all(promises).then(() => {
         this.loading = false;
-      }.bind(this));
+      });
     },
 
     /**
@@ -128,62 +127,62 @@
      * @param  {Array} relatedChanges
      * @return {Boolean}
      */
-    _calculateHasParent: function(currentChangeId, relatedChanges) {
+    _calculateHasParent(currentChangeId, relatedChanges) {
       return relatedChanges.length > 0 &&
           relatedChanges[relatedChanges.length - 1].change_id !==
           currentChangeId;
     },
 
-    _getRelatedChanges: function() {
+    _getRelatedChanges() {
       return this.$.restAPI.getRelatedChanges(this.change._number,
           this.patchNum);
     },
 
-    _getSubmittedTogether: function() {
+    _getSubmittedTogether() {
       return this.$.restAPI.getChangesSubmittedTogether(this.change._number);
     },
 
-    _getServerConfig: function() {
+    _getServerConfig() {
       return this.$.restAPI.getConfig();
     },
 
-    _getConflicts: function() {
+    _getConflicts() {
       return this.$.restAPI.getChangeConflicts(this.change._number);
     },
 
-    _getCherryPicks: function() {
+    _getCherryPicks() {
       return this.$.restAPI.getChangeCherryPicks(this.change.project,
           this.change.change_id, this.change._number);
     },
 
-    _getChangesWithSameTopic: function() {
+    _getChangesWithSameTopic() {
       return this.$.restAPI.getChangesWithSameTopic(this.change.topic);
     },
 
-    _computeChangeURL: function(changeNum, patchNum) {
-      var urlStr = this.getBaseUrl() + '/c/' + changeNum;
+    _computeChangeURL(changeNum, patchNum) {
+      let urlStr = this.getBaseUrl() + '/c/' + changeNum;
       if (patchNum != null) {
         urlStr += '/' + patchNum;
       }
       return urlStr;
     },
 
-    _computeChangeContainerClass: function(currentChange, relatedChange) {
-      var classes = ['changeContainer'];
+    _computeChangeContainerClass(currentChange, relatedChange) {
+      const classes = ['changeContainer'];
       if (relatedChange.change_id === currentChange.change_id) {
         classes.push('thisChange');
       }
       return classes.join(' ');
     },
 
-    _computeLinkClass: function(change) {
+    _computeLinkClass(change) {
       if (change.status == this.ChangeStatus.ABANDONED) {
         return 'strikethrough';
       }
     },
 
-    _computeChangeStatusClass: function(change) {
-      var classes = ['status'];
+    _computeChangeStatusClass(change) {
+      const classes = ['status'];
       if (change._revision_number != change._current_revision_number) {
         classes.push('notCurrent');
       } else if (this._isIndirectAncestor(change)) {
@@ -196,7 +195,7 @@
       return classes.join(' ');
     },
 
-    _computeChangeStatus: function(change) {
+    _computeChangeStatus(change) {
       switch (change.status) {
         case this.ChangeStatus.MERGED:
           return 'Merged';
@@ -215,16 +214,16 @@
       return '';
     },
 
-    _resultsChanged: function(related, submittedTogether, conflicts,
+    _resultsChanged(related, submittedTogether, conflicts,
         cherryPicks, sameTopic) {
-      var results = [
+      const results = [
         related,
         submittedTogether,
         conflicts,
         cherryPicks,
         sameTopic,
       ];
-      for (var i = 0; i < results.length; i++) {
+      for (let i = 0; i < results.length; i++) {
         if (results[i].length > 0) {
           this.hidden = false;
           this.fire('update', null, {bubbles: false});
@@ -234,23 +233,23 @@
       this.hidden = true;
     },
 
-    _isIndirectAncestor: function(change) {
-      return this._connectedRevisions.indexOf(change.commit.commit) == -1;
+    _isIndirectAncestor(change) {
+      return !this._connectedRevisions.includes(change.commit.commit);
     },
 
-    _computeConnectedRevisions: function(change, patchNum, relatedChanges) {
-      var connected = [];
-      var changeRevision;
-      for (var rev in change.revisions) {
+    _computeConnectedRevisions(change, patchNum, relatedChanges) {
+      const connected = [];
+      let changeRevision;
+      for (const rev in change.revisions) {
         if (change.revisions[rev]._number == patchNum) {
           changeRevision = rev;
         }
       }
-      var commits = relatedChanges.map(function(c) { return c.commit; });
-      var pos = commits.length - 1;
+      const commits = relatedChanges.map(c => { return c.commit; });
+      let pos = commits.length - 1;
 
       while (pos >= 0) {
-        var commit = commits[pos].commit;
+        const commit = commits[pos].commit;
         connected.push(commit);
         if (commit == changeRevision) {
           break;
@@ -258,8 +257,8 @@
         pos--;
       }
       while (pos >= 0) {
-        for (var i = 0; i < commits[pos].parents.length; i++) {
-          if (connected.indexOf(commits[pos].parents[i].commit) != -1) {
+        for (let i = 0; i < commits[pos].parents.length; i++) {
+          if (connected.includes(commits[pos].parents[i].commit)) {
             connected.push(commits[pos].commit);
             break;
           }
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
index 171f758..4a25405 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.html
@@ -33,21 +33,21 @@
 </test-fixture>
 
 <script>
-  suite('gr-related-changes-list tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-related-changes-list tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('connected revisions', function() {
-      var change = {
+    test('connected revisions', () => {
+      const change = {
         revisions: {
           'e3c6d60783bfdec9ebae7dcfec4662360433449e': {
             _number: 1,
@@ -72,8 +72,8 @@
           },
         },
       };
-      var patchNum = 7;
-      var relatedChanges = [
+      let patchNum = 7;
+      let relatedChanges = [
         {
           commit: {
             commit: '2cebeedfb1e80f4b872d0a13ade529e70652c0c8',
@@ -136,7 +136,7 @@
         },
       ];
 
-      var connectedChanges =
+      let connectedChanges =
           element._computeConnectedRevisions(change, patchNum, relatedChanges);
       assert.deepEqual(connectedChanges, [
         '613bc4f81741a559c6667ac08d71dcc3348f73ce',
@@ -222,9 +222,9 @@
       ]);
     });
 
-    test('_computeChangeContainerClass', function() {
-      var change1 = {change_id: 123};
-      var change2 = {change_id: 456};
+    test('_computeChangeContainerClass', () => {
+      const change1 = {change_id: 123};
+      const change2 = {change_id: 456};
 
       assert.notEqual(element._computeChangeContainerClass(
           change1, change1).indexOf('thisChange'), -1);
@@ -232,26 +232,25 @@
           change1, change2).indexOf('thisChange'), -1);
     });
 
-    suite('get conflicts tests', function() {
-      var element;
-      var conflictsStub;
+    suite('get conflicts tests', () => {
+      let element;
+      let conflictsStub;
 
-      setup(function() {
+      setup(() => {
         element = fixture('basic');
 
-        sandbox.stub(element, '_getRelatedChanges',
-            function() {
-              return Promise.resolve({changes: []});
-            });
+        sandbox.stub(element, '_getRelatedChanges', () => {
+          return Promise.resolve({changes: []});
+        });
         sandbox.stub(element, '_getSubmittedTogether',
-            function() { return Promise.resolve(); });
+            () => { return Promise.resolve(); });
         sandbox.stub(element, '_getCherryPicks',
-            function() { return Promise.resolve(); });
+            () => { return Promise.resolve(); });
         conflictsStub = sandbox.stub(element, '_getConflicts',
-            function() { return Promise.resolve(['test data']); });
+            () => { return Promise.resolve(['test data']); });
       });
 
-      test('request conflicts if open and mergeable', function() {
+      test('request conflicts if open and mergeable', () => {
         element.patchNum = 7;
         element.change = {
           change_id: 123,
@@ -262,7 +261,7 @@
         assert.isTrue(conflictsStub.called);
       });
 
-      test('does not request conflicts if closed and mergeable', function() {
+      test('does not request conflicts if closed and mergeable', () => {
         element.patchNum = 7;
         element.change = {
           change_id: 123,
@@ -273,7 +272,7 @@
         assert.isFalse(conflictsStub.called);
       });
 
-      test('does not request conflicts if open and not mergeable', function() {
+      test('does not request conflicts if open and not mergeable', () => {
         element.patchNum = 7;
         element.change = {
           change_id: 123,
@@ -284,7 +283,7 @@
         assert.isFalse(conflictsStub.called);
       });
 
-      test('doesnt request conflicts if closed and not mergeable', function() {
+      test('doesnt request conflicts if closed and not mergeable', () => {
         element.patchNum = 7;
         element.change = {
           change_id: 123,
@@ -296,9 +295,9 @@
       });
     });
 
-    test('_calculateHasParent', function() {
-      var changeId = 123;
-      var relatedChanges = [];
+    test('_calculateHasParent', () => {
+      const changeId = 123;
+      const relatedChanges = [];
 
       assert.equal(element._calculateHasParent(changeId, relatedChanges),
           false);
@@ -310,10 +309,9 @@
       relatedChanges.push({change_id: 234});
       assert.equal(element._calculateHasParent(changeId, relatedChanges),
           true);
-
     });
 
-    test('clear hides', function() {
+    test('clear hides', () => {
       element.loading = false;
       element.hidden = false;
       element.clear();
@@ -321,8 +319,8 @@
       assert.isTrue(element.hidden);
     });
 
-    test('update fires', function() {
-      var updateHandler = sandbox.stub();
+    test('update fires', () => {
+      const updateHandler = sandbox.stub();
       element.addEventListener('update', updateHandler);
 
       element._resultsChanged([], [], [], [], []);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
index df75d52..7899fc7 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
@@ -21,7 +21,7 @@
       changeNum: String,
       comments: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
       patchForNewThreads: String,
       projectConfig: Object,
@@ -32,7 +32,7 @@
       },
       _threads: {
         type: Array,
-        value: function() { return []; },
+        value() { return []; },
       },
     },
 
@@ -40,16 +40,16 @@
       '_commentsChanged(comments.*)',
     ],
 
-    addNewThread: function(locationRange) {
+    addNewThread(locationRange) {
       this.push('_threads', {
         comments: [],
-        locationRange: locationRange,
+        locationRange,
         patchNum: this.patchForNewThreads,
       });
     },
 
-    removeThread: function(locationRange) {
-      for (var i = 0; i < this._threads.length; i++) {
+    removeThread(locationRange) {
+      for (let i = 0; i < this._threads.length; i++) {
         if (this._threads[i].locationRange === locationRange) {
           this.splice('_threads', i, 1);
           return;
@@ -57,10 +57,10 @@
       }
     },
 
-    getThreadForRange: function(rangeToCheck) {
-      var threads = [].filter.call(
+    getThreadForRange(rangeToCheck) {
+      const threads = [].filter.call(
           Polymer.dom(this.root).querySelectorAll('gr-diff-comment-thread'),
-          function(thread) {
+          thread => {
             return thread.locationRange === rangeToCheck;
           });
       if (threads.length === 1) {
@@ -68,13 +68,13 @@
       }
     },
 
-    _commentsChanged: function() {
+    _commentsChanged() {
       this._threads = this._getThreadGroups(this.comments);
     },
 
-    _sortByDate: function(threadGroups) {
+    _sortByDate(threadGroups) {
       if (!threadGroups.length) { return; }
-      return threadGroups.sort(function(a, b) {
+      return threadGroups.sort((a, b) => {
         // If a comment is a draft, it doesn't have a start_datetime yet.
         // Assume it is newer than the comment it is being compared to.
         if (!a.start_datetime) {
@@ -88,7 +88,7 @@
       });
     },
 
-    _calculateLocationRange: function(range, comment) {
+    _calculateLocationRange(range, comment) {
       return 'range-' + range.start_line + '-' +
           range.start_character + '-' +
           range.end_line + '-' +
@@ -102,15 +102,15 @@
      * This is needed for switching between side-by-side and unified views when
      * there are unsaved drafts.
      */
-    _getPatchNum: function(comment) {
+    _getPatchNum(comment) {
       return comment.patchNum || this.patchForNewThreads;
     },
 
-    _getThreadGroups: function(comments) {
-      var threadGroups = {};
+    _getThreadGroups(comments) {
+      const threadGroups = {};
 
-      comments.forEach(function(comment) {
-        var locationRange;
+      for (const comment of comments) {
+        let locationRange;
         if (!comment.range) {
           locationRange = 'line-' + comment.__commentSide;
         } else {
@@ -123,18 +123,18 @@
           threadGroups[locationRange] = {
             start_datetime: comment.updated,
             comments: [comment],
-            locationRange: locationRange,
+            locationRange,
             commentSide: comment.__commentSide,
             patchNum: this._getPatchNum(comment),
           };
         }
-      }.bind(this));
+      }
 
-      var threadGroupArr = [];
-      var threadGroupKeys = Object.keys(threadGroups);
-      threadGroupKeys.forEach(function(threadGroupKey) {
+      const threadGroupArr = [];
+      const threadGroupKeys = Object.keys(threadGroups);
+      for (const threadGroupKey of threadGroupKeys) {
         threadGroupArr.push(threadGroups[threadGroupKey]);
-      });
+      }
 
       return this._sortByDate(threadGroupArr);
     },
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
index 53a8e81..056b74f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
@@ -34,25 +34,25 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-comment-thread-group tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-diff-comment-thread-group tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
       stub('gr-rest-api-interface', {
-        getLoggedIn: function() { return Promise.resolve(false); },
+        getLoggedIn() { return Promise.resolve(false); },
       });
       element = fixture('basic');
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('_getThreadGroups', function() {
+    test('_getThreadGroups', () => {
       element.patchForNewThreads = 3;
-      var comments = [
+      const comments = [
         {
           id: 'sallys_confession',
           message: 'i like you, jack',
@@ -66,23 +66,23 @@
         },
       ];
 
-      var expectedThreadGroups = [
+      let expectedThreadGroups = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
           commentSide: 'left',
           comments: [{
-              id: 'sallys_confession',
-              message: 'i like you, jack',
-              updated: '2015-12-23 15:00:20.396000000',
-              __commentSide: 'left',
-            }, {
-              id: 'jacks_reply',
-              message: 'i like you, too',
-              updated: '2015-12-24 15:00:20.396000000',
-              __commentSide: 'left',
-            }],
+            id: 'sallys_confession',
+            message: 'i like you, jack',
+            updated: '2015-12-23 15:00:20.396000000',
+            __commentSide: 'left',
+          }, {
+            id: 'jacks_reply',
+            message: 'i like you, too',
+            updated: '2015-12-24 15:00:20.396000000',
+            __commentSide: 'left',
+          }],
           locationRange: 'line-left',
-          patchNum: 3
+          patchNum: 3,
         },
       ];
 
@@ -91,33 +91,33 @@
 
       // Patch num should get inherited from comment rather
       comments.push({
-          id: 'betsys_confession',
-          message: 'i like you, jack',
-          updated: '2015-12-24 15:00:10.396000000',
-          range: {
-            start_line: 1,
-            start_character: 1,
-            end_line: 1,
-            end_character: 2,
-          },
-          __commentSide: 'left',
-        });
+        id: 'betsys_confession',
+        message: 'i like you, jack',
+        updated: '2015-12-24 15:00:10.396000000',
+        range: {
+          start_line: 1,
+          start_character: 1,
+          end_line: 1,
+          end_character: 2,
+        },
+        __commentSide: 'left',
+      });
 
       expectedThreadGroups = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
           commentSide: 'left',
           comments: [{
-              id: 'sallys_confession',
-              message: 'i like you, jack',
-              updated: '2015-12-23 15:00:20.396000000',
-              __commentSide: 'left',
-            }, {
-              id: 'jacks_reply',
-              message: 'i like you, too',
-              updated: '2015-12-24 15:00:20.396000000',
-              __commentSide: 'left',
-            }],
+            id: 'sallys_confession',
+            message: 'i like you, jack',
+            updated: '2015-12-23 15:00:20.396000000',
+            __commentSide: 'left',
+          }, {
+            id: 'jacks_reply',
+            message: 'i like you, too',
+            updated: '2015-12-24 15:00:20.396000000',
+            __commentSide: 'left',
+          }],
           patchNum: 3,
           locationRange: 'line-left',
         },
@@ -145,8 +145,8 @@
           expectedThreadGroups);
     });
 
-    test('_sortByDate', function() {
-      var threadGroups = [
+    test('_sortByDate', () => {
+      let threadGroups = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
           comments: [],
@@ -159,12 +159,12 @@
         },
       ];
 
-      var expectedResult = [
+      let expectedResult = [
         {
           start_datetime: '2015-12-22 15:00:10.396000000',
           comments: [],
           locationRange: 'range-1-1-1-2',
-        },{
+        }, {
           start_datetime: '2015-12-23 15:00:20.396000000',
           comments: [],
           locationRange: 'line',
@@ -175,7 +175,7 @@
 
       // When a comment doesn't have a date, the one without the date should be
       // last.
-      var threadGroups = [
+      threadGroups = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
           comments: [],
@@ -187,7 +187,7 @@
         },
       ];
 
-      var expectedResult = [
+      expectedResult = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
           comments: [],
@@ -198,22 +198,25 @@
           locationRange: 'range-1-1-1-2',
         },
       ];
+
+      assert.deepEqual(element._sortByDate(threadGroups), expectedResult);
     });
 
-    test('_calculateLocationRange', function() {
-      var comment = {__commentSide: 'left'};
-      var range = {
+    test('_calculateLocationRange', () => {
+      const comment = {__commentSide: 'left'};
+      const range = {
         start_line: 1,
         start_character: 2,
         end_line: 3,
         end_character: 4,
       };
       assert.equal(
-        element._calculateLocationRange(range, comment), 'range-1-2-3-4-left');
+          element._calculateLocationRange(range, comment),
+          'range-1-2-3-4-left');
     });
 
-    test('thread groups are updated when comments change', function() {
-      var commentsChangedStub = sandbox.stub(element, '_commentsChanged');
+    test('thread groups are updated when comments change', () => {
+      const commentsChangedStub = sandbox.stub(element, '_commentsChanged');
       element.comments = [];
       element.comments.push({
         id: 'sallys_confession',
@@ -223,16 +226,16 @@
       assert(commentsChangedStub.called);
     });
 
-    test('addNewThread', function() {
-      var locationRange = 'range-1-2-3-4';
+    test('addNewThread', () => {
+      const locationRange = 'range-1-2-3-4';
       element._threads = [{locationRange: 'line'}];
       element.addNewThread(locationRange);
       assert(element._threads.length, 2);
     });
 
-    test('_getPatchNum', function() {
+    test('_getPatchNum', () => {
       element.patchForNewThreads = 3;
-      var comment = {
+      const comment = {
         id: 'sallys_confession',
         message: 'i like you, jack',
         updated: '2015-12-23 15:00:20.396000000',
@@ -242,11 +245,11 @@
       assert.equal(element._getPatchNum(comment), 4);
     });
 
-    test('removeThread', function() {
-      var locationRange = 'range-1-2-3-4';
+    test('removeThread', () => {
+      const locationRange = 'range-1-2-3-4';
       element._threads = [
         {locationRange: 'range-1-2-3-4', comments: []},
-        {locationRange: 'line', comments: []}
+        {locationRange: 'line', comments: []},
       ];
       flushAsynchronousOperations();
       element.removeThread(locationRange);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
index 0791193..ea6347f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
@@ -173,6 +173,9 @@
     },
 
     _eraseDraftComment: function() {
+      // Prevents a race condition in which removing the draft comment occurs
+      // prior to it being saved.
+      this.cancelDebouncer('store');
       this.$.storage.eraseDraftComment({
         changeNum: this.changeNum,
         patchNum: this._getPatchNum(),
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
index 919a64f..bcac6b3 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
@@ -476,6 +476,7 @@
 
     test('draft saving/editing', function(done) {
       var fireStub = sinon.stub(element, 'fire');
+      let cancelDebounce = sandbox.stub(element, 'cancelDebouncer');
 
       element.draft = true;
       MockInteractions.tap(element.$$('.edit'));
@@ -507,6 +508,7 @@
       element._xhrPromise.then(function(draft) {
         assert(fireStub.calledWith('comment-save'),
                'comment-save should be sent');
+        assert(cancelDebounce.calledWith('store'));
         assert.deepEqual(fireStub.lastCall.args[1], {
           comment: {
             __commentSide: 'right',
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
index e29f8ef..20833d0 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences.js
@@ -41,20 +41,19 @@
       '_localPrefsChanged(localPrefs.*)',
     ],
 
-    getFocusStops: function() {
+    getFocusStops() {
       return {
         start: this.$.contextSelect,
         end: this.$.cancelButton,
       };
     },
 
-    resetFocus: function() {
+    resetFocus() {
       this.$.contextSelect.focus();
     },
 
-    _prefsChanged: function(changeRecord) {
-      var prefs = changeRecord.base;
-      // TODO(andybons): This is not supported in IE. Implement a polyfill.
+    _prefsChanged(changeRecord) {
+      const prefs = changeRecord.base;
       // NOTE: Object.assign is NOT automatically a deep copy. If prefs adds
       // an object as a value, it must be marked enumerable.
       this._newPrefs = Object.assign({}, prefs);
@@ -65,71 +64,70 @@
       this.$.syntaxHighlightInput.checked = prefs.syntax_highlighting;
     },
 
-    _localPrefsChanged: function(changeRecord) {
-      var localPrefs = changeRecord.base || {};
-      // TODO(viktard): This is not supported in IE. Implement a polyfill.
+    _localPrefsChanged(changeRecord) {
+      const localPrefs = changeRecord.base || {};
       this._newLocalPrefs = Object.assign({}, localPrefs);
     },
 
-    _handleContextSelectChange: function(e) {
-      var selectEl = Polymer.dom(e).rootTarget;
+    _handleContextSelectChange(e) {
+      const selectEl = Polymer.dom(e).rootTarget;
       this.set('_newPrefs.context', parseInt(selectEl.value, 10));
     },
 
-    _handleShowTabsTap: function(e) {
+    _handleShowTabsTap(e) {
       this.set('_newPrefs.show_tabs', Polymer.dom(e).rootTarget.checked);
     },
 
-    _handleShowTrailingWhitespaceTap: function(e) {
+    _handleShowTrailingWhitespaceTap(e) {
       this.set('_newPrefs.show_whitespace_errors',
           Polymer.dom(e).rootTarget.checked);
     },
 
-    _handleSyntaxHighlightTap: function(e) {
+    _handleSyntaxHighlightTap(e) {
       this.set('_newPrefs.syntax_highlighting',
           Polymer.dom(e).rootTarget.checked);
     },
 
-    _handlelineWrappingTap: function(e) {
+    _handlelineWrappingTap(e) {
       this.set('_newPrefs.line_wrapping', Polymer.dom(e).rootTarget.checked);
     },
 
-    _handleSave: function(e) {
+    _handleSave(e) {
       e.stopPropagation();
       this.prefs = this._newPrefs;
       this.localPrefs = this._newLocalPrefs;
-      var el = Polymer.dom(e).rootTarget;
+      const el = Polymer.dom(e).rootTarget;
       el.disabled = true;
       this.$.storage.savePreferences(this._localPrefs);
-      this._saveDiffPreferences().then(function(response) {
+      this._saveDiffPreferences().then(response => {
         el.disabled = false;
         if (!response.ok) { return response; }
 
         this.$.prefsOverlay.close();
-      }.bind(this)).catch(function(err) {
+      }).catch(err => {
         el.disabled = false;
-      }.bind(this));
+      });
     },
 
-    _handleCancel: function(e) {
+    _handleCancel(e) {
       e.stopPropagation();
       this.$.prefsOverlay.close();
     },
 
-    _handlePrefsTap: function(e) {
+    _handlePrefsTap(e) {
       e.preventDefault();
       this._openPrefs();
     },
 
-    open: function() {
-      this.$.prefsOverlay.open().then(function() {
-        var focusStops = this.getFocusStops();
+    open() {
+      this.$.prefsOverlay.open().then(() => {
+        const focusStops = this.getFocusStops();
         this.$.prefsOverlay.setFocusStops(focusStops);
         this.resetFocus();
-      }.bind(this));
+      });
     },
 
-    _saveDiffPreferences: function() {
+    _saveDiffPreferences() {
       return this.$.restAPI.saveDiffPreferences(this.prefs);
     },
   });
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
index b163c71..d201edf 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences/gr-diff-preferences_test.html
@@ -33,20 +33,20 @@
 </test-fixture>
 
 <script>
-  suite('gr-diff-preferences tests', function() {
-    var element;
-    var sandbox;
+  suite('gr-diff-preferences tests', () => {
+    let element;
+    let sandbox;
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
       element = fixture('basic');
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
     });
 
-    test('model changes', function() {
+    test('model changes', () => {
       element.prefs = {
         context: 10,
         font_size: 12,
@@ -78,7 +78,7 @@
       assert.isFalse(element._newPrefs.syntax_highlighting);
     });
 
-    test('clicking fit to screen hides line length input', function() {
+    test('clicking fit to screen hides line length input', () => {
       element.prefs = {line_wrapping: false};
 
       assert.isFalse(element.$.columnsPref.hidden);
@@ -90,31 +90,31 @@
       assert.isFalse(element.$.columnsPref.hidden);
     });
 
-    test('clicking save button calls _handleSave function', function() {
-      var savePrefs = sinon.stub(element, '_handleSave');
+    test('clicking save button calls _handleSave function', () => {
+      const savePrefs = sinon.stub(element, '_handleSave');
       MockInteractions.tap(element.$.saveButton);
       flushAsynchronousOperations();
       assert(savePrefs.calledOnce);
       savePrefs.restore();
     });
 
-    test('save button', function() {
+    test('save button', () => {
       element.prefs = {
         font_size: '11',
       };
       element._newPrefs = {
         font_size: '12',
       };
-      var saveStub = sandbox.stub(element.$.restAPI, 'saveDiffPreferences',
-          function() { return Promise.resolve(); });
+      const saveStub = sandbox.stub(element.$.restAPI, 'saveDiffPreferences',
+          () => { return Promise.resolve(); });
 
       MockInteractions.tap(element.$$('gr-button[primary]'));
       assert.deepEqual(element.prefs, element._newPrefs);
       assert.deepEqual(saveStub.lastCall.args[0], element._newPrefs);
     });
 
-    test('cancel button', function() {
-      var closeStub = sandbox.stub(element.$.prefsOverlay, 'close');
+    test('cancel button', () => {
+      const closeStub = sandbox.stub(element.$.prefsOverlay, 'close');
       MockInteractions.tap(element.$$('gr-button:not([primary])'));
       assert.isTrue(closeStub.called);
     });
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
index 58d29bd..e9437bd 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.js
@@ -15,7 +15,7 @@
   'use strict';
 
   // Maximum length for patch set descriptions.
-  var PATCH_DESC_MAX_LENGTH = 500;
+  const PATCH_DESC_MAX_LENGTH = 500;
 
   Polymer({
     is: 'gr-patch-range-select',
@@ -36,15 +36,15 @@
 
     behaviors: [Gerrit.PatchSetBehavior],
 
-    _updateSelected: function() {
+    _updateSelected() {
       this._rightSelected = this.patchRange.patchNum;
       this._leftSelected = this.patchRange.basePatchNum;
     },
 
-    _handlePatchChange: function(e) {
-      var leftPatch = this._leftSelected;
-      var rightPatch = this._rightSelected;
-      var rangeStr = rightPatch;
+    _handlePatchChange(e) {
+      const leftPatch = this._leftSelected;
+      const rightPatch = this._rightSelected;
+      let rangeStr = rightPatch;
       if (leftPatch != 'PARENT') {
         rangeStr = leftPatch + '..' + rangeStr;
       }
@@ -52,11 +52,11 @@
       e.target.blur();
     },
 
-    _computeLeftDisabled: function(patchNum, patchRange) {
+    _computeLeftDisabled(patchNum, patchRange) {
       return parseInt(patchNum, 10) >= parseInt(patchRange.patchNum, 10);
     },
 
-    _computeRightDisabled: function(patchNum, patchRange) {
+    _computeRightDisabled(patchNum, patchRange) {
       if (patchRange.basePatchNum == 'PARENT') { return false; }
       return parseInt(patchNum, 10) <= parseInt(patchRange.basePatchNum, 10);
     },
@@ -66,16 +66,16 @@
     // are loaded, the correct value will get selected.  I attempted to
     // debounce these, but because they are detecting two different
     // events, sometimes the timing was off and one ended up missing.
-    _synchronizeSelectionRight: function() {
+    _synchronizeSelectionRight() {
       this.$.rightPatchSelect.value = this._rightSelected;
     },
 
-    _synchronizeSelectionLeft: function() {
+    _synchronizeSelectionLeft() {
       this.$.leftPatchSelect.value = this._leftSelected;
     },
 
-    _computePatchSetDescription: function(revisions, patchNum) {
-      var rev = this.getRevisionByPatchNum(revisions, patchNum);
+    _computePatchSetDescription(revisions, patchNum) {
+      const rev = this.getRevisionByPatchNum(revisions, patchNum);
       return (rev && rev.description) ?
           rev.description.substring(0, PATCH_DESC_MAX_LENGTH) : '';
     },
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
index 00d73bf..0195eac 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.html
@@ -34,24 +34,24 @@
 </test-fixture>
 
 <script>
-  suite('gr-patch-range-select tests', function() {
-    var element;
+  suite('gr-patch-range-select tests', () => {
+    let element;
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
     });
 
-    test('enabled/disabled options', function() {
-      var patchRange = {
+    test('enabled/disabled options', () => {
+      const patchRange = {
         basePatchNum: 'PARENT',
         patchNum: '3',
       };
-      ['1', '2', '3'].forEach(function(patchNum) {
+      for (const patchNum of ['1', '2', '3']) {
         assert.isFalse(element._computeRightDisabled(patchNum, patchRange));
-      });
-      ['PARENT', '1', '2'].forEach(function(patchNum) {
+      }
+      for (const patchNum of ['PARENT', '1', '2']) {
         assert.isFalse(element._computeLeftDisabled(patchNum, patchRange));
-      });
+      }
       assert.isTrue(element._computeLeftDisabled('3', patchRange));
 
       patchRange.basePatchNum = '2';
@@ -61,11 +61,11 @@
       assert.isFalse(element._computeRightDisabled('3', patchRange));
     });
 
-    test('navigation', function(done) {
-      var showStub = sinon.stub(page, 'show');
-      var leftSelectEl = element.$.leftPatchSelect;
-      var rightSelectEl = element.$.rightPatchSelect;
-      var blurSpy = sinon.spy(leftSelectEl, 'blur');
+    test('navigation', done => {
+      const showStub = sinon.stub(page, 'show');
+      const leftSelectEl = element.$.leftPatchSelect;
+      const rightSelectEl = element.$.rightPatchSelect;
+      const blurSpy = sinon.spy(leftSelectEl, 'blur');
       element.changeNum = '42';
       element.path = 'path/to/file.txt';
       element.availablePatches = ['1', '2', '3'];
@@ -75,8 +75,8 @@
       };
       flushAsynchronousOperations();
 
-      var numEvents = 0;
-      leftSelectEl.addEventListener('change', function(e) {
+      let numEvents = 0;
+      leftSelectEl.addEventListener('change', e => {
         numEvents++;
         if (numEvents == 1) {
           assert(showStub.lastCall.calledWithExactly(
@@ -98,23 +98,23 @@
       element.fire('change', {}, {node: leftSelectEl});
     });
 
-    test('filesWeblinks', function() {
+    test('filesWeblinks', () => {
       element.filesWeblinks = {
         meta_a: [
           {
             name: 'foo',
             url: 'f.oo',
-          }
+          },
         ],
         meta_b: [
           {
             name: 'bar',
             url: 'ba.r',
-          }
+          },
         ],
       };
       flushAsynchronousOperations();
-      var domApi = Polymer.dom(element.root);
+      const domApi = Polymer.dom(element.root);
       assert.equal(
           domApi.querySelector('a[href="f.oo"]').textContent, 'foo');
       assert.equal(
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
index 9bcde07..99c4fed 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.js
@@ -22,13 +22,13 @@
   }
 
   GrChangeActionsInterface.prototype.addPrimaryActionKey = function(key) {
-    if (this._el.primaryActionKeys.indexOf(key) !== -1) { return; }
+    if (this._el.primaryActionKeys.includes(key)) { return; }
 
     this._el.push('primaryActionKeys', key);
   };
 
   GrChangeActionsInterface.prototype.removePrimaryActionKey = function(key) {
-    this._el.primaryActionKeys = this._el.primaryActionKeys.filter(function(k) {
+    this._el.primaryActionKeys = this._el.primaryActionKeys.filter(k => {
       return k !== key;
     });
   };
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
index d964cde..24fee39 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.html
@@ -37,43 +37,44 @@
 </test-fixture>
 
 <script>
-  suite('gr-js-api-interface tests', function() {
-    var element;
-    var changeActions;
+  suite('gr-js-api-interface tests', () => {
+    let element;
+    let changeActions;
 
     // Because deepEqual doesn’t behave in Safari.
     function assertArraysEqual(actual, expected) {
       assert.equal(actual.length, expected.length);
-      for (var i = 0; i < actual.length; i++) {
+      for (let i = 0; i < actual.length; i++) {
         assert.equal(actual[i], expected[i]);
       }
     }
 
-    setup(function() {
+    setup(() => {
       element = fixture('basic');
       element.change = {};
       element._hasKnownChainState = false;
-      var plugin;
-      Gerrit.install(function(p) { plugin = p; }, '0.1',
+      let plugin;
+      Gerrit.install(p => { plugin = p; }, '0.1',
           'http://test.com/plugins/testplugin/static/test.js');
       changeActions = plugin.changeActions();
     });
 
-    teardown(function() {
+    teardown(() => {
       changeActions = null;
     });
 
-    test('property existence', function() {
-      [
+    test('property existence', () => {
+      const properties = [
         'ActionType',
         'ChangeActions',
         'RevisionActions',
-      ].forEach(function(p) {
+      ];
+      for (const p of properties) {
         assertArraysEqual(changeActions[p], element[p]);
-      });
+      }
     });
 
-    test('add/remove primary action keys', function() {
+    test('add/remove primary action keys', () => {
       element.primaryActionKeys = [];
       changeActions.addPrimaryActionKey('foo');
       assertArraysEqual(element.primaryActionKeys, ['foo']);
@@ -89,34 +90,34 @@
       assertArraysEqual(element.primaryActionKeys, []);
     });
 
-    test('action buttons', function(done) {
-      var key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-      var handler = sinon.spy();
+    test('action buttons', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      const handler = sinon.spy();
       changeActions.addTapListener(key, handler);
-      flush(function() {
+      flush(() => {
         MockInteractions.tap(element.$$('[data-action-key="' + key + '"]'));
         assert(handler.calledOnce);
         changeActions.removeTapListener(key, handler);
         MockInteractions.tap(element.$$('[data-action-key="' + key + '"]'));
         assert(handler.calledOnce);
         changeActions.remove(key);
-        flush(function() {
+        flush(() => {
           assert.isNull(element.$$('[data-action-key="' + key + '"]'));
           done();
         });
       });
     });
 
-    test('action button properties', function(done) {
-      var key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-      flush(function() {
-        var button = element.$$('[data-action-key="' + key + '"]');
+    test('action button properties', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      flush(() => {
+        const button = element.$$('[data-action-key="' + key + '"]');
         assert.isOk(button);
         assert.equal(button.getAttribute('data-label'), 'Bork!');
         assert.isNotOk(button.disabled);
         changeActions.setLabel(key, 'Yo');
         changeActions.setEnabled(key, false);
-        flush(function() {
+        flush(() => {
           assert.equal(button.getAttribute('data-label'), 'Yo');
           assert.isTrue(button.disabled);
           done();
@@ -124,30 +125,30 @@
       });
     });
 
-    test('hide action buttons', function(done) {
-      var key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-      flush(function() {
-        var button = element.$$('[data-action-key="' + key + '"]');
+    test('hide action buttons', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      flush(() => {
+        const button = element.$$('[data-action-key="' + key + '"]');
         assert.isOk(button);
         assert.isFalse(button.hasAttribute('hidden'));
         changeActions.setActionHidden(
             changeActions.ActionType.REVISION, key, true);
-        flush(function() {
-          var button = element.$$('[data-action-key="' + key + '"]');
+        flush(() => {
+          const button = element.$$('[data-action-key="' + key + '"]');
           assert.isNotOk(button);
           done();
         });
       });
     });
 
-    test('move action button to overflow', function(done) {
-      var key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-      flush(function() {
+    test('move action button to overflow', done => {
+      const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      flush(() => {
         assert.isTrue(element.$.moreActions.hidden);
         assert.isOk(element.$$('[data-action-key="' + key + '"]'));
         changeActions.setActionOverflow(
             changeActions.ActionType.REVISION, key, true);
-        flush(function() {
+        flush(() => {
           assert.isNotOk(element.$$('[data-action-key="' + key + '"]'));
           assert.isFalse(element.$.moreActions.hidden);
           assert.strictEqual(element.$.moreActions.items[0].name, 'Bork!');
@@ -156,17 +157,19 @@
       });
     });
 
-    test('change actions priority', function(done) {
-      var key1 = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
-      var key2 = changeActions.add(changeActions.ActionType.CHANGE, 'Squanch?');
-      flush(function() {
-        var buttons =
+    test('change actions priority', done => {
+      const key1 =
+          changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
+      const key2 =
+          changeActions.add(changeActions.ActionType.CHANGE, 'Squanch?');
+      flush(() => {
+        let buttons =
             Polymer.dom(element.root).querySelectorAll('[data-action-key]');
         assert.equal(buttons[0].getAttribute('data-action-key'), key1);
         assert.equal(buttons[1].getAttribute('data-action-key'), key2);
         changeActions.setActionPriority(
             changeActions.ActionType.REVISION, key1, 10);
-        flush(function() {
+        flush(() => {
           buttons =
               Polymer.dom(element.root).querySelectorAll('[data-action-key]');
           assert.equal(buttons[0].getAttribute('data-action-key'), key2);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
index c2357cc..73f3479 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api_test.html
@@ -37,35 +37,35 @@
 </test-fixture>
 
 <script>
-  suite('gr-change-reply-js-api tests', function() {
-    var element;
-    var sandbox;
-    var changeReply;
+  suite('gr-change-reply-js-api tests', () => {
+    let element;
+    let sandbox;
+    let changeReply;
 
-    setup(function() {
+    setup(() => {
       stub('gr-rest-api-interface', {
-        getConfig: function() { return Promise.resolve({}); },
-        getAccount: function() { return Promise.resolve(null); },
+        getConfig() { return Promise.resolve({}); },
+        getAccount() { return Promise.resolve(null); },
       });
       element = fixture('basic');
       sandbox = sinon.sandbox.create();
-      var plugin;
-      Gerrit.install(function(p) { plugin = p; }, '0.1',
+      let plugin;
+      Gerrit.install(p => { plugin = p; }, '0.1',
           'http://test.com/plugins/testplugin/static/test.js');
       changeReply = plugin.changeReply();
     });
 
-    teardown(function() {
+    teardown(() => {
       changeReply = null;
       sandbox.restore();
     });
 
-    test('calls', function() {
-      var setLabelValueStub = sinon.stub(element, 'setLabelValue');
+    test('calls', () => {
+      const setLabelValueStub = sinon.stub(element, 'setLabelValue');
       changeReply.setLabelValue('My-Label', '+1337');
       assert(setLabelValueStub.calledWithExactly('My-Label', '+1337'));
 
-      var sendStub = sinon.stub(element, 'send');
+      const sendStub = sinon.stub(element, 'send');
       changeReply.send(false);
       assert(sendStub.calledWithExactly(false));
     });
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
index 34ca728..70a9bf5 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface.js
@@ -14,7 +14,7 @@
 (function() {
   'use strict';
 
-  var EventType = {
+  const EventType = {
     HISTORY: 'history',
     LABEL_CHANGE: 'labelchange',
     SHOW_CHANGE: 'showchange',
@@ -25,7 +25,7 @@
     POST_REVERT: 'postrevert',
   };
 
-  var Element = {
+  const Element = {
     CHANGE_ACTIONS: 'changeactions',
     REPLY_DIALOG: 'replydialog',
   };
@@ -44,11 +44,11 @@
       },
     },
 
-    Element: Element,
-    EventType: EventType,
+    Element,
+    EventType,
 
-    handleEvent: function(type, detail) {
-      Gerrit.awaitPluginsLoaded().then(function() {
+    handleEvent(type, detail) {
+      Gerrit.awaitPluginsLoaded().then(() => {
         switch (type) {
           case EventType.HISTORY:
             this._handleHistory(detail);
@@ -67,27 +67,27 @@
                 type);
             break;
         }
-      }.bind(this));
+      });
     },
 
-    addElement: function(key, el) {
+    addElement(key, el) {
       this._elements[key] = el;
     },
 
-    getElement: function(key) {
+    getElement(key) {
       return this._elements[key];
     },
 
-    addEventCallback: function(eventName, callback) {
+    addEventCallback(eventName, callback) {
       if (!this._eventCallbacks[eventName]) {
         this._eventCallbacks[eventName] = [];
       }
       this._eventCallbacks[eventName].push(callback);
     },
 
-    canSubmitChange: function(change, revision) {
-      var submitCallbacks = this._getEventCallbacks(EventType.SUBMIT_CHANGE);
-      var cancelSubmit = submitCallbacks.some(function(callback) {
+    canSubmitChange(change, revision) {
+      const submitCallbacks = this._getEventCallbacks(EventType.SUBMIT_CHANGE);
+      const cancelSubmit = submitCallbacks.some(callback => {
         try {
           return callback(change, revision) === false;
         } catch (err) {
@@ -99,28 +99,29 @@
       return !cancelSubmit;
     },
 
-    _removeEventCallbacks: function() {
-      for (var k in EventType) {
+    _removeEventCallbacks() {
+      for (const k in EventType) {
+        if (!EventType.hasOwnProperty(k)) { continue; }
         this._eventCallbacks[EventType[k]] = [];
       }
     },
 
-    _handleHistory: function(detail) {
-      this._getEventCallbacks(EventType.HISTORY).forEach(function(cb) {
+    _handleHistory(detail) {
+      for (const cb of this._getEventCallbacks(EventType.HISTORY)) {
         try {
           cb(detail.path);
         } catch (err) {
           console.error(err);
         }
-      });
+      }
     },
 
-    _handleShowChange: function(detail) {
-      this._getEventCallbacks(EventType.SHOW_CHANGE).forEach(function(cb) {
-        var change = detail.change;
-        var patchNum = detail.patchNum;
-        var revision;
-        for (var rev in change.revisions) {
+    _handleShowChange(detail) {
+      for (const cb of this._getEventCallbacks(EventType.SHOW_CHANGE)) {
+        const change = detail.change;
+        const patchNum = detail.patchNum;
+        let revision;
+        for (const rev in change.revisions) {
           if (change.revisions[rev]._number == patchNum) {
             revision = change.revisions[rev];
             break;
@@ -131,67 +132,63 @@
         } catch (err) {
           console.error(err);
         }
-      });
+      }
     },
 
-    handleCommitMessage: function(change, msg) {
-      this._getEventCallbacks(EventType.COMMIT_MSG_EDIT).forEach(
-          function(cb) {
-            try {
-              cb(change, msg);
-            } catch (err) {
-              console.error(err);
-            }
-          }
-      );
+    handleCommitMessage(change, msg) {
+      for (const cb of this._getEventCallbacks(EventType.COMMIT_MSG_EDIT)) {
+        try {
+          cb(change, msg);
+        } catch (err) {
+          console.error(err);
+        }
+      }
     },
 
-    _handleComment: function(detail) {
-      this._getEventCallbacks(EventType.COMMENT).forEach(function(cb) {
+    _handleComment(detail) {
+      for (const cb of this._getEventCallbacks(EventType.COMMENT)) {
         try {
           cb(detail.node);
         } catch (err) {
           console.error(err);
         }
-      });
+      }
     },
 
-    _handleLabelChange: function(detail) {
-      this._getEventCallbacks(EventType.LABEL_CHANGE).forEach(function(cb) {
+    _handleLabelChange(detail) {
+      for (const cb of this._getEventCallbacks(EventType.LABEL_CHANGE)) {
         try {
           cb(detail.change);
         } catch (err) {
           console.error(err);
         }
-      });
+      }
     },
 
-    modifyRevertMsg: function(change, revertMsg, origMsg) {
-      this._getEventCallbacks(EventType.REVERT).forEach(function(callback) {
+    modifyRevertMsg(change, revertMsg, origMsg) {
+      for (const cb of this._getEventCallbacks(EventType.REVERT)) {
         try {
-          revertMsg = callback(change, revertMsg, origMsg);
+          revertMsg = cb(change, revertMsg, origMsg);
         } catch (err) {
           console.error(err);
         }
-      });
+      }
       return revertMsg;
     },
 
-    getLabelValuesPostRevert: function(change) {
-      var labels = {};
-      this._getEventCallbacks(EventType.POST_REVERT).forEach(
-          function(callback) {
-            try {
-              labels = callback(change);
-            } catch (err) {
-              console.error(err);
-            }
-          }
-      );
+    getLabelValuesPostRevert(change) {
+      let labels = {};
+      for (const cb of this._getEventCallbacks(EventType.POST_REVERT)) {
+        try {
+          labels = cb(change);
+        } catch (err) {
+          console.error(err);
+        }
+      }
       return labels;
     },
 
-    _getEventCallbacks: function(type) {
+    _getEventCallbacks(type) {
       return this._eventCallbacks[type] || [];
     },
   });
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
index d62bdd8..c3013bd 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.html
@@ -31,45 +31,45 @@
 </test-fixture>
 
 <script>
-  suite('gr-js-api-interface tests', function() {
-    var element;
-    var plugin;
-    var errorStub;
-    var sandbox;
+  suite('gr-js-api-interface tests', () => {
+    let element;
+    let plugin;
+    let errorStub;
+    let sandbox;
 
-    var throwErrFn = function() {
+    const throwErrFn = function() {
       throw Error('Unfortunately, this handler has stopped');
     };
 
-    setup(function() {
+    setup(() => {
       sandbox = sinon.sandbox.create();
       stub('gr-rest-api-interface', {
-        getAccount: function() {
+        getAccount() {
           return Promise.resolve({name: 'Judy Hopps'});
         },
       });
       element = fixture('basic');
       errorStub = sandbox.stub(console, 'error');
       Gerrit._setPluginsCount(1);
-      Gerrit.install(function(p) { plugin = p; }, '0.1',
+      Gerrit.install(p => { plugin = p; }, '0.1',
           'http://test.com/plugins/testplugin/static/test.js');
     });
 
-    teardown(function() {
+    teardown(() => {
       sandbox.restore();
       element._removeEventCallbacks();
       plugin = null;
     });
 
-    test('url', function() {
+    test('url', () => {
       assert.equal(plugin.url(), 'http://test.com/plugins/testplugin/');
       assert.equal(plugin.url('/static/test.js'),
           'http://test.com/plugins/testplugin/static/test.js');
     });
 
-    test('history event', function(done) {
+    test('history event', done => {
       plugin.on(element.EventType.HISTORY, throwErrFn);
-      plugin.on(element.EventType.HISTORY, function(path) {
+      plugin.on(element.EventType.HISTORY, path => {
         assert.equal(path, '/path/to/awesomesauce');
         assert.isTrue(errorStub.calledOnce);
         done();
@@ -78,13 +78,13 @@
           {path: '/path/to/awesomesauce'});
     });
 
-    test('showchange event', function(done) {
-      var testChange = {
+    test('showchange event', done => {
+      const testChange = {
         _number: 42,
         revisions: {def: {_number: 2}, abc: {_number: 1}},
       };
       plugin.on(element.EventType.SHOW_CHANGE, throwErrFn);
-      plugin.on(element.EventType.SHOW_CHANGE, function(change, revision) {
+      plugin.on(element.EventType.SHOW_CHANGE, (change, revision) => {
         assert.deepEqual(change, testChange);
         assert.deepEqual(revision, testChange.revisions.abc);
         assert.isTrue(errorStub.calledOnce);
@@ -94,28 +94,28 @@
           {change: testChange, patchNum: 1});
     });
 
-    test('handleEvent awaits plugins load', function(done) {
-      var testChange = {
+    test('handleEvent awaits plugins load', done => {
+      const testChange = {
         _number: 42,
         revisions: {def: {_number: 2}, abc: {_number: 1}},
       };
-      var spy = sandbox.spy();
+      const spy = sandbox.spy();
       Gerrit._setPluginsCount(1);
       plugin.on(element.EventType.SHOW_CHANGE, spy);
       element.handleEvent(element.EventType.SHOW_CHANGE,
           {change: testChange, patchNum: 1});
       assert.isFalse(spy.called);
       Gerrit._setPluginsCount(0);
-      flush(function() {
+      flush(() => {
         assert.isTrue(spy.called);
         done();
       });
     });
 
-    test('comment event', function(done) {
-      var testCommentNode = {foo: 'bar'};
+    test('comment event', done => {
+      const testCommentNode = {foo: 'bar'};
       plugin.on(element.EventType.COMMENT, throwErrFn);
-      plugin.on(element.EventType.COMMENT, function(commentNode) {
+      plugin.on(element.EventType.COMMENT, commentNode => {
         assert.deepEqual(commentNode, testCommentNode);
         assert.isTrue(errorStub.calledOnce);
         done();
@@ -123,7 +123,7 @@
       element.handleEvent(element.EventType.COMMENT, {node: testCommentNode});
     });
 
-    test('revert event', function() {
+    test('revert event', () => {
       function appendToRevertMsg(c, revertMsg, originalMsg) {
         return revertMsg + '\n' + originalMsg.replace(/^/gm, '> ') + '\ninfo';
       }
@@ -134,16 +134,16 @@
       plugin.on(element.EventType.REVERT, throwErrFn);
       plugin.on(element.EventType.REVERT, appendToRevertMsg);
       assert.equal(element.modifyRevertMsg(null, 'test', 'origTest'),
-                   'test\n> origTest\ninfo');
+          'test\n> origTest\ninfo');
       assert.isTrue(errorStub.calledOnce);
 
       plugin.on(element.EventType.REVERT, appendToRevertMsg);
       assert.equal(element.modifyRevertMsg(null, 'test', 'origTest'),
-                   'test\n> origTest\ninfo\n> origTest\ninfo');
+          'test\n> origTest\ninfo\n> origTest\ninfo');
       assert.isTrue(errorStub.calledTwice);
     });
 
-    test('postrevert event', function() {
+    test('postrevert event', () => {
       function getLabels(c) {
         return {'Code-Review': 1};
       }
@@ -158,10 +158,10 @@
       assert.isTrue(errorStub.calledOnce);
     });
 
-    test('commitmsgedit event', function(done) {
-      var testMsg = 'Test CL commit message';
+    test('commitmsgedit event', done => {
+      const testMsg = 'Test CL commit message';
       plugin.on(element.EventType.COMMIT_MSG_EDIT, throwErrFn);
-      plugin.on(element.EventType.COMMIT_MSG_EDIT, function(change, msg) {
+      plugin.on(element.EventType.COMMIT_MSG_EDIT, (change, msg) => {
         assert.deepEqual(msg, testMsg);
         assert.isTrue(errorStub.calledOnce);
         done();
@@ -169,10 +169,10 @@
       element.handleCommitMessage(null, testMsg);
     });
 
-    test('labelchange event', function(done) {
-      var testChange = {_number: 42};
+    test('labelchange event', done => {
+      const testChange = {_number: 42};
       plugin.on(element.EventType.LABEL_CHANGE, throwErrFn);
-      plugin.on(element.EventType.LABEL_CHANGE, function(change) {
+      plugin.on(element.EventType.LABEL_CHANGE, change => {
         assert.deepEqual(change, testChange);
         assert.isTrue(errorStub.calledOnce);
         done();
@@ -180,41 +180,41 @@
       element.handleEvent(element.EventType.LABEL_CHANGE, {change: testChange});
     });
 
-    test('submitchange', function() {
+    test('submitchange', () => {
       plugin.on(element.EventType.SUBMIT_CHANGE, throwErrFn);
-      plugin.on(element.EventType.SUBMIT_CHANGE, function() { return true; });
+      plugin.on(element.EventType.SUBMIT_CHANGE, () => { return true; });
       assert.isTrue(element.canSubmitChange());
       assert.isTrue(errorStub.calledOnce);
-      plugin.on(element.EventType.SUBMIT_CHANGE, function() { return false; });
-      plugin.on(element.EventType.SUBMIT_CHANGE, function() { return true; });
+      plugin.on(element.EventType.SUBMIT_CHANGE, () => { return false; });
+      plugin.on(element.EventType.SUBMIT_CHANGE, () => { return true; });
       assert.isFalse(element.canSubmitChange());
       assert.isTrue(errorStub.calledTwice);
     });
 
-    test('versioning', function() {
-      var callback = sandbox.spy();
+    test('versioning', () => {
+      const callback = sandbox.spy();
       Gerrit.install(callback, '0.0pre-alpha');
       assert(callback.notCalled);
     });
 
-    test('getAccount', function(done) {
-      Gerrit.getLoggedIn().then(function(loggedIn) {
+    test('getAccount', done => {
+      Gerrit.getLoggedIn().then(loggedIn => {
         assert.isTrue(loggedIn);
         done();
       });
     });
 
-    test('_setPluginsCount', function(done) {
+    test('_setPluginsCount', done => {
       stub('gr-reporting', {
-        pluginsLoaded: function() {
+        pluginsLoaded() {
           assert.equal(Gerrit._pluginsPending, 0);
           done();
-        }
+        },
       });
       Gerrit._setPluginsCount(0);
     });
 
-    test('_arePluginsLoaded', function() {
+    test('_arePluginsLoaded', () => {
       assert.isTrue(Gerrit._arePluginsLoaded());
       Gerrit._setPluginsCount(1);
       assert.isFalse(Gerrit._arePluginsLoaded());
@@ -222,12 +222,12 @@
       assert.isTrue(Gerrit._arePluginsLoaded());
     });
 
-    test('_pluginInstalled', function(done) {
+    test('_pluginInstalled', done => {
       stub('gr-reporting', {
-        pluginsLoaded: function() {
+        pluginsLoaded() {
           assert.equal(Gerrit._pluginsPending, 0);
           done();
-        }
+        },
       });
       Gerrit._setPluginsCount(2);
       Gerrit._pluginInstalled();
@@ -235,34 +235,34 @@
       Gerrit._pluginInstalled();
     });
 
-    test('install calls _pluginInstalled', function() {
+    test('install calls _pluginInstalled', () => {
       sandbox.stub(Gerrit, '_pluginInstalled');
-      Gerrit.install(function(p) { plugin = p; }, '0.1',
+      Gerrit.install(p => { plugin = p; }, '0.1',
           'http://test.com/plugins/testplugin/static/test.js');
       assert.isTrue(Gerrit._pluginInstalled.calledOnce);
     });
 
-    test('install calls _pluginInstalled on error', function() {
+    test('install calls _pluginInstalled on error', () => {
       sandbox.stub(Gerrit, '_pluginInstalled');
-      Gerrit.install(function() {}, '0.0pre-alpha');
+      Gerrit.install(() => {}, '0.0pre-alpha');
       assert.isTrue(Gerrit._pluginInstalled.calledOnce);
     });
 
-    test('installGwt calls _pluginInstalled', function() {
+    test('installGwt calls _pluginInstalled', () => {
       sandbox.stub(Gerrit, '_pluginInstalled');
       Gerrit.installGwt();
       assert.isTrue(Gerrit._pluginInstalled.calledOnce);
     });
 
-    test('installGwt returns a stub object', function() {
-      var plugin = Gerrit.installGwt();
+    test('installGwt returns a stub object', () => {
+      const plugin = Gerrit.installGwt();
       sandbox.stub(console, 'warn');
       assert.isAbove(Object.keys(plugin).length, 0);
-      Object.keys(plugin).forEach(function(name) {
+      for (const name of Object.keys(plugin)) {
         console.warn.reset();
         plugin[name]();
         assert.isTrue(console.warn.calledOnce);
-      });
+      }
     });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
index 402b371..a84eedd 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.js
@@ -14,17 +14,17 @@
 (function(window) {
   'use strict';
 
-  var warnNotSupported = function(opt_name) {
+  const warnNotSupported = function(opt_name) {
     console.warn('Plugin API method ' + (opt_name || '') + ' is not supported');
   };
 
-  var stubbedMethods = ['_loadedGwt', 'screen', 'settingsScreen', 'panel'];
-  var GWT_PLUGIN_STUB = {};
-  stubbedMethods.forEach(function(name) {
+  const stubbedMethods = ['_loadedGwt', 'screen', 'settingsScreen', 'panel'];
+  const GWT_PLUGIN_STUB = {};
+  for (const name of stubbedMethods) {
     GWT_PLUGIN_STUB[name] = warnNotSupported.bind(null, name);
-  });
+  }
 
-  var API_VERSION = '0.1';
+  const API_VERSION = '0.1';
 
   // GWT JSNI uses $wnd to refer to window.
   // http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJSNI.html
@@ -38,7 +38,7 @@
     }
 
     this._url = new URL(opt_url);
-    if (this._url.pathname.indexOf('/plugins') !== 0) {
+    if (!this._url.pathname.startsWith('/plugins')) {
       console.warn('Plugin not being loaded from /plugins base path:',
           this._url.href, '— Unable to determine name.');
       return;
@@ -54,14 +54,14 @@
     return this._name;
   };
 
-  Plugin.prototype.registerStyleModule =
-      function(stylingEndpointName, moduleName) {
+  Plugin.prototype.registerStyleModule = function(stylingEndpointName,
+      moduleName) {
     if (!Gerrit._styleModules[stylingEndpointName]) {
       Gerrit._styleModules[stylingEndpointName] = [];
     }
     Gerrit._styleModules[stylingEndpointName].push({
       pluginUrl: this._url,
-      moduleName: moduleName,
+      moduleName,
     });
   };
 
@@ -87,7 +87,7 @@
         Plugin._sharedAPIElement.Element.REPLY_DIALOG));
   };
 
-  var Gerrit = window.Gerrit || {};
+  const Gerrit = window.Gerrit || {};
 
   // Number of plugins to initialize, -1 means 'not yet known'.
   Gerrit._pluginsPending = -1;
@@ -102,12 +102,13 @@
 
   Gerrit.css = function(rulesStr) {
     if (!Gerrit._customStyleSheet) {
-      var styleEl = document.createElement('style');
+      const styleEl = document.createElement('style');
       document.head.appendChild(styleEl);
       Gerrit._customStyleSheet = styleEl.sheet;
     }
 
-    var name = '__pg_js_api_class_' + Gerrit._customStyleSheet.cssRules.length;
+    const name = '__pg_js_api_class_' +
+        Gerrit._customStyleSheet.cssRules.length;
     Gerrit._customStyleSheet.insertRule('.' + name + '{' + rulesStr + '}', 0);
     return name;
   };
@@ -121,9 +122,9 @@
     }
 
     // TODO(andybons): Polyfill currentScript for IE10/11 (edge supports it).
-    var src = opt_src || (document.currentScript &&
+    const src = opt_src || (document.currentScript &&
          document.currentScript.src || document.currentScript.baseURI);
-    var plugin = new Plugin(src);
+    const plugin = new Plugin(src);
     try {
       callback(plugin);
     } catch (e) {
@@ -155,7 +156,7 @@
       if (Gerrit._arePluginsLoaded()) {
         Gerrit._allPluginsPromise = Promise.resolve();
       } else {
-        Gerrit._allPluginsPromise = new Promise(function(resolve) {
+        Gerrit._allPluginsPromise = new Promise(resolve => {
           Gerrit._resolveAllPluginsLoaded = resolve;
         });
       }